#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1999-02-09 16:27 EST by <jcej@chiroptera.tragus.org>.
# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/010'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    440 -rw-rw-r-- hdr
#     49 -rw-rw-r-- bodies
#   2246 -rw-rw-r-- page01.pre
#     84 -rw-rw-r-- page02.pre
#    231 -rw-rw-r-- page03.pre
#    138 -rw-rw-r-- page04.pre
#    607 -rw-rw-r-- page05.pre
#   1493 -rw-rw-r-- page06.pre
#    444 -rw-rw-r-- page07.pre
#    689 -rw-rw-r-- page02.pst
#    237 -rw-rw-r-- page03.pst
#    387 -rw-rw-r-- page04.pst
#    366 -rw-rw-r-- page05.pst
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh15890; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= hdr ==============
if test -f 'hdr' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'hdr' '(file already exists)'
else
  $echo 'x -' extracting 'hdr' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'hdr' &&
<HTML>
<HEAD>
X   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
X   <META NAME="Author" CONTENT="James CE Johnson">
X   <TITLE>ACE Tutorial 010</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
X
<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER>
X
<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER>
X
X
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0124153399 'hdr' &&
  chmod 0664 'hdr' ||
  $echo 'restore of' 'hdr' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'hdr:' 'MD5 check failed'
