Received: by ATHENA-PO-2.MIT.EDU (5.45/4.7) id AA10340; Tue, 15 Aug 89 18:51:11 EDT
Received: by ATHENA.MIT.EDU (5.45/4.7) id AA05854; Tue, 15 Aug 89 18:50:35 EDT
Received: from uunet.uu.net by expo.lcs.mit.edu; Tue, 15 Aug 89 18:49:07 EDT
Received: from parallax.UUCP by uunet.uu.net (5.61/1.14) with UUCP 
	id AA06957; Tue, 15 Aug 89 18:48:41 -0400
Received: by parallax; Tue, 15 Aug 89 15:45:55 pdt
Date: Tue, 15 Aug 89 15:45:55 pdt
From: Murali V. Srinivasan <parallax!vsm@uunet.uu.net>
Message-Id: <8908152245.AA14241@parallax.parallax.com>
To: xvideo@expo.lcs.mit.edu
Subject: Video widget Source.

This is a shar file consisting of video widget and a test client program
based video widget and command buttons.

The output of shar will be four files:

VVideo.h,
VVideoP.h,
VVideo.c and 
xvideo.c  	- test client.

Have fun,

Murali V. Srinivasan,
Parallax Graphics Inc.

#---------------------------------- cut here ----------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Murali V. Srinivasan <vsm@parallax> on Tue Aug 15 15:40:30 1989
#
# This archive contains:
#	VVideo.c	VVideo.h	VVideoP.h	xvideo.c	
#
# Error checking via wc(1) will be performed.
# Error checking via sum(1) will be performed.

LANG=""; export LANG

if sum -r </dev/null >/dev/null 2>&1
then
	sumopt='-r'
else
	sumopt=''
fi

echo x - VVideo.c
cat >VVideo.c <<'@EOF'
/*
 *   Copyright (c) 1988 by
 *   PARALLAX GRAPHICS, INCORPORATED, Santa Clara, California.
 *   All rights reserved
 *
 *   This software is furnished on an as-is basis, and may be used and copied
 *   only with the inclusion of the above copyright notice.
 *
 *   The information in this software is subject to change without notice.
 *   No committment is made as to the usability or reliability of this
 *   software.
 *
 *   Parallax Graphics, Inc.
 *   2500 Condensa Street
 *   Santa Clara, California  95051
 */

#ifndef lint
static char *sid_vvideo_c = "@(#)VVideo.c	1.2 8/7/88 Parallax Graphics Inc";
#endif

/*
 * VVideo.c program, taken from Logo.c
 */

/*
Copyright 1988 by the Massachusetts Institute of Technology

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of M.I.T. not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is"
without express or implied warranty.
*/

#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
/*
#include <X11/VVideoP.h>
*/
#include "VVideoP.h"

static void AnotherFrame();
static void SwapLiveStill();

static char defaultTranslations[] =
    "<Btn1Down>:	anotherframe() \n\
     <Btn2Down>:	swaplivestill()";

static XtActionsRec actionsList[] = {
	{ "anotherframe",	AnotherFrame, },
	{ "swaplivestill",	SwapLiveStill, },
};


static XtResource resources[] = {
	{
		XtNwidth, XtCWidth, XtRInt, sizeof(int),
		XtOffset(Widget,core.width), XtRString, "640",
	},
	{
		XtNheight, XtCHeight, XtRInt, sizeof(int),
		XtOffset(Widget,core.height), XtRString, "482",
	},
	{
		XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
		XtOffset(VideoWidget,video.fgpixel), XtRString, "Black",
	},
	{
		XtNhigh, XtCForeground, XtRPixel, sizeof(Pixel),
		XtOffset(VideoWidget,video.highpixel), XtRString, "White",
	},
	{
		XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
		XtOffset(VideoWidget,video.reverse_video), XtRString, "FALSE",
	},
	{
		XtNlive, XtCBoolean, XtRBoolean, sizeof (Boolean),
		XtOffset(VideoWidget,video.live), XtRString, "FALSE"
	},
	{
		XtNscale, XtCBoolean, XtRBoolean, sizeof (Boolean),
		XtOffset(VideoWidget,video.scale), XtRString, "FALSE",
	},
	{
		XtNupdate, XtCBoolean, XtRBoolean, sizeof (Boolean),
		XtOffset(VideoWidget,video.update), XtRString, "FALSE",
	},
};

static void Initialize(), Realize(), Destroy(), Redisplay();
static Boolean SetValues();

