ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 2.6
Committed: Fri Aug 21 13:49:35 1992 UTC (31 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.5: +1 -1 lines
Log Message:
made getscan() slightly more efficient

File Contents

# User Rev Content
1 greg 1.1 /* Copyright (c) 1987 Regents of the University of California */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * ximage.c - driver for X-windows
9     *
10     * 4/30/87
11     * 3/3/88 Added calls to xraster & Paul Heckbert's ciq routines
12     */
13    
14     #include "standard.h"
15    
16     #include <X/Xlib.h>
17     #include <X/cursors/bcross.cursor>
18     #include <X/cursors/bcross_mask.cursor>
19    
20     #include <sys/types.h>
21    
22     #include <ctype.h>
23    
24     #include "color.h"
25    
26 greg 2.1 #include "resolu.h"
27    
28 greg 1.1 #include "xraster.h"
29    
30     #include "view.h"
31    
32     #include "pic.h"
33    
34 greg 1.15 #include "random.h"
35    
36 greg 1.1 #define controlshift(e) (((XButtonEvent *)(e))->detail & (ShiftMask|ControlMask))
37    
38     #define FONTNAME "9x15" /* text font we'll use */
39    
40 greg 2.3 #define CTRL(c) ((c)-'@')
41 greg 1.1
42     #define BORWIDTH 5 /* border width */
43     #define BARHEIGHT 25 /* menu bar size */
44    
45 greg 1.11 double gamcor = 2.2; /* gamma correction */
46 greg 1.1
47 greg 1.2 XRASTER *ourras = NULL; /* our stored raster image */
48 greg 1.1
49     int dither = 1; /* dither colors? */
50     int fast = 0; /* keep picture in Pixmap? */
51    
52     Window wind = 0; /* our output window */
53     Font fontid; /* our font */
54    
55     int maxcolors = 0; /* maximum colors */
56     int greyscale = 0; /* in grey */
57    
58 greg 1.2 int scale = 0; /* scalefactor; power of two */
59    
60 greg 1.1 int xoff = 0; /* x image offset */
61     int yoff = 0; /* y image offset */
62    
63 greg 1.21 VIEW ourview = STDVIEW; /* image view parameters */
64 greg 1.1 int gotview = 0; /* got parameters from file */
65    
66     COLR *scanline; /* scan line buffer */
67    
68     int xmax, ymax; /* picture resolution */
69     int width, height; /* window size */
70     char *fname = NULL; /* input file name */
71     FILE *fin = stdin; /* input file */
72     long *scanpos = NULL; /* scan line positions in file */
73     int cury = 0; /* current scan location */
74    
75     double exposure = 1.0; /* exposure compensation used */
76    
77 greg 1.29 int wrongformat = 0; /* input in another format */
78    
79 greg 1.1 struct {
80     int xmin, ymin, xsiz, ysiz;
81     } box = {0, 0, 0, 0}; /* current box */
82    
83     char *geometry = NULL; /* geometry specification */
84    
85     char *progname;
86    
87     char errmsg[128];
88    
89     extern long ftell();
90    
91     extern char *malloc(), *calloc();
92    
93 greg 2.2 extern double pow(), log();
94 greg 1.1
95    
96     main(argc, argv)
97     int argc;
98     char *argv[];
99     {
100 greg 2.5 extern char *getenv();
101     char *gv;
102 greg 1.1 int headline();
103     int i;
104    
105     progname = argv[0];
106 greg 2.5 if ((gv = getenv("GAMMA")) != NULL)
107     gamcor = atof(gv);
108 greg 1.1
109     for (i = 1; i < argc; i++)
110     if (argv[i][0] == '-')
111     switch (argv[i][1]) {
112     case 'c':
113     maxcolors = atoi(argv[++i]);
114     break;
115     case 'b':
116     greyscale = !greyscale;
117     break;
118     case 'm':
119     maxcolors = 2;
120     break;
121     case 'd':
122     dither = !dither;
123     break;
124     case 'f':
125     fast = !fast;
126     break;
127 greg 1.2 case 'e':
128     if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
129     goto userr;
130     scale = atoi(argv[++i]);
131     break;
132 greg 1.1 case 'g':
133     gamcor = atof(argv[++i]);
134     break;
135     default:
136     goto userr;
137     }
138     else if (argv[i][0] == '=')
139     geometry = argv[i];
140     else
141     break;
142    
143     if (argc-i == 1) {
144     fname = argv[i];
145     fin = fopen(fname, "r");
146     if (fin == NULL) {
147     sprintf(errmsg, "can't open file \"%s\"", fname);
148     quiterr(errmsg);
149     }
150 greg 1.6 }
151 greg 1.1 /* get header */
152 greg 1.29 getheader(fin, headline, NULL);
153 greg 1.1 /* get picture dimensions */
154 greg 1.29 if (wrongformat || fgetresolu(&xmax, &ymax, fin) != (YMAJOR|YDECR))
155 greg 1.1 quiterr("bad picture size");
156     /* set view parameters */
157 greg 1.21 if (gotview && setview(&ourview) != NULL)
158     gotview = 0;
159 greg 1.1 if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
160     quiterr("out of memory");
161    
162     init(); /* get file and open window */
163    
164     for ( ; ; )
165     getevent(); /* main loop */
166     userr:
167     fprintf(stderr,
168 greg 1.2 "Usage: %s [=geometry][-b][-m][-d][-f][-c ncolors][-e +/-stops] file\n",
169 greg 1.1 progname);
170     quit(1);
171     }
172    
173    
174     headline(s) /* get relevant info from header */
175     char *s;
176     {
177 greg 1.29 char fmt[32];
178 greg 1.1
179 greg 1.20 if (isexpos(s))
180     exposure *= exposval(s);
181 greg 1.29 else if (isformat(s)) {
182     formatval(fmt, s);
183     wrongformat = strcmp(fmt, COLRFMT);
184 greg 2.4 } else if (isview(s) && sscanview(&ourview, s) > 0)
185     gotview++;
186 greg 1.1 }
187    
188    
189     init() /* get data and open window */
190     {
191     register int i;
192     OpaqueFrame mainframe;
193     char defgeom[32];
194    
195     if (fname != NULL) {
196     scanpos = (long *)malloc(ymax*sizeof(long));
197     if (scanpos == NULL)
198     goto memerr;
199     for (i = 0; i < ymax; i++)
200     scanpos[i] = -1;
201     }
202     if (XOpenDisplay(NULL) == NULL)
203     quiterr("can't open display; DISPLAY variable set?");
204     #ifdef notdef
205     if (DisplayWidth() - 2*BORWIDTH < xmax ||
206     DisplayHeight() - 2*BORWIDTH - BARHEIGHT < ymax)
207     quiterr("resolution mismatch");
208     #endif
209     if (maxcolors == 0) { /* get number of available colors */
210     maxcolors = 1<<DisplayPlanes();
211     if (maxcolors > 4) maxcolors -= 2;
212     }
213     /* store image */
214 greg 1.2 getras();
215    
216 greg 1.1 mainframe.bdrwidth = BORWIDTH;
217     mainframe.border = WhitePixmap;
218     mainframe.background = BlackPixmap;
219     sprintf(defgeom, "=%dx%d+0+22", xmax, ymax);
220     wind = XCreate("Radiance Image", progname, geometry, defgeom,
221     &mainframe, 16, 16);
222     if (wind == 0)
223     quiterr("can't create window");
224     width = mainframe.width;
225     height = mainframe.height;
226     fontid = XGetFont(FONTNAME);
227     if (fontid == 0)
228     quiterr("can't get font");
229     XStoreName(wind, fname == NULL ? progname : fname);
230     XDefineCursor(wind, XCreateCursor(bcross_width, bcross_height,
231     bcross_bits, bcross_mask_bits,
232     bcross_x_hot, bcross_y_hot,
233     BlackPixel, WhitePixel, GXcopy));
234     XSelectInput(wind, ButtonPressed|ButtonReleased|UnmapWindow
235     |RightDownMotion|MiddleDownMotion|LeftDownMotion
236     |KeyPressed|ExposeWindow|ExposeRegion);
237     XMapWindow(wind);
238     return;
239     memerr:
240     quiterr("out of memory");
241     }
242    
243    
244     quiterr(err) /* print message and exit */
245     char *err;
246     {
247     if (err != NULL)
248     fprintf(stderr, "%s: %s\n", progname, err);
249    
250     exit(err == NULL ? 0 : 1);
251     }
252    
253    
254     eputs(s)
255     char *s;
256     {
257     fputs(s, stderr);
258     }
259    
260    
261     quit(code)
262     int code;
263     {
264     exit(code);
265     }
266    
267    
268 greg 1.2 getras() /* get raster file */
269     {
270     colormap ourmap;
271    
272     ourras = (XRASTER *)calloc(1, sizeof(XRASTER));
273     if (ourras == NULL)
274     goto memerr;
275     ourras->width = xmax;
276     ourras->height = ymax;
277     if (maxcolors <= 2) { /* monochrome */
278     ourras->data.m = (unsigned short *)malloc(BitmapSize(xmax,ymax));
279     if (ourras->data.m == NULL)
280     goto memerr;
281     getmono();
282     } else {
283     ourras->data.bz = (unsigned char *)malloc(BZPixmapSize(xmax,ymax));
284     if (ourras->data.bz == NULL)
285     goto memerr;
286     if (greyscale)
287     biq(dither,maxcolors,1,ourmap);
288     else
289     ciq(dither,maxcolors,1,ourmap);
290     if (init_rcolors(ourras, ourmap) == 0)
291     goto memerr;
292     }
293     return;
294     memerr:
295 greg 1.26 quiterr("out of memory");
296 greg 1.2 }
297    
298    
299 greg 1.1 getevent() /* process the next event */
300     {
301     WindowInfo info;
302     XEvent e;
303    
304     XNextEvent(&e);
305     switch (e.type) {
306     case KeyPressed:
307     docom(&e);
308     break;
309     case ExposeWindow:
310     XQueryWindow(wind, &info); /* in case resized */
311     width = info.width;
312     height = info.height;
313     /* fall through */
314     case ExposeRegion:
315     fixwindow(&e);
316     break;
317     case UnmapWindow:
318 greg 1.2 unmap_rcolors(ourras);
319 greg 1.1 break;
320     case ButtonPressed:
321     if (controlshift(&e))
322     moveimage(&e);
323     else
324     getbox(&e);
325     break;
326     }
327     }
328    
329    
330     fixwindow(eexp) /* fix new or stepped-on window */
331     XExposeEvent *eexp;
332     {
333     redraw(eexp->x, eexp->y, eexp->width, eexp->height);
334     }
335    
336    
337     redraw(x, y, w, h) /* redraw section of window */
338     int x, y;
339     int w, h;
340     {
341 greg 1.7 if (ourras->ncolors && map_rcolors(ourras) == NULL) {
342 greg 1.2 fprintf(stderr, "%s: cannot allocate colors\n", progname);
343     return(-1);
344     }
345 greg 1.1 if (fast)
346 greg 1.2 make_rpixmap(ourras);
347     return(patch_raster(wind,x-xoff,y-yoff,x,y,w,h,ourras) ? 0 : -1);
348 greg 1.1 }
349    
350    
351     docom(ekey) /* execute command */
352     XKeyEvent *ekey;
353     {
354     char buf[80];
355     COLOR cval;
356 greg 1.15 Color cvx;
357 greg 1.1 char *cp;
358     int n;
359 greg 1.2 double comp;
360 greg 1.1 FVECT rorg, rdir;
361    
362     cp = XLookupMapping(ekey, &n);
363     if (n == 0)
364     return(0);
365     switch (*cp) { /* interpret command */
366     case 'q':
367 greg 2.3 case CTRL('D'): /* quit */
368 greg 1.1 quit(0);
369     case '\n':
370     case '\r':
371     case 'l':
372     case 'c': /* value */
373     if (avgbox(cval) == -1)
374     return(-1);
375     switch (*cp) {
376     case '\n':
377     case '\r': /* radiance */
378 greg 1.17 sprintf(buf, "%.3f", intens(cval)/exposure);
379 greg 1.1 break;
380     case 'l': /* luminance */
381 greg 1.30 sprintf(buf, "%.0fL", luminance(cval)/exposure);
382 greg 1.1 break;
383     case 'c': /* color */
384 greg 1.2 comp = pow(2.0, (double)scale);
385 greg 1.1 sprintf(buf, "(%.2f,%.2f,%.2f)",
386 greg 1.2 colval(cval,RED)*comp,
387     colval(cval,GRN)*comp,
388     colval(cval,BLU)*comp);
389 greg 1.1 break;
390     }
391     XText(wind, box.xmin, box.ymin, buf, strlen(buf),
392     fontid, BlackPixel, WhitePixel);
393     return(0);
394 greg 1.15 case 'i': /* identify (contour) */
395 greg 1.16 if (ourras->pixels == NULL)
396 greg 1.15 return(-1);
397     n = ourras->data.bz[ekey->x-xoff+BZPixmapSize(xmax,ekey->y-yoff)];
398     n = ourras->pmap[n];
399     cvx.pixel = ourras->cdefs[n].pixel;
400     cvx.red = random() & 65535;
401     cvx.green = random() & 65535;
402     cvx.blue = random() & 65535;
403     XStoreColor(&cvx);
404     return(0);
405 greg 1.1 case 'p': /* position */
406     sprintf(buf, "(%d,%d)", ekey->x-xoff, ymax-1-ekey->y+yoff);
407     XText(wind, ekey->x, ekey->y, buf, strlen(buf),
408     fontid, BlackPixel, WhitePixel);
409     return(0);
410     case 't': /* trace */
411     if (!gotview) {
412     XFeep(0);
413     return(-1);
414     }
415 greg 1.25 if (viewray(rorg, rdir, &ourview, (ekey->x-xoff+.5)/xmax,
416     (ymax-1-ekey->y+yoff+.5)/ymax) < 0)
417     return(-1);
418 greg 1.1 printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
419     printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]);
420     fflush(stdout);
421     return(0);
422 greg 1.2 case '=': /* adjust exposure */
423     if (avgbox(cval) == -1)
424     return(-1);
425     n = log(.5/bright(cval))/.69315 - scale; /* truncate */
426 greg 1.5 if (n == 0)
427 greg 1.2 return(0);
428     scale_rcolors(ourras, pow(2.0, (double)n));
429     scale += n;
430     sprintf(buf, "%+d", scale);
431     XText(wind, box.xmin, box.ymin, buf, strlen(buf),
432     fontid, BlackPixel, WhitePixel);
433     XFlush();
434     free_raster(ourras);
435     getras();
436 greg 1.3 /* fall through */
437 greg 2.3 case CTRL('R'): /* redraw */
438     case CTRL('L'):
439 greg 1.16 unmap_rcolors(ourras);
440 greg 1.1 XClear(wind);
441     return(redraw(0, 0, width, height));
442     case ' ': /* clear */
443     return(redraw(box.xmin, box.ymin, box.xsiz, box.ysiz));
444     default:
445     XFeep(0);
446     return(-1);
447     }
448     }
449    
450    
451     moveimage(ep) /* shift the image */
452     XButtonEvent *ep;
453     {
454     XButtonEvent eb;
455    
456     XMaskEvent(ButtonReleased, &eb);
457     xoff += eb.x - ep->x;
458     yoff += eb.y - ep->y;
459     XClear(wind);
460     return(redraw(0, 0, width, height));
461     }
462    
463    
464     getbox(ebut) /* get new box */
465     XButtonEvent *ebut;
466     {
467     union {
468     XEvent e;
469     XButtonEvent b;
470     XMouseMovedEvent m;
471     } e;
472    
473     XMaskEvent(ButtonReleased|MouseMoved, &e.e);
474     while (e.e.type == MouseMoved) {
475     revbox(ebut->x, ebut->y, box.xmin = e.m.x, box.ymin = e.m.y);
476     XMaskEvent(ButtonReleased|MouseMoved, &e.e);
477     revbox(ebut->x, ebut->y, box.xmin, box.ymin);
478     }
479     box.xmin = e.b.x<0 ? 0 : (e.b.x>=width ? width-1 : e.b.x);
480     box.ymin = e.b.y<0 ? 0 : (e.b.y>=height ? height-1 : e.b.y);
481     if (box.xmin > ebut->x) {
482     box.xsiz = box.xmin - ebut->x + 1;
483     box.xmin = ebut->x;
484     } else {
485     box.xsiz = ebut->x - box.xmin + 1;
486     }
487     if (box.ymin > ebut->y) {
488     box.ysiz = box.ymin - ebut->y + 1;
489     box.ymin = ebut->y;
490     } else {
491     box.ysiz = ebut->y - box.ymin + 1;
492     }
493     }
494    
495    
496     revbox(x0, y0, x1, y1) /* draw box with reversed lines */
497     int x0, y0, x1, y1;
498     {
499     XLine(wind, x0, y0, x1, y0, 1, 1, 0, GXinvert, AllPlanes);
500     XLine(wind, x0, y1, x1, y1, 1, 1, 0, GXinvert, AllPlanes);
501     XLine(wind, x0, y0, x0, y1, 1, 1, 0, GXinvert, AllPlanes);
502     XLine(wind, x1, y0, x1, y1, 1, 1, 0, GXinvert, AllPlanes);
503     }
504    
505    
506     avgbox(clr) /* average color over current box */
507     COLOR clr;
508     {
509     int left, right, top, bottom;
510     int y;
511     double d;
512     COLOR ctmp;
513     register int x;
514    
515     setcolor(clr, 0.0, 0.0, 0.0);
516     left = box.xmin - xoff;
517     right = left + box.xsiz;
518     if (left < 0)
519     left = 0;
520     if (right > xmax)
521     right = xmax;
522     if (left >= right)
523     return(-1);
524     top = box.ymin - yoff;
525     bottom = top + box.ysiz;
526     if (top < 0)
527     top = 0;
528     if (bottom > ymax)
529     bottom = ymax;
530     if (top >= bottom)
531     return(-1);
532     for (y = top; y < bottom; y++) {
533     if (getscan(y) == -1)
534     return(-1);
535     for (x = left; x < right; x++) {
536     colr_color(ctmp, scanline[x]);
537     addcolor(clr, ctmp);
538     }
539     }
540     d = 1.0/((right-left)*(bottom-top));
541     scalecolor(clr, d);
542     return(0);
543     }
544    
545    
546     getmono() /* get monochrome data */
547     {
548     register unsigned short *dp;
549     register int x, err;
550 greg 1.31 int y, errp;
551 greg 1.24 rgbpixel *inl;
552 greg 1.1 short *cerr;
553    
554 greg 1.24 if ((inl = (rgbpixel *)malloc(xmax*sizeof(rgbpixel))) == NULL
555 greg 1.1 || (cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
556 greg 1.26 quiterr("out of memory in getmono");
557 greg 1.2 dp = ourras->data.m - 1;
558 greg 1.1 for (y = 0; y < ymax; y++) {
559 greg 1.24 picreadline3(y, inl);
560 greg 1.1 err = 0;
561     for (x = 0; x < xmax; x++) {
562     if (!(x&0xf))
563     *++dp = 0;
564 greg 1.31 errp = err;
565 greg 1.24 err += rgb_bright(&inl[x]) + cerr[x];
566 greg 1.1 if (err > 127)
567     err -= 255;
568     else
569     *dp |= 1<<(x&0xf);
570 greg 1.31 err /= 3;
571     cerr[x] = err + errp;
572 greg 1.1 }
573     }
574 greg 1.24 free((char *)inl);
575 greg 1.1 free((char *)cerr);
576     }
577    
578    
579 greg 1.2 init_rcolors(xr, cmap) /* (re)assign color values */
580 greg 1.1 register XRASTER *xr;
581     colormap cmap;
582     {
583     register int i;
584     register unsigned char *p;
585    
586     xr->pmap = (int *)malloc(256*sizeof(int));
587     if (xr->pmap == NULL)
588     return(0);
589     xr->cdefs = (Color *)malloc(256*sizeof(Color));
590     if (xr->cdefs == NULL)
591     return(0);
592     for (i = 0; i < 256; i++)
593     xr->pmap[i] = -1;
594     xr->ncolors = 0;
595     for (p = xr->data.bz, i = BZPixmapSize(xr->width,xr->height); i--; p++)
596     if (xr->pmap[*p] == -1) {
597     xr->cdefs[xr->ncolors].red = cmap[0][*p] << 8;
598     xr->cdefs[xr->ncolors].green = cmap[1][*p] << 8;
599     xr->cdefs[xr->ncolors].blue = cmap[2][*p] << 8;
600     xr->cdefs[xr->ncolors].pixel = *p;
601     xr->pmap[*p] = xr->ncolors++;
602     }
603     xr->cdefs = (Color *)realloc((char *)xr->cdefs, xr->ncolors*sizeof(Color));
604     if (xr->cdefs == NULL)
605     return(0);
606     return(1);
607     }
608    
609    
610 greg 1.2 scale_rcolors(xr, sf) /* scale color map */
611     register XRASTER *xr;
612     double sf;
613     {
614     register int i;
615 greg 1.16 long maxv;
616 greg 1.2
617 greg 1.16 if (xr->pixels == NULL)
618     return;
619    
620 greg 1.2 sf = pow(sf, 1.0/gamcor);
621 greg 1.16 maxv = 65535/sf;
622 greg 1.2
623     for (i = xr->ncolors; i--; ) {
624 greg 1.16 xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
625     65535 :
626 greg 1.2 xr->cdefs[i].red * sf;
627 greg 1.16 xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
628     65535 :
629 greg 1.2 xr->cdefs[i].green * sf;
630 greg 1.16 xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
631     65535 :
632 greg 1.2 xr->cdefs[i].blue * sf;
633     }
634 greg 1.16 XStoreColors(xr->ncolors, xr->cdefs);
635 greg 1.2 }
636    
637    
638 greg 1.1 getscan(y)
639     int y;
640     {
641     if (y != cury) {
642     if (scanpos == NULL || scanpos[y] == -1)
643     return(-1);
644     if (fseek(fin, scanpos[y], 0) == -1)
645 greg 1.26 quiterr("fseek error");
646 greg 1.1 cury = y;
647 greg 2.6 } else if (scanpos != NULL && scanpos[y] == -1)
648 greg 1.1 scanpos[y] = ftell(fin);
649    
650     if (freadcolrs(scanline, xmax, fin) < 0)
651     quiterr("read error");
652    
653     cury++;
654     return(0);
655     }
656    
657    
658     picreadline3(y, l3) /* read in 3-byte scanline */
659     int y;
660     register rgbpixel *l3;
661     {
662 greg 1.12 register int i;
663     /* read scanline */
664 greg 1.1 if (getscan(y) < 0)
665     quiterr("cannot seek for picreadline");
666     /* convert scanline */
667 greg 1.23 normcolrs(scanline, xmax, scale);
668 greg 1.12 for (i = 0; i < xmax; i++) {
669     l3[i].r = scanline[i][RED];
670     l3[i].g = scanline[i][GRN];
671     l3[i].b = scanline[i][BLU];
672 greg 1.1 }
673     }
674    
675    
676     picwriteline(y, l) /* add 8-bit scanline to image */
677     int y;
678     pixel *l;
679     {
680 greg 1.22 bcopy((char *)l, (char *)ourras->data.bz+BZPixmapSize(xmax,y), BZPixmapSize(xmax,1));
681 greg 1.1 }
682    
683    
684 greg 1.8 picreadcm(map) /* do gamma correction */
685 greg 1.1 colormap map;
686     {
687     extern double pow();
688     register int i, val;
689    
690     for (i = 0; i < 256; i++) {
691 greg 1.27 val = pow((i+0.5)/256.0, 1.0/gamcor) * 256.0;
692 greg 1.1 map[0][i] = map[1][i] = map[2][i] = val;
693     }
694     }
695    
696    
697     picwritecm(map) /* handled elsewhere */
698     colormap map;
699     {
700 greg 1.2 #ifdef DEBUG
701     register int i;
702    
703     for (i = 0; i < 256; i++)
704     printf("%d %d %d\n", map[0][i],map[1][i],map[2][i]);
705     #endif
706 greg 1.1 }