e3d97df3787127f8678ec95f024c44c6  hdr
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`"
    test 440 -eq "$shar_count" ||
    $echo 'hdr:' 'original size' '440,' 'current size' "$shar_count!"
  fi
fi
# ============= bodies ==============
if test -f 'bodies' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'bodies' '(file already exists)'
else
  $echo 'x -' extracting 'bodies' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'bodies' &&
PAGE=2
message_queue.cpp
block.h
task.h
task.cpp
SHAR_EOF
  $shar_touch -am 0124153399 'bodies' &&
  chmod 0664 'bodies' ||
  $echo 'restore of' 'bodies' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'bodies:' 'MD5 check failed'
888c8b85427980776f703176da1f9ee4  bodies
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
    test 49 -eq "$shar_count" ||
    $echo 'bodies:' 'original size' '49,' 'current size' "$shar_count!"
  fi
fi
# ============= page01.pre ==============
if test -f 'page01.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page01.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page01.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' &&
<P>
In an earlier tutorial we briefly introduced ACE_Message_Queue.  In this
tutorial we'll go into a bit more detail.
<P>
ACE_Message_Queue is modeled after Unix System V IPC mechanisms.  The basic
idea is that you put a block of data into one end of the Queue and take it
out of the other end.  Your basic FIFO in other words.  The SysV mechanism
works great for passing these blocks of data between processes on the same
host but it's a bit overkill for moving blocks between threads.  You could
use a pipe, socket or similar mechanism but that still has more overhead than
we really want just for moving data between threads.  Process-global memory
is a good technique but then you need a way to signal the "listening" threads.
The ACE_Message_Queue is a better approach:  Create blocks of data and enqueue
them in one thread while another thread (or threads) dequeue and perform work.
<P>
Kirthika's Abstract:
<UL>
The Message Queue is a FIFO accessible from multiple threads.
That is, a thread puts the produced blocks of data on the message queue
to be consumed by some other thread/threads and processed. In this
tutorial, we see how effectively the Message Queue in a ACE_Task can be
used to pass data among threads in the thread pool. 
(this is very similar to 
<A HREF="../007/page01.html">Tutorial 7</A>
X wherein we implemented a
thread-pool server).Here, actual data is passed between the threads and
also an ACE_Barrier has been used to provide synchronisation among
multiple threads.
<P>
The Message Queue consists of Message Blocks, each of which has a read
and write pointer. Using these pointers the message blocks can be
accessed for reading and writing operations. The ACE_Task::svc() method
will put the block onto the queue without bothering about the existence 
of a consumer for that block. A thread from the thread pool obtains the
block from the queue, and checks to see whether the block_type is
MB_HANGUP. If so, it puts the block back on the queue for its 
peers and exits. Otherwise, it reads the block and processes it before
releasing it.
<P>
This simple tutorial makes us aware of the usage and importance of the
Message Queue which could be used to our advantage especially for
multithreaded applications.
</UL>
SHAR_EOF
  $shar_touch -am 0124153899 'page01.pre' &&
  chmod 0664 'page01.pre' ||
  $echo 'restore of' 'page01.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page01.pre:' 'MD5 check failed'
84d1b63ff2eb7eecec515b248f73d791  page01.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
    test 2246 -eq "$shar_count" ||
    $echo 'page01.pre:' 'original size' '2246,' 'current size' "$shar_count!"
  fi
fi
# ============= page02.pre ==============
if test -f 'page02.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page02.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page02.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' &&
X
We'll look first at <A HREF="message_queue.cpp">main()</A>.
<P>
X
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0124153399 'page02.pre' &&
  chmod 0664 'page02.pre' ||
  $echo 'restore of' 'page02.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page02.pre:' 'MD5 check failed'
166bf09c6c4474767e95ef4a7be20a03  page02.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
    test 84 -eq "$shar_count" ||
    $echo 'page02.pre:' 'original size' '84,' 'current size' "$shar_count!"
  fi
fi
# ============= page03.pre ==============
if test -f 'page03.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page03.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page03.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' &&
Our <A HREF="block.h">Block</A> object is a very simple derivative
of the ACE_Message_Block.  The only reason I created it was to prove
that the message blocks to, indeed, get freed when we're done with 'em.
<P>
X
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0124153399 'page03.pre' &&
  chmod 0664 'page03.pre' ||
  $echo 'restore of' 'page03.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page03.pre:' 'MD5 check failed'
3164732c254de8d97fac8fd52071ae32  page03.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
    test 231 -eq "$shar_count" ||
    $echo 'page03.pre:' 'original size' '231,' 'current size' "$shar_count!"
  fi
fi
# ============= page04.pre ==============
if test -f 'page04.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page04.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page04.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' &&
Our <A HREF="task.h">Task</A> object executes in one or more threads
and reads from the message queue it contains.
<P>
X
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0124153399 'page04.pre' &&
  chmod 0664 'page04.pre' ||
  $echo 'restore of' 'page04.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page04.pre:' 'MD5 check failed'
fec9a7b5b9b2a8f61c0178aaf1b78a91  page04.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
    test 138 -eq "$shar_count" ||
    $echo 'page04.pre:' 'original size' '138,' 'current size' "$shar_count!"
  fi
fi
# ============= page05.pre ==============
if test -f 'page05.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page05.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page05.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' &&
X
Our <A HREF="task.cpp">Task</A> object definition.
<P>
Something to look at here is the ACE_Barrier usage.  In the
constructor, we tell the barrier how many threads we're using.  Then,
in the svc() method, we use the barrier's wait() method.  You can
think of the barrier as a semaphore initialized to the thread count.
X  Each time wait()
is invoked, the semaphore is decremented and the thread is blocked.
X  When the count equals zero, all threads are unblocked and allowed to
continue.
<P>
<font size=-1>Note:  This isn't the way ACE_Barrier really works, it's 
just an analogy</font>
X
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0209155699 'page05.pre' &&
  chmod 0664 'page05.pre' ||
  $echo 'restore of' 'page05.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page05.pre:' 'MD5 check failed'
ff8f02648de795cd92f08141962d746d  page05.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
    test 607 -eq "$shar_count" ||
    $echo 'page05.pre:' 'original size' '607,' 'current size' "$shar_count!"
  fi
fi
# ============= page06.pre ==============
if test -f 'page06.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page06.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page06.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page06.pre' &&
X
Since I added Block just to give us output, let's take a look at that output.
X
<P>
<HR WIDTH="100%">
<PRE>
[jcej@chiroptera 010]$./message_queue 4 2
(8910|1024) Task ctor 0xbffff9c4
(8910|2050) Task 0xbffff9c4 starts in thread 2050
(8910|1025) Task 0xbffff9c4 starts in thread 1025
(8910|1024) Block ctor 0x8052398
(8910|1024) Block ctor 0x8052488
(8910|1024) Block ctor 0x8052578
(8910|1024) Block ctor 0x8052668
(8910|1024) Block ctor 0x8052758
(8910|1025) Block 0x8052398 contains (This is message 0.)
(8910|2050) Block 0x8052488 contains (This is message 1.)
(8910|1025) Block dtor 0x8052398
(8910|1025) Block 0x8052578 contains (This is message 2.)
(8910|2050) Block dtor 0x8052488
(8910|2050) Block 0x8052668 contains (This is message 3.)
(8910|1025) Block dtor 0x8052578
(8910|1025) Task close 0xbffff9c4
(8910|2050) Block dtor 0x8052668
(8910|2050) Task close 0xbffff9c4
(8910|1024) Task dtor 0xbffff9c4
(8910|1024) Block dtor 0x8052758
(8910|1024) Application exiting
[jcej@chiroptera 010]$
</PRE>
<HR WIDTH="100%">
<P>
Notice that each <i>Block ctor</i> has a corresponding <i>Block dtor</i>.
We've proven the point that all memory gets cleaned up.  We also see that
both threads get to do some work and that both close as expected.
<P>
It's also worth mentioning that it's just an accident that all of the blocks
are created and enqueued before any are processed.  Run the test on a multi-processor
or with more iterations and you'll see some get processed before all are created.
SHAR_EOF
  $shar_touch -am 0124153299 'page06.pre' &&
  chmod 0664 'page06.pre' ||
  $echo 'restore of' 'page06.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page06.pre:' 'MD5 check failed'
d2a471df09308f89a611a7aa0218737f  page06.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`"
    test 1493 -eq "$shar_count" ||
    $echo 'page06.pre:' 'original size' '1493,' 'current size' "$shar_count!"
  fi