VideoClassRec videoClassRec = {
    { /* core fields */
    /* superclass		*/	&widgetClassRec,
    /* class_name		*/	"Video",
    /* widget_size		*/	sizeof(VideoRec),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	Realize,
    /* actions                  */	actionsList,
    /* num_actions		*/	XtNumber(actionsList),
    /* resources		*/	resources,
    /* resource_count		*/	XtNumber(resources),
    /* xrm_class		*/	NULL,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	TRUE,
    /* destroy			*/	Destroy,
    /* resize			*/	NULL,
    /* expose			*/	Redisplay,
    /* set_values		*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	defaultTranslations,
    /* query_geometry		*/	NULL,
    }
};

WidgetClass videoWidgetClass = (WidgetClass) &videoClassRec;

/* ARGSUSED */
static void Initialize (request, new)
Widget request, new;
{
	VideoWidget w = (VideoWidget)new;
	register Display *dpy = XtDisplay(w);
	XGCValues  gcv;

	XSynchronize(dpy, 1);		/* for debug only */

	if (w->video.reverse_video) {
		Pixel fg = w->video.fgpixel;
		Pixel bg = w->core.background_pixel;

		if (w->core.border_pixel == fg)
			w->core.border_pixel = bg;
		w->video.fgpixel = bg;
		w->core.background_pixel = fg;
	}


	/*
	w->video.colormap = XCreateColormap(dpy,
				RootWindow(dpy, DefaultScreen(dpy)),
				DefaultVisual(dpy, DefaultScreen(dpy)),
				AllocNone);
	XSetWindowColormap(dpy, win, w->video.colormap);
	*/

	gcv.foreground = w->video.fgpixel;
	w->video.foreGC = XtGetGC((Widget)w, GCForeground, &gcv);
	gcv.foreground = w->core.background_pixel;
	w->video.backGC = XtGetGC((Widget)w, GCForeground, &gcv);

	gcv.foreground = w->video.highpixel;
	w->video.highGC = XtGetGC((Widget)w, GCForeground, &gcv);

	w->video.input.x = 0;
	w->video.input.y = 0;
	w->video.input.width = 640;
	w->video.input.height = 482;
}

static void Realize (gw, valueMask, attrs)
Widget gw;
XtValueMask *valueMask;
XSetWindowAttributes *attrs;
{
	XtCreateWindow( gw, InputOutput, (Visual *)CopyFromParent,
	*valueMask, attrs);
}

static void Destroy (gw)
Widget gw;
{
	VideoWidget w = (VideoWidget) gw;
	XtDestroyGC (w->video.foreGC);
	XtDestroyGC (w->video.backGC);
	XtDestroyGC (w->video.highGC);
}

/* ARGSUSED */
static void Redisplay (gw, event, region)
	Widget gw;
	XEvent *event;		/* unused */
	Region region;		/* unused */
{
	VideoWidget w = (VideoWidget) gw;
	register Display *dpy = XtDisplay(w);
	register Window win = XtWindow(w);

	w->video.update = FALSE;

	/* XClearWindow(dpy, win);*/

	if (w->video.live) {
		if (w->video.scale) {
			w->video.scale = FALSE;
			/* scale video expends past other types */
			XClearWindow(dpy, win);
		}
		
		XVideoLive(dpy, win, w->video.highGC,
			w->video.input.x, w->video.input.y,
			0, 0, w->core.width, w->core.height);
	} else {
		if (w->video.scale) {
			XVideoStop(dpy, win, w->video.highGC);
			XVideoScale(dpy, win, w->video.highGC,
				w->video.input.x, w->video.input.y,
				w->video.input.width, w->video.input.height,
				0, 0, w->core.width, w->core.height);
		} else {
			XVideoStop(dpy, win, w->video.highGC);
			XVideoStill(dpy, win, w->video.highGC,
				w->video.input.x, w->video.input.y,
				0, 0, w->core.width, w->core.height);
		}
	}
}

