home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / bin / foo2oak-wrapper < prev    next >
Encoding:
Text File  |  2007-03-27  |  13.7 KB  |  597 lines

  1. #!/bin/sh
  2.  
  3. #* Copyright (C) 2003-2006  Rick Richardson
  4. #*
  5. #* This program is free software; you can redistribute it and/or modify
  6. #* it under the terms of the GNU General Public License as published by
  7. #* the Free Software Foundation; either version 2 of the License, or
  8. #* (at your option) any later version.
  9. #*
  10. #* This program is distributed in the hope that it will be useful,
  11. #* but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #* GNU General Public License for more details.
  14. #*
  15. #* You should have received a copy of the GNU General Public License
  16. #* along with this program; if not, write to the Free Software
  17. #* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. #*
  19. #* Authors: Rick Richardson <rick.richardson@comcast.net>
  20.  
  21. VERSION='$Id: foo2oak-wrapper.in,v 1.24 2006/12/17 16:00:06 rick Exp $'
  22.  
  23. PROGNAME="$0"
  24. BASENAME=`basename $PROGNAME`
  25. PREFIX=/usr
  26. SHARE=$PREFIX/share/foo2oak
  27.  
  28. #
  29. #    Log the command line, for debugging and problem reports
  30. #
  31. if [ -x /usr/bin/logger ]; then
  32.     logger -t "$BASENAME" -p lpr.info -- "foo2oak-wrapper $@" </dev/null
  33. fi
  34.  
  35. usage() {
  36.     cat <<EOF
  37. Usage:
  38.     $BASENAME [options] [ps-file]
  39.  
  40.     Foomatic printer wrapper for the foo2oak printer driver.
  41.     This script reads a Postscript ps-file or standard input
  42.     and converts it to Oak Technoligies OAKT printer format.
  43.  
  44. Normal Options:
  45. -b bits           Bits per plane (1 or 2) [$BPP]
  46. -c                Print in color (else monochrome)
  47. -m media          Media code to send to printer [$MEDIA]
  48.                     0=auto 1=plain 2=preprinted 3=letterhead 4=graytrans
  49.                     5=prepunched 6=labels 7=bond 8=recycled 9=color
  50.                     10=cardstock 11=heavy 12=envelope 13=light 14=tough
  51. -p paper          Paper code [$PAPER]
  52.                     1=letter, 5=legal, 7=executive, 9=A4, 11=A5, 13=B5jis
  53. -n copies         Number of copies [$COPIES]
  54. -r <xres>x<yres>  Set device resolution in pixels/inch [$RES]
  55. -s source         Source code to send to printer [$SOURCE]
  56.                     1=tray1, 4=manual, 7=auto
  57.             Code numbers may vary with printer model.
  58. -2/-3/-4/-6/-8/-10/-12/-14/-15/-16/-18
  59.                   Print with N-up (requires psutils)
  60. -o orient         For N-up: -op is portrait, -ol is landscape, -os is seascape.
  61.  
  62. Printer Tweaking Options:
  63. -u <xoff>x<yoff>  Set offset of upper left printable in pixels [varies]
  64. -l <xoff>x<yoff>  Set offset of lower right printable in pixels [varies]
  65. -L mask           Send logical clipping values from -u/-l in ZjStream [3]
  66.                   0=no, 1=Y, 2=X, 3=XY
  67.  
  68. Color Tweaking Options:
  69. -g gsopts         Additional options to pass to Ghostscript, such as
  70.                   -dDITHERPPI=nnn, etc.  May appear more than once. []
  71. -G profile.icm    Convert profile.icm to a Postscript CRD using icc2ps and
  72.                   adjust colors using the setcolorrendering PS operator.
  73.                   $SHARE/icm/ will be searched for profile.icm.
  74. -I intent         Select profile intent from ICM file [$INTENT]
  75.                   0=Perceptual, 1=Colorimetric, 2=Saturation, 3=Absolute
  76. -G gamma-file.ps  Prepend gamma-file to the Postscript input to perform
  77.                   color correction using the setcolortransfer PS operator.
  78.  
  79. Debugging Options:
  80. -S plane          Output just a single color plane from a color print [all]
  81.                   1=Cyan, 2=Magenta, 3=Yellow, 4=Black
  82. -D lvl            Set Debug level [$DEBUG]
  83. -V                $VERSION
  84. EOF
  85.  
  86.     exit 1
  87. }
  88.  
  89. #
  90. #       Report an error and exit
  91. #
  92. error() {
  93.     echo "$BASENAME: $1" >&2
  94.     exit 1
  95. }
  96.  
  97. dbgcmd() {
  98.     if [ $DEBUG -ge 1 ]; then
  99.         echo "$@" >&2
  100.     fi
  101.     "$@"
  102. }
  103.  
  104. #
  105. #    N-up-ify the job.  Requires psnup from psutils package
  106. #
  107. nup() {
  108.     case "$NUP" in
  109.     [2368]|1[0458])
  110.     tr '\r' '\n' | psnup $NUP_ORIENT -d2 -$NUP -m.3in -p$paper -q
  111.     ;;
  112.     [49]|1[26])
  113.     tr '\r' '\n' | psnup $NUP_ORIENT -d2 -$NUP -m.5in -p$paper -q
  114.     ;;
  115.     *)
  116.     error "Illegal call to nup()."
  117.     ;;
  118.     esac
  119. }
  120.  
  121. #
  122. #       Process the options
  123. #
  124. BPP=1
  125. GSBIN=gs
  126. CMDLINE="$*"
  127. DEBUG=0
  128. DUPLEX=1
  129. COLOR=
  130. QUALITY=1
  131. MEDIA=1
  132. COPIES=1
  133. test -r /etc/papersize && PAPER=$(cat /etc/papersize)
  134. test "$PAPER" || PAPER=1
  135. RES=600x600
  136. SOURCE=7
  137. NUP=
  138. CLIP_UL=
  139. CLIP_LR=
  140. CLIP_LOG=
  141. BC=
  142. AIB=
  143. COLOR2MONO=
  144. GAMMAFILE=
  145. INTENT=0
  146. GSOPTS=
  147. GSDEV=-sDEVICE=pbmraw
  148. NUP_ORIENT=
  149. while getopts "1:23456789o:b:cd:g:l:u:L:m:n:p:q:r:s:ABS:D:G:I:Vh?" opt
  150. do
  151.     case $opt in
  152.     b)    BPP=$OPTARG;;
  153.     c)    COLOR=-c;;
  154.     d)    DUPLEX="$OPTARG";;
  155.     g)    GSOPTS="$GSOPTS $OPTARG";;
  156.     m)    MEDIA="$OPTARG";;
  157.     n)    COPIES="$OPTARG";;
  158.     p)    PAPER="$OPTARG";;
  159.     q)    QUALITY="$OPTARG";;
  160.     r)    RES="$OPTARG";;
  161.     s)    SOURCE="$OPTARG";;
  162.     l)    CLIP_LR="-l $OPTARG";;
  163.     u)    CLIP_UL="-u $OPTARG";;
  164.     L)    CLIP_LOG="-L $OPTARG";;
  165.     A)    AIB=-A;;
  166.     B)    BC=-B;;
  167.     S)    COLOR2MONO="-S$OPTARG";;
  168.     D)    DEBUG="$OPTARG";;
  169.     G)    GAMMAFILE="$OPTARG";;
  170.     I)    INTENT="$OPTARG";;
  171.     [234689])    NUP="$opt";;
  172.     [57])    error "Can't find acceptable layout for $opt-up";;
  173.     1)    case "$OPTARG" in
  174.         [024568])    NUP="1$OPTARG";;
  175.         *)    error "Can't find acceptable layout for 1$OPTARG-up";;
  176.         esac
  177.         ;;
  178.     o)    case "$OPTARG" in
  179.         l*)    NUP_ORIENT=-l;;
  180.         s*)    NUP_ORIENT=-r;;
  181.         p*|*)    NUP_ORIENT=;;
  182.         esac;;
  183.     V)    echo "$VERSION"; foo2oak -V; exit 0;;
  184.     h|\?)
  185.         if [ "$CMDLINE" != "-?" -a "$CMDLINE" != -h ]; then
  186.             echo "Illegal command:"
  187.             echo "    $0 $CMDLINE"
  188.             echo
  189.         fi
  190.         usage;;
  191.     esac
  192. done
  193. shift `expr $OPTIND - 1`
  194.  
  195. #
  196. #    Select the ghostscript device to use
  197. #
  198. case "$BPP" in
  199. 1)    if [ "" = "$COLOR" ]; then
  200.         GSDEV=-sDEVICE=pbmraw
  201.     else
  202.         GSDEV=-sDEVICE=bitcmyk
  203.     fi
  204.     ;;
  205. 2)    if [ "" = "$COLOR" ];
  206.     then
  207.         GSDEV=-sDEVICE=pgmraw
  208.     else
  209.         GSDEV="-sDEVICE=cups -dcupsColorSpace=6 -dcupsBitsPerColor=2"
  210.     fi
  211.     ;;
  212. *)    error "Illegal number of bits per plane ($BPP)";;
  213. esac
  214.  
  215. #
  216. case "$QUALITY" in
  217. 0)
  218.     GSOPTS="-dCOLORSCREEN $GSOPTS"
  219.     ;;
  220. 1)
  221.     GSOPTS="-dCOLORSCREEN $GSOPTS"
  222.     ;;
  223. 2)
  224.     GSOPTS="-dMaxBitMap=500000000 $GSOPTS"
  225.     ;;
  226. esac
  227.  
  228. #
  229. #    Validate media code
  230. #
  231. case "$MEDIA" in
  232. 0|auto)        MEDIA=0;;
  233. 1|plain)    MEDIA=1;;
  234. 2|preprinted)    MEDIA=2;;
  235. 3|letterhead)    MEDIA=3;;
  236. 4|gratrans*)    MEDIA=4;;
  237. 5|prepunched)    MEDIA=5;;
  238. 6|labels)    MEDIA=6;;
  239. 7|bond)        MEDIA=7;;
  240. 8|recylcled)    MEDIA=8;;
  241. 9|color)    MEDIA=9;;
  242. 10|cardstock)    MEDIA=10;;
  243. 11|heavy)    MEDIA=11;;
  244. 12|envelope)    MEDIA=12;;
  245. 13|light)    MEDIA=13;;
  246. 14|tough)    MEDIA=14;;
  247. [0-9]*)        ;;
  248. *)        error "Unknown media code $MEDIA";;
  249. esac
  250.  
  251. #
  252. #    Validate source (InputSlot) code
  253. #
  254. case "$SOURCE" in
  255. 1|tray1)    SOURCE=1;;
  256. 4|manual)    SOURCE=4;;
  257. 7|auto)        SOURCE=7;;
  258. [0-9]*)        ;;
  259. *)        error "Unknown source code $SOURCE";;
  260. esac
  261.  
  262. #
  263. #    Validate Duplex code
  264. #
  265. case "$DUPLEX" in
  266. 1|off|none)    DUPLEX=1;;
  267. 2|long*)    DUPLEX=2;;
  268. 3|short*)    DUPLEX=3;;
  269. [0-9]*)        ;;
  270. *)        error "Unknown duplex code $DUPLEX";;
  271. esac
  272.  
  273. #
  274. #    Validate Resolution
  275. #
  276. case "$RES" in
  277. 600x600)    ;;
  278. 1200x600)    ;;
  279. 2400x600)    ;;
  280. *)        error "Illegal resolution $RES";;
  281. esac
  282.  
  283. #
  284. #    Figure out the paper dimensions in pixels/inch, and set the
  285. #    default clipping region.
  286. #
  287. set_clipping() {
  288.     ulx=$1; uly=$2
  289.     lrx=$3; lry=$4
  290.  
  291.     # Set clipping region if it isn't already set
  292.     if [ "$CLIP_UL" = "" ]; then
  293.     case "$RES" in
  294.     600x600)    ulx=`expr $ulx / 2`;;
  295.     2400x600)    ulx=`expr $ulx \* 2`;;
  296.     esac
  297.     CLIP_UL="-u ${ulx}x${uly}"
  298.     fi
  299.     if [ "$CLIP_LR" = "" ]; then
  300.     case "$RES" in
  301.     600x600)    lrx=`expr $lrx / 2`;;
  302.     2400x600)    lrx=`expr $lrx \* 2`;;
  303.     esac
  304.     CLIP_LR="-l ${lrx}x${lry}"
  305.     fi
  306. }
  307.  
  308. case "$PAPER" in
  309. [0-9]*x*[0-9])
  310.         XDIM=`echo "$PAPER" | sed 's/x.*//' `
  311.         YDIM=`echo "$PAPER" | sed 's/.*x//' `
  312.         XDIM=`awk -vval=$XDIM 'BEGIN{ print int(val * 1200.0) }' `
  313.         YDIM=`awk -vval=$YDIM 'BEGIN{ print int(val * 600.0) }' `
  314.         set_clipping 140 100    140 100
  315.         paper=letter
  316.         PAPER=256
  317.         ;;
  318. 1|letter)    PAPER=1;    paper=letter;    XDIM="10200"; YDIM="6600"
  319.         set_clipping 140 100    140 100
  320.         ;;
  321. 5|legal)    PAPER=5;    paper=legal;     XDIM="10200"; YDIM="8400"
  322.         set_clipping 140 100    140 100
  323.         ;;
  324. 7|executive)    PAPER=7;    paper=executive; XDIM="8700";  YDIM="6300"
  325.         set_clipping 140 100    140 100
  326.         ;;
  327. 9|a4|A4)    PAPER=9;    paper=a4;        XDIM="9920";  YDIM="7014"
  328.         set_clipping 160 100    160 100
  329.         ;;
  330. 11|a5|A5)    PAPER=11;    paper=a5;        XDIM="6992";  YDIM="4960"
  331.         set_clipping 140 100    140 100
  332.         ;;
  333. 13|b5jis|B5JIS)    PAPER=13;    paper=b5;        XDIM="8598";  YDIM="6070"
  334.         set_clipping 140 100    140 100
  335.         ;;
  336. *)        error "Unimplemented paper code $PAPER";;
  337. esac
  338. PAPERSIZE="-sPAPERSIZE=$paper";
  339.  
  340. case "$RES" in
  341. 600x600)    XDIM=`expr $XDIM / 2`;;
  342. 1200x600)    ;;
  343. 2400x600)    XDIM=`expr $XDIM \* 2`;;
  344. esac
  345. DIM="${XDIM}x${YDIM}"
  346.  
  347. #
  348. # If there is an argument left, take it as the file to print.
  349. # Else, the input comes from stdin.
  350. #
  351. if [ $# -ge 1 ]; then
  352.     if [ "$LPJOB" = "" ]; then
  353.     LPJOB="$1"
  354.     fi
  355.     exec < $1
  356. fi
  357.  
  358. #
  359. # Filter thru psnup if N-up printing has been requested
  360. #
  361. case $NUP in
  362. [234689]|1[024568])    PREFILTER="nup";;
  363. *)            PREFILTER=cat;;
  364. esac
  365.  
  366. #
  367. #    Overload -G.  If the file name ends with ".icm" or ".ICM"
  368. #    then convert the ICC color profile to a Postscript CRD,
  369. #    then prepend it to the users job.  Select the intent
  370. #    using the -I option.
  371. #
  372.  
  373. create_crd() {
  374.     #
  375.     # Create a Postscript CRD
  376.     #
  377.     ICC2PS=$PREFIX/bin/foo2zjs-icc2ps
  378.     if [ -x $ICC2PS ]; then
  379.     $ICC2PS -o $GAMMAFILE -t$INTENT > $ICCTMP.crd.ps 2>$ICCTMP.log \
  380.     || error "Problem converting .ICM file to Postscript"
  381.     cat > $ICCTMP.usecie.ps <<-EOF
  382.         %!PS-Adobe-3.0
  383.         <</UseCIEColor true>>setpagedevice
  384.     EOF
  385.     cat > $ICCTMP.selcrd.ps <<-EOF
  386.         /Current /ColorRendering findresource setcolorrendering
  387.     EOF
  388.     GAMMAFILE="$ICCTMP.usecie.ps $ICCTMP.crd.ps $ICCTMP.selcrd.ps"
  389.     else
  390.     GAMMFILE=
  391.     fi
  392. }
  393.  
  394. if [ $DEBUG -gt 0 ]; then
  395.     ICCTMP=/tmp/icc
  396. else
  397.     ICCTMP=/tmp/icc$$
  398. fi
  399. case "$GAMMAFILE" in
  400. *.icm|*.ICM|*.icc|*.ICC)
  401.     #
  402.     # Its really an .ICM file, not a gamma file.
  403.     #
  404.     # The file can be a full path name, or the name of a file in $SHARE/icm/
  405.     #
  406.     if [ "$COLOR" = "" ]; then
  407.     GAMMAFILE=
  408.     elif [ -r "$GAMMAFILE" ]; then
  409.     create_crd
  410.     elif [ -r "$SHARE/icm/$GAMMAFILE" ]; then
  411.     GAMMAFILE="$SHARE/icm/$GAMMAFILE"
  412.     create_crd
  413.     else
  414.     GAMMAFILE=
  415.     fi
  416.     ;;
  417. esac
  418.  
  419. #
  420. #    Use a Well Tempered Screen in quality mode 2.
  421. #       from Karl Putland <karl@putland.linux-site.net>
  422. #
  423. #    NOTE from Rick: Karl abandoned this approach.
  424. #
  425. create_wts() {
  426.     #
  427.     # Screen frequencies
  428.     #
  429.     C_FREQ="120"
  430.     M_FREQ="123.33"
  431.     Y_FREQ="126.85"
  432.     K_FREQ="143.22"
  433.  
  434.     case "$RES" in
  435.     600x600)    MUL=0.50;;
  436.     1200x600)    MUL=0.75;;
  437.     2400x600)    MUL=1.00;;
  438.     *)        MUL=0.50;;
  439.     esac
  440.  
  441.     cat > $ICCTMP.wts.ps <<-EOF
  442.     %!PS-Adobe-3.0
  443.     << /UseWTS true >> setuserparams
  444.     <<
  445.     /HalftoneType 5
  446.     /Cyan <<
  447.         /AccurateScreens true
  448.         /HalftoneType 1
  449.         /SpotFunction {
  450.         % 180 mul cos exch 180 mul cos add 2 div
  451.         abs exch abs 2 dup add 0.75 le
  452.             { 2 exp exch 2 exp add 1 exch sub }
  453.             { 2 dup add 1.23 le 
  454.             { exch 0.76 mul add 1 exch sub }
  455.             { 1 sub 2 exp exch 1 sub 2 exp add 1 sub }
  456.             ifelse
  457.             }
  458.             ifelse 
  459.         }
  460.         /TransferFunction {1 exp}
  461.         /Frequency $C_FREQ $MUL mul
  462.         /Angle 98
  463.     >>
  464.     /Magenta <<
  465.         /AccurateScreens true
  466.         /HalftoneType 1
  467.         /SpotFunction { 
  468.         % 180 mul cos exch 180 mul cos add 2 div
  469.         abs exch abs 2 dup add 0.75 le
  470.             { 2 exp exch 2 exp add 1 exch sub }
  471.             { 2 dup add 1.23 le 
  472.             { exch 0.76 mul add 1 exch sub }
  473.             { 1 sub 2 exp exch 1 sub 2 exp add 1 sub }
  474.             ifelse
  475.             }
  476.             ifelse 
  477.         } 
  478.         /TransferFunction {0.45 exp}
  479.         /Frequency $M_FREQ $MUL mul
  480.         /Angle 51.5
  481.     >>
  482.     /Yellow <<
  483.         /AccurateScreens true
  484.         /HalftoneType 1
  485.         /SpotFunction { 
  486.         % 180 mul cos exch 180 mul cos add 2 div
  487.         abs exch abs 2 dup add 0.75 le
  488.             { 2 exp exch 2 exp add 1 exch sub }
  489.             { 2 dup add 1.23 le 
  490.             { exch 0.76 mul add 1 exch sub }
  491.             { 1 sub 2 exp exch 1 sub 2 exp add 1 sub }
  492.             ifelse
  493.             }
  494.             ifelse 
  495.         } 
  496.         /TransferFunction {0.45 exp}
  497.         /Frequency $Y_FREQ $MUL mul
  498.         /Angle 27
  499.     >>
  500.     /Black <<
  501.         /AccurateScreens true
  502.         /HalftoneType 1
  503.         /SpotFunction { 
  504.         % 180 mul cos exch 180 mul cos add 2 div
  505.         abs exch abs 2 dup add 0.75 le
  506.             { 2 exp exch 2 exp add 1 exch sub }
  507.             { 2 dup add 1.23 le 
  508.             { exch 0.76 mul add 1 exch sub }
  509.             { 1 sub 2 exp exch 1 sub 2 exp add 1 sub }
  510.             ifelse
  511.             }
  512.             ifelse 
  513.         } 
  514.         /TransferFunction {0.60 exp}
  515.         /Frequency $K_FREQ $MUL mul
  516.         /Angle 75
  517.     >>
  518.     /Default <<
  519.         /AccurateScreens true
  520.         /HalftoneType 1
  521.         /SpotFunction { 
  522.         % 180 mul cos exch 180 mul cos add 2 div
  523.         abs exch abs 2 dup add 0.75 le
  524.         { 2 exp exch 2 exp add 1 exch sub }
  525.         { 2 dup add 1.23 le 
  526.             { exch 0.76 mul add 1 exch sub }
  527.             { 1 sub 2 exp exch 1 sub 2 exp add 1 sub }
  528.             ifelse
  529.         }
  530.         ifelse 
  531.         } 
  532.         /TransferFunction {0.45 exp}
  533.         /Frequency $Y_FREQ $MUL mul
  534.         /Angle 27
  535.     >>
  536.     >> sethalftone
  537.     EOF
  538.  
  539.     GAMMAFILE="$GAMMAFILE $ICCTMP.wts.ps"
  540. }
  541.  
  542. if [ "$COLOR" != "" -a "$QUALITY" = 2 ]; then
  543.     create_wts
  544. fi
  545.  
  546. #
  547. #    Figure out USERNAME
  548. #
  549. if [ "$LPUSER" != "" ]; then
  550.     USER="$LPUSER@$LPHOST"
  551. else
  552.     USER=""
  553. fi
  554.  
  555. #
  556. #    Main Program, just cobble together the pipeline and run it
  557. #
  558. #    The malarky with file descriptors 1 and 3 is to avoid a bug in
  559. #    (some versions?) of Ghostscript where Postscript's stdout gets
  560. #    intermingled with the printer drivers output, resulting in
  561. #    corrupted image data.
  562. #
  563. GS="$GSBIN -q -dBATCH -dSAFER -dQUIET -dNOPAUSE"
  564.  
  565. $PREFILTER \
  566. | ($GS $PAPERSIZE -g$DIM -r$RES $GSDEV $GSOPTS \
  567.     -sOutputFile="|cat 1>&3" $GAMMAFILE - >/dev/null 2>/dev/null) 3>&1 \
  568. | dbgcmd foo2oak -r$RES -g$DIM -p$PAPER -m$MEDIA -n$COPIES -d$DUPLEX -s$SOURCE \
  569.         $COLOR -b$BPP $CLIP_UL $CLIP_LR $CLIP_LOG \
  570.         -J "$LPJOB" -U "$USER" \
  571.         $BC $AIB $COLOR2MONO -D$DEBUG
  572.  
  573. #
  574. #    Log the command line, for debugging and problem reports
  575. #
  576. if [ $DEBUG = 0 -a -x /usr/bin/logger ]; then
  577.     logger -t "$BASENAME" -p lpr.info -- \
  578.     "gs $PAPERSIZE -g$DIM -r$RES $GSDEV $GSOPT"
  579.     logger -t "$BASENAME" -p lpr.info -- \
  580.     "foo2oak -r$RES -g$DIM -p$PAPER -m$MEDIA \
  581. -n$COPIES -d$DUPLEX -s$SOURCE $COLOR -b$BPP $CLIP_UL $CLIP_LR $CLIP_LOG \
  582. $BC $AIB $COLOR2MONO"
  583. fi
  584.  
  585. #
  586. #    Remove cruft
  587. #
  588. if [ $DEBUG -eq 0 ]; then
  589.     for i in crd.ps log usecie.ps selcrd.ps wts.ps
  590.     do
  591.     file="$ICCTMP.$i"
  592.     [ -f $file ] && rm -f $file
  593.     done
  594. fi
  595.  
  596. exit 0
  597.