fi
# ============= page07.pre ==============
if test -f 'page07.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page07.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page07.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page07.pre' &&
X
That's it for Tutorial 10.  There are some esoteric changes between the thread-pool server
and this application but it's basically the same.  In the next tutorial I'll modify this just
a bit to move non-trivial data through the queue.
<P>
X
<UL>
<LI><A HREF="Makefile">Makefile</A>
<LI><A HREF="block.h">block.h</A>
<LI><A HREF="message_queue.cpp">message_queue.cpp</A>
<LI><A HREF="task.cpp">task.cpp</A>
<LI><A HREF="task.h">task.h</A>
</UL>
SHAR_EOF
  $shar_touch -am 0124153299 'page07.pre' &&
  chmod 0664 'page07.pre' ||
  $echo 'restore of' 'page07.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page07.pre:' 'MD5 check failed'
07ae8f9b2a400e46ab102ab8c40a8b81  page07.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page07.pre'`"
    test 444 -eq "$shar_count" ||
    $echo 'page07.pre:' 'original size' '444,' 'current size' "$shar_count!"
  fi
fi
# ============= page02.pst ==============
if test -f 'page02.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page02.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page02.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page02.pst' &&
<HR WIDTH="100%">
<P>
This looks a lot like our thread-pool server and it even does some things
better.  In particular, I've scoped the Task object so that it's destructor
will have a chance to get called before the application exits.
Notice how we write actual data into the message block though.  In the thread-pool
server we just provided a pointer.  Writting the data is actually a more correct
way of doing things since you don't get into strange pointer casting situations.
What if you want to put complex objects into the message block though?  We'll do
that in the next tutorial, let's stick with the basics first.
<P>
On the next page we'll take a look at our Block object...
<P>
SHAR_EOF
  $shar_touch -am 0124153399 'page02.pst' &&
  chmod 0664 'page02.pst' ||
  $echo 'restore of' 'page02.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page02.pst:' 'MD5 check failed'
10957f28adbff16015bd94bdc01cd779  page02.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pst'`"
    test 689 -eq "$shar_count" ||
    $echo 'page02.pst:' 'original size' '689,' 'current size' "$shar_count!"
  fi
fi
# ============= page03.pst ==============
if test -f 'page03.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page03.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page03.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page03.pst' &&
<HR WIDTH="100%">
<P>
Ok, nothing really magic there.  Some folks just feel a little uncomfortable
not doing an explicit <i>delete</i> on objects they've <i>new</i>'d so I
wanted to show you that the memory really does get cleaned up.
X 
SHAR_EOF
  $shar_touch -am 0124153399 'page03.pst' &&
  chmod 0664 'page03.pst' ||
  $echo 'restore of' 'page03.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page03.pst:' 'MD5 check failed'
f0ce99c3625ad734730e7ac93efd2c8d  page03.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pst'`"
    test 237 -eq "$shar_count" ||
    $echo 'page03.pst:' 'original size' '237,' 'current size' "$shar_count!"
  fi
fi
# ============= page04.pst ==============
if test -f 'page04.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page04.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page04.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page04.pst' &&
<HR WIDTH="100%">
<P>
The only thing here that we didn't see in the thread-pool server is the
ACE_Barrier.  The application logic really doesn't need it but it is a
handy way to synchronize the threads at the beginning of svc().  In testing
I found that if I didn't sync svc(), the first thread to get activated would
tend to get all of the messages before the other threads came alive.
SHAR_EOF
  $shar_touch -am 0124153399 'page04.pst' &&
  chmod 0664 'page04.pst' ||
  $echo 'restore of' 'page04.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page04.pst:' 'MD5 check failed'
2212efef5c096791808b00a5212c4376  page04.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pst'`"
    test 387 -eq "$shar_count" ||
    $echo 'page04.pst:' 'original size' '387,' 'current size' "$shar_count!"
  fi
fi
# ============= page05.pst ==============
if test -f 'page05.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page05.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page05.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page05.pst' &&
<HR WIDTH="100%">
<P>
This is all pretty straight-forward too.  One gottcha we avoided was a memory leak
due to our shutdown message.  Notice that svc() enqueues that block without bothering
to see if there are any more threads to dequeue it.  Thats why our dtor can call getq()
without worrying about blocking infinitely:  it knows the message block will be there.
SHAR_EOF
  $shar_touch -am 0124153399 'page05.pst' &&
  chmod 0664 'page05.pst' ||
  $echo 'restore of' 'page05.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page05.pst:' 'MD5 check failed'
54b2e8e21aa451c7a3a227da8069bdf7  page05.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pst'`"
    test 366 -eq "$shar_count" ||
    $echo 'page05.pst:' 'original size' '366,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh15890
exit 0