/* ARGSUSED */
static Boolean SetValues(gcurrent, grequest, gnew)
Widget gcurrent, grequest, gnew;
{
	VideoWidget current = (VideoWidget) gcurrent;
	VideoWidget new = (VideoWidget) gnew;
	Boolean redisplay = FALSE;
	XGCValues	gcv;

	if ((new->video.fgpixel != current->video.fgpixel) ||
	    (new->video.highpixel != current->video.highpixel) ||
	    (new->core.background_pixel != current->core.background_pixel)) {
		XtDestroyGC(current->video.foreGC);
		XtDestroyGC(current->video.backGC);
		XtDestroyGC(current->video.highGC);
		gcv.foreground = new->video.fgpixel;
		new->video.foreGC = XtGetGC(gcurrent, GCForeground, &gcv);
		gcv.foreground = new->core.background_pixel;
		new->video.backGC = XtGetGC(gcurrent, GCForeground, &gcv);
		gcv.foreground = new->video.highpixel;
		new->video.highGC = XtGetGC(gcurrent, GCForeground, &gcv);
		redisplay = TRUE;
	}
	if (new->video.update) {
		redisplay = TRUE;
	}
	if (new->video.scale != current->video.scale) {
		if (current->video.live) {
			XVideoStop(XtDisplay(current), XtWindow(current), current->video.highGC);
		}
		redisplay = TRUE;
	}
	if (new->video.live != current->video.live) {
		if (current->video.live) {
			XVideoStop(XtDisplay(current), XtWindow(current), current->video.highGC);
		}
		redisplay = TRUE;
	}

	return (redisplay);
}

/*
 *  Action Procedures
 */

/* ARGSUSED */
static void AnotherFrame(gw,event,params,num_params)
Widget gw;
XEvent *event;
String *params;		/* unused */
Cardinal *num_params;	/* unused */
{
	VideoWidget w = (VideoWidget) gw;

	Redisplay(w, event, NULL);
}

/* ARGSUSED */
static void SwapLiveStill(gw,event,params,num_params)
Widget gw;
XEvent *event;
String *params;		/* unused */
Cardinal *num_params;	/* unused */
{
	VideoWidget w = (VideoWidget) gw;

	if (w->video.live) {
		XVideoStop(XtDisplay(w), XtWindow(w), w->video.highGC);
	}
	w->video.live = !w->video.live;
	Redisplay(w, event, NULL);
}
@EOF
set `sum $sumopt <VVideo.c`; if test $1 -ne 1083
then
	echo ERROR: VVideo.c checksum is $1 should be 1083
fi
set `wc -lwc <VVideo.c`
if test $1$2$3 != 3119228318
then
	echo ERROR: wc results of VVideo.c are $* should be 311 922 8318
fi

chmod 664 VVideo.c

echo x - VVideo.h
cat >VVideo.h <<'@EOF'
/*
 *   Copyright (c) 1988 by
 *   PARALLAX GRAPHICS, INCORPORATED, Santa Clara, California.
 *   All rights reserved
 *
 *   This software is furnished on an as-is basis, and may be used and copied
 *   only with the inclusion of the above copyright notice.
 *
 *   The information in this software is subject to change without notice.
 *   No committment is made as to the usability or reliability of this
 *   software.
 *
 *   Parallax Graphics, Inc.
 *   2500 Condensa Street
 *   Santa Clara, California  95051
 */

#ifndef _XtVVIdeo_h
#define _XtVVIdeo_h

#ifndef lint
static char *sid_vvideo_h = "@(#)VVideo.h	1.1 7/28/88 Parallax Graphics Inc";
#endif

/*
 * VVideo.h program, taken from Logo.h
 */

/*
Copyright 1988 by the Massachusetts Institute of Technology

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of M.I.T. not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is"
without express or implied warranty.
*/

/* Parameters:

 Name		     Class		RepType		Default Value
 ----		     -----		-------		-------------
 live		     Boolean		Boolean		False
 scale		     Boolean		Boolean		False
 update		     Boolean		Boolean		False

 background	     Background		pixel		White
 border		     BorderColor	pixel		Black
 borderWidth	     BorderWidth	int		1
 destroyCallback     Callback		Pointer		NULL
 foreground	     Foreground		Pixel		Black
 height		     Height		int		100
 mappedWhenManaged   MappedWhenManaged	Boolean		True
 reverseVideo	     ReverseVideo	Boolean		False
 width		     Width		int		100
 x		     Position		int		0
 y		     Position		int		0

*/


/* Resource names used to the video widget */

#define XtNhigh			"highlight"
		/* color of higlighted data */
#define XtNlive			"live"
		/* Boolean: still picture if FALSE */
#define XtNscale		"scale"
		/* Boolean: 1:1 ratio if FALSE */
#define XtNupdate		"update"
		/* Boolean: forces a redisplay of video image */

typedef struct _VideoRec *VideoWidget;
typedef struct _VideoClassRec *VideoWidgetClass;

extern WidgetClass videoWidgetClass;

#endif _XtVVideo_h
@EOF
set `sum $sumopt <VVideo.h`; if test $1 -ne 12693
then
	echo ERROR: VVideo.h checksum is $1 should be 12693
fi
set `wc -lwc <VVideo.h`
if test $1$2$3 != 843442475
then
	echo ERROR: wc results of VVideo.h are $* should be 84 344 2475
fi

chmod 444 VVideo.h

echo x - VVideoP.h
cat >VVideoP.h <<'@EOF'
/*
 *   Copyright (c) 1988 by
 *   PARALLAX GRAPHICS, INCORPORATED, Santa Clara, California.
 *   All rights reserved
 *
 *   This software is furnished on an as-is basis, and may be used and copied
 *   only with the inclusion of the above copyright notice.
 *
 *   The information in this software is subject to change without notice.
 *   No committment is made as to the usability or reliability of this
 *   software.
 *
 *   Parallax Graphics, Inc.
 *   2500 Condensa Street
 *   Santa Clara, California  95051
 */

#ifndef _XtVVideoP_h
#define _XtVVideoP_h

#ifndef lint
static char *sid_vvideop_h = "@(#)VVideoP.h	1.1 7/28/88 Parallax Graphics Inc";
#endif

/*
 * VVideoP.h program, taken from LogoP.h
 */

/*
Copyright 1988 by the Massachusetts Institute of Technology

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of M.I.T. not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is"
without express or implied warranty.
*/

#include <X11/CoreP.h>
/*
#include <X11/VVideo.h>
*/
#include "VVideo.h"

typedef struct {
	Pixel	fgpixel, highpixel;
	Boolean reverse_video;
	GC	foreGC;
	GC	backGC;
	GC	highGC;
	Boolean	live;
	Boolean scale;
	XRectangle	input;
	Colormap	colormap;
	Boolean	update;
} VideoPart;

typedef struct _VideoRec {
   CorePart core;
   VideoPart video;
   } VideoRec;

typedef struct {int dummy;} VideoClassPart;

typedef struct _VideoClassRec {
   CoreClassPart core_class;
   VideoClassPart video_class;
   } VideoClassRec;

extern VideoClassRec videoClassRec;

#endif _XtVVideoP_h
@EOF
set `sum $sumopt <VVideoP.h`; if test $1 -ne 8386
then
	echo ERROR: VVideoP.h checksum is $1 should be 8386
fi
set `wc -lwc <VVideoP.h`
if test $1$2$3 != 782771958
then
	echo ERROR: wc results of VVideoP.h are $* should be 78 277 1958
fi

chmod 444 VVideoP.h

echo x - xvideo.c
cat >xvideo.c <<'@EOF'
/*
 *   Copyright (c) 1988 by
 *   PARALLAX GRAPHICS, INCORPORATED, Santa Clara, California.
 *   All rights reserved
 *
 *   This software is furnished on an as-is basis, and may be used and copied
 *   only with the inclusion of the above copyright notice.
 *
 *   The information in this software is subject to change without notice.
 *   No committment is made as to the usability or reliability of this
 *   software.
 *
 *   Parallax Graphics, Inc.
 *   2500 Condensa Street
 *   Santa Clara, California  95051
 */

#ifndef lint
static char *sid_xvideo_c = "@(#)xvideo.c	1.3 8/7/88 Parallax Graphics Inc";
#endif

/*
 * xvideo.c program, taken from xlogo.
 */

/*
Copyright 1988 by the Massachusetts Institute of Technology

Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of M.I.T. not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is"
without express or implied warranty.
*/

#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Atoms.h>
#include <X11/Shell.h>
#include <X11/Label.h>
#include <X11/Box.h>
#include <X11/Form.h>
#include <X11/Command.h>
#include <X11/Cardinals.h>

/*
#include <X11/VVideo.h>
*/
#include "VVideo.h"

extern void exit();

static XrmOptionDescRec options[] = {
	{"-live",	"*video.live",	XrmoptionNoArg,	"TRUE", },
	{"-still",	"*video.live",	XrmoptionNoArg,	"FALSE", },
	{"-scale",	"*video.scale",	XrmoptionNoArg,	"FALSE", },
};

/*
 * Report the syntax for calling xvideo.
 */
Syntax(call)
char *call;
{
	(void)printf("Usage: %s [-live] [-scale]\n", call);
	(void)printf("	[-fg <color>] [-bg <color>] [-rv]\n");
	(void)printf("	[-bw <pixels>] [-bd <color>]\n");
	(void)printf("	[-d [<host>]:[<vs>]]\n");
	(void)printf("	[-g =[<width>][x<height>][<+-><xoff>[<+-><yoff>]]]\n\n");
	exit(1);
}

static Widget toplevel, form, box, video, info;
static Widget command1, command2, command3, command4;
static XtCallbackRec callback[2];
static Arg args[5];
static unsigned int n;

static void PressedScaleButton(w, closure, call_data)
Widget w;
caddr_t closure, call_data;
{
	n = 0;
	XtSetArg(args[n], XtNlabel, "Video Picture Scaled"); n++;
	XtSetValues(info, args, n);
	n = 0;
	XtSetArg(args[n], XtNlive, FALSE); n++;
	XtSetArg(args[n], XtNscale, TRUE); n++;
	XtSetArg(args[n], XtNupdate, TRUE); n++;
	XtSetValues(video, args, n);
}

static void PressedStillButton(w, closure, call_data)
Widget w;
caddr_t closure, call_data;
{
	n = 0;
	XtSetArg(args[n], XtNlabel, "Video Picture Still"); n++;
	XtSetValues(info, args, n);
	n = 0;
	XtSetArg(args[n], XtNlive, FALSE); n++;
	XtSetArg(args[n], XtNscale, FALSE); n++;
	XtSetArg(args[n], XtNupdate, TRUE); n++;
	XtSetValues(video, args, n);
}

static void PressedLiveButton(w, closure, call_data)
Widget w;
caddr_t closure, call_data;
{
	n = 0;
	XtSetArg(args[n], XtNlabel, "Video Picture Live"); n++;
	XtSetValues(info, args, n);
	n = 0;
	XtSetArg(args[n], XtNlive, TRUE); n++;
	XtSetArg(args[n], XtNscale, FALSE); n++;
	XtSetArg(args[n], XtNupdate, TRUE); n++;
	XtSetValues(video, args, n);
}

static void PressedQuitButton(w, closure, call_data)
Widget w;
caddr_t closure, call_data;
{
	exit(0);
}

void main(argc, argv)
int argc;
char **argv;
{
	toplevel = XtInitialize("main", "XVideo", options, XtNumber(options), &argc, argv);
	if (argc != 1)
		Syntax(argv[0]);

	n = 0;
	XtSetArg(args[n], XtNdefaultDistance, 16); n++;
	form = XtCreateManagedWidget("the form", formWidgetClass, toplevel, args, n);

	callback[0].callback = PressedLiveButton;
	n = 0;
	XtSetArg(args[n], XtNcallback, callback); n++;
	XtSetArg(args[n], XtNleft, XtChainLeft); n++;
	command1 = XtCreateManagedWidget("live", commandWidgetClass, form, args, n);

	callback[0].callback = PressedScaleButton;
	n = 0;
	XtSetArg(args[n], XtNcallback, callback); n++;
	XtSetArg(args[n], XtNfromHoriz, command1); n++;
	XtSetArg(args[n], XtNleft, XtChainLeft); n++;
	command2 = XtCreateManagedWidget("scaled", commandWidgetClass, form, args, n);

	callback[0].callback = PressedStillButton;
	n = 0;
	XtSetArg(args[n], XtNcallback, callback); n++;
	XtSetArg(args[n], XtNfromHoriz, command2); n++;
	XtSetArg(args[n], XtNleft, XtChainLeft); n++;
	command3 = XtCreateManagedWidget("still", commandWidgetClass, form, args, n);

	callback[0].callback = PressedQuitButton;
	n = 0;
	XtSetArg(args[n], XtNcallback, callback); n++;
	XtSetArg(args[n], XtNfromVert, command1); n++;
	XtSetArg(args[n], XtNleft, XtChainTop); n++;
	command4 = XtCreateManagedWidget("quit", commandWidgetClass, form, args, n);

	n = 0;
	XtSetArg(args[n], XtNsensitive, 1); n++;
	XtSetArg(args[n], XtNfromHoriz, command3); n++;
	XtSetArg(args[n], XtNleft, XtChainLeft); n++;
	XtSetArg(args[n], XtNresizable, TRUE); n++;
        info = XtCreateManagedWidget("                                ", labelWidgetClass, form, args, n);

	n = 0;
	XtSetArg(args[n], XtNfromVert, command4); n++;
	XtSetArg(args[n], XtNresizable, TRUE); n++;
	XtSetArg(args[n], XtNborderWidth, 0); n++;
	video = XtCreateManagedWidget("xvideo", videoWidgetClass, form, args, n);

	/*
	 * all set up, let her fly.
	 */
	XtRealizeWidget(toplevel);
	XtMainLoop();
}
@EOF
set `sum $sumopt <xvideo.c`; if test $1 -ne 53789
then
	echo ERROR: xvideo.c checksum is $1 should be 53789
fi
set `wc -lwc <xvideo.c`
if test $1$2$3 != 1926515523
then
	echo ERROR: wc results of xvideo.c are $* should be 192 651 5523
fi

chmod 444 xvideo.c

exit 0
