s+ow: update files

This commit is contained in:
Mark Joshwel 2024-06-18 18:58:39 +08:00
parent 44907e3462
commit 40d318bef7
6 changed files with 169 additions and 344 deletions

View file

@ -1,284 +1,13 @@
# surplus on wheels
surplus on wheels (s+ow) is a pure shell script to get your location using
`termux-location`, process it through [surplus](https://github.com/markjoshwel/surplus),
and send it to messaging service or wherever using [bridges](#bridges).
[termux-location](https://wiki.termux.com/wiki/Termux-location), process it through surplus, and
send it to messaging service or wherever using “bridges”
surplus was made to emulate sending your location through the iOS Shortcuts app, and
surplus on wheels complements it by running surplus automatically using a cron job.
surplus was made to emulate sending your location through the iOS Shortcuts app, and surplus on
wheels complements it by running surplus automatically using a cron job.
(but using it manually also works!)
- [installing](#installing)
- [as a standalone script](#as-a-standalone-script)
- [as a cron job](#as-a-cron-job)
- [using installation scripts](#using-installation-scripts)
- [usage](#usage)
- [environment variables](#environment-variables)
- [faking locations](#faking-locations)
- [bridges](#bridges)
- [bring your own bridge](#bring-your-own-bridge)
- [licence](#licence)
## installing
> [!IMPORTANT]
> s+ow is a Termux-first script, and will not work anywhere else unless you have
> a utility that emulates [termux-location](https://wiki.termux.com/wiki/termux-location)
> on `$PATH` alongside bridges that supports your platform.
there are two notable ways to install s+ow:
1. [as a standalone script](#as-a-standalone-script)
2. or, [as a cron job](#as-a-cron-job).
there is also an [installation script](#using-installation-scripts) for quickly getting
started from a _fresh_ termux installation.
### as a standalone script
1. firstly install python and termux-api if you haven't already:
```text
pkg install python termux-api
```
also install the accompanying the Termux:API app from [F-Froid](https://f-droid.org/en/packages/com.termux.api/).
2. install pipx
```text
pip install pipx
```
3. install surplus:
```text
pip install https://github.com/markjoshwel/surplus/releases/latest/download/surplus-latest-py3-none-any.whl
```
4. install surplus on wheels:
```text
mkdir -p ~/.local/bin/
curl https://raw.githubusercontent.com/markjoshwel/surplus-on-wheels/main/s+ow > ~/.local/bin/s+ow
chmod +x ~/.local/bin/s+ow
```
if `~/.local/bin` is not in your `$PATH`, add the following to your shell's rc file:
```shell
export PATH="$HOME/.local/bin:$PATH"
```
et voilà! s+ow is now setup. to actually send the message to a messaging platform,
[install an appropriate bridge](#bridges).
### as a cron job
> [!IMPORTANT]
> these instructions rely on following the [previous instructions](#as-a-standalone-script).
1. install necessary packages to run cron jobs:
```text
pkg install cronie termux-services
```
2. restart termux and start the cron service:
```text
sv-enable cron
```
3. set up the cron job:
> [!IMPORTANT]
> minimally fill in the `SPOW_TARGETS` variable before running s+ow.
> [(see usage for more info)](#usage)
run the following command:
```text
crontab -e
```
and add the following text:
```text
59 * * * * bash -l -c "SPOW_TARGETS="" SPOW_CRON=y s+ow"
```
this will run s+ow every hour, a minute before the hour.
modify the variables as per your needs.
see [usage](#usage) for more information.
et voilà! s+ow will now send a message every hour. feel free to experiment with the cron
job to your liking. see [crontab.guru](https://crontab.guru/) if youre new to cron jobs.
if you havent already, [install an appropriate bridge](#bridges) to actually send a
message to a messaging platform.
### using installation scripts
> [!WARNING]
> these scripts assume you're starting from a fresh base installation of Termux.
> if you have already cron jobs, then manually carry out the instructiions in
> [as a cron job](#as-a-cron-job).
> [!IMPORTANT]
> if not installed already, install [Termux:API](https://f-droid.org/en/packages/com.termux.api/)
> from F-Droid.
1. setup s+ow:
```text
curl https://raw.githubusercontent.com/markjoshwel/surplus-on-wheels/main/termux-s+ow-setup | sh
```
2. restart termux!
3. setup cron job:
```text
curl https://raw.githubusercontent.com/markjoshwel/surplus-on-wheels/main/termux-s+ow-setup-cron | sh
```
the script will run `crontab -e`, and you can then edit the variables as per your
needs. minimally fill in the `SPOW_TARGETS` variable before running s+ow.
see [usage](#usage) for more information.
et voilà! s+ow is now setup. to actually send the message to a messaging platform,
[install an appropriate bridge](#bridges).
## usage
### environment variables
s+ow uses three environment variables, two of which are optional:
1. `SPOW_TARGETS`
a single line of comma-deliminated chat IDs with bridge prefixes.
```text
wa:000000000000000000@g.us,tg:-0000000000000000000,...
```
in the example above, the WhatsApp chat ID is `wa:`-prefixed as recognised by the
[spow-whatsapp-bridge](https://github.com/markjoshwel/spow-whatsapp-bridge), and the
Telegram chat ID is `tg:`-prefixed as recognised by the
[spow-telegram-bridge](https://github.com/markjoshwel/spow-telegram-bridge).
2. `SPOW_CRON` (optional)
set as non-empty to declare that s+ow is being run as a cron job.
if running as a cron job, start s+ow one minute earlier than intended to account for
the time it takes to run `termux-location` and `surplus`.
s+ow will delay itself appropriately.
setting it to `n` will also be treated as empty.
3. `LOCATION_PRIORITISE_NETWORK` (optional)
set as non-empty to declare that s+ow can just use network location instead of GPS
if GPS is taking too long.
you should only turn this on if punctuality means that much to you, or youre in a
country with cell towers close by or everywhere, like Singapore.
setting it to `n` will also be treated as empty.
the JIDs can be obtained by sending a message to the user/group, while running
`s+ow mdtest`, and examining the output for your message. JIDs are email address-like
strings.
4. `LOCATION_TIMEOUT` (optional)
set as a number to override the default first location timeout of `50`.
### faking locations
> sometimes you gotta do what you gotta do
you can fake your s+ow messages by either:
1. setting a dummy `last` file in s+ow cache
`$HOME/.cache/s+ow/last` is used as the fallback response when a part of s+ow (either
`termux-location` or `surplus` errors out). you can set this file to whatever you want
and just turn off location on your device.
2. setting a `fake` file in s+ow cache
> [!WARNING]
> s+ow uses the `read` command to read the file. as such, it is possible for s+ow to
> prematurely stop reading the file if the file does not contain a trailing newline.
you can also write text to `$HOME/.cache/s+ow/fake` to fake upcoming messages. the file
is delimited by empty lines. as such, arrange the file like so:
```text
The Clementi Mall
3155 Commonwealth Avenue West
Westpeak Terrace
129588
Southwest, Singapore
Westgate
3 Gateway Drive
Jurong East
608532
Southwest, Singapore
...
```
on every run of s+ow, the first group of lines will be consumed, and the file will be
updated with the remaining lines. if the file is empty, it will be deleted.
## bridges
there are two “official” bridges for s+ow:
- [spow-whatsapp-bridge](https://github.com/markjoshwel/spow-whatsapp-bridge)
- [spow-telegram-bridge](https://github.com/markjoshwel/spow-telegram-bridge)
bridges can be located anywhere, as long as they are reachable by the shell s+ow is
running in.
s+ow will run the bridges through definitions in in `$HOME/.s+ow-bridges`.
each line of `$HOME/.s+ow-bridges` is evaluated as a shell command, and is piped
`SPOW_TARGETS`.
> [!WARNING]
> s+ow uses the `read` command to read the file. as such, it is possible for s+ow to
> prematurely stop reading the file if the file does not contain a trailing newline.
### bring your own bridge
custom bridges are relatively easy as they are:
1. an executable or script
2. that reads `SPOW_TARGETS` (see [usage](#usage)) from stdin
- bridges should account for the possibility of comma and space (`, ` instead of just
`,`) delimited targets, and strip each target of preceding and trailing whitespace.
- bridges should recognise a platform based on a prefix
(e.g. `wa:` for WhatsApp, `tg:` for Telegram, etc.)
- bridges do not need to account for the possibility of multiple lines sent to stdin.
3. reads `SPOW_MESSAGE` (`~/.cache/spow/message`) for the message content
notes:
1. stderr and stdout are redirected to s+ows error and output logs respectively.
2. any errors encountered by the bridge should always result in a non-zero return.
error logs will show the exact error code, so feel free to use other numbers than 1.
3. persistent data such as credentials and session data storage are to be handled by the
bridge itself.
consider storing them in `$HOME/.local/share/<bridge-name>/`, or similar.
## licence
surplus on wheels is free and unencumbered software released into the public domain.
for more information, please refer to [UNLICENCE](/UNLICENCE) or <http://unlicense.org/>.
see <https://surplus.joshwel.co/onwheels/>
or [/docs/onwheels/index.md](../../docs/onwheels/index.md)
for more information and documentation

View file

@ -0,0 +1,37 @@
#!/bin/sh
# surplus on wheels: termux installation script
set -e
# get packages
yes | pkg upgrade
yes | pkg install python cronie termux-api termux-services wget
# install pipx and surplus
pip install pipx
pipx install surplus
# install s+ow
mkdir -p ~/.local/bin/
if ping -c 1 surplus.joshwel.co ; then
wget -O ~/.local/bin/s+ow https://surplus.joshwel.co/spow.sh
else
wget -O ~/.local/bin/s+ow https://raw.githubusercontent.com/markjoshwel/surplus/main/src/surplus-on-wheels/s+ow
fi
chmod +x ~/.local/bin/s+ow
# setup path
echo "export PATH=\$PATH:\$HOME/.local/bin/" >> ~/.profile
printf "
----- done! -----
if you're going to set a cron job up:
1. restart termux
2. run crontab -e
3. add \"59 * * * * bash -l -c \"(SPOW_TARGETS="" SPOW_CRON=y s+ow)\"\"
(remember to minimally fill in the SPOW_TARGETS variable)
else, surplus on wheels has been set up!
"

View file

@ -2,10 +2,38 @@
# surplus on wheels (s+ow) - a pure shell script to run surplus with mdtest using the termux-api
# ------------------------
# public domain, unlicence
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>
SURPLUS_CMD_DEFAULT="surplus -td"
SURPLUS_CMD=${SURPLUS_CMD:-$SURPLUS_CMD_DEFAULT}
LOCATION_CMD_DEFAULT="termux-location"
LOCATION_CMD=${LOCATION_CMD:-$LOCATION_CMD_DEFAULT}
# shellcheck disable=SC2059
LOCATION_FALLBACK="%d%d%d\nSingapore?"
LOCATION_FALLBACK=${LOCATION_FALLBACK:-"%d%d%d\nSingapore?"}
# shellcheck disable=SC2269
LOCATION_PRIORITISE_NETWORK="$LOCATION_PRIORITISE_NETWORK"
LOCATION_TIMEOUT=${LOCATION_TIMEOUT:-50}
@ -15,17 +43,18 @@ SPOW_TARGETS="$SPOW_TARGETS"
SPOW_CACHE_DIR="$HOME/.cache/s+ow"
SPOW_BRIDGES="$HOME/.s+ow-bridges"
SPOW_CRON=${SPOW_CRON:-n}
SPOW_PRIVATE=${SPOW_PRIVATE:-n}
# per-tool session logs
SPOW_NETLC_OUT="$SPOW_CACHE_DIR/location.net.json"
SPOW_GPSLC_OUT="$SPOW_CACHE_DIR/location.gps.json"
SPOW_LOCTN_OUT="$SPOW_CACHE_DIR/location.json"
SPOW_SPLUS_OUT="$SPOW_CACHE_DIR/surplus.out.log"
SPOW_SPLUS_ERR="$SPOW_CACHE_DIR/surplus.err.log"
SPOW_NETLC_OUT="$SPOW_CACHE_DIR/location.net.json" # honours SPOW_PRIVATE (cleared after use)
SPOW_GPSLC_OUT="$SPOW_CACHE_DIR/location.gps.json" # honours SPOW_PRIVATE (cleared after use)
SPOW_LOCTN_OUT="$SPOW_CACHE_DIR/location.json" # honours SPOW_PRIVATE (cleared after use)
SPOW_SPLUS_OUT="$SPOW_CACHE_DIR/surplus.out.log" # honours SPOW_PRIVATE (cleared after use)
SPOW_SPLUS_ERR="$SPOW_CACHE_DIR/surplus.err.log" # honours SPOW_PRIVATE (set to /dev/null + cleared after use)
# per-session collated logs
SPOW_SESH_OUT="$SPOW_CACHE_DIR/out.log"
SPOW_SESH_ERR="$SPOW_CACHE_DIR/err.log"
SPOW_SESH_OUT="$SPOW_CACHE_DIR/out.log" # honours SPOW_PRIVATE (set to /dev/null)
SPOW_SESH_ERR="$SPOW_CACHE_DIR/err.log" # honours SPOW_PRIVATE (set to /dev/null)
# per-week collated logs
SPOW_WEEK_PRE="$SPOW_CACHE_DIR/$(date +%Y)W$(date +"%V")"
@ -36,7 +65,7 @@ SPOW_WEEK_ERR="$SPOW_WEEK_PRE.err.log"
SPOW_LAST_OUT="$SPOW_CACHE_DIR/last"
# message to be sent
SPOW_MESSAGE="$SPOW_CACHE_DIR/message"
SPOW_MESSAGE="$SPOW_CACHE_DIR/message" # honours SPOW_PRIVATE (cleared after use)
# list of fakes
SPOW_FAKE_OUT="$SPOW_CACHE_DIR/fake"
@ -51,14 +80,31 @@ if [ "$SPOW_CRON" = "n" ]; then
SPOW_CRON=""
fi
# ensure commands exist
if ! command -v termux-location >/dev/null 2>&1; then
printf "s+ow: error: termux-location is not installed.\ninstall it with 'pkg install termux-api' and with installing the termux:api app from the play store or f-droid.\n"
exit 1
# check if running in 'private' mode
if [ "$SPOW_PRIVATE" = "n" ]; then
SPOW_PRIVATE=""
fi
if ! command -v surplus >/dev/null 2>&1; then
printf "s+ow: error: surplus is not installed.\ninstall it with 'pip install https://github.com/markjoshwel/surplus/releases/latest/download/surplus-latest-py3-none-any.whl'\n"
# extract command names for checking
TERMUX_EXE=$(echo "$TERMUX_CMD" | awk '{print $1}')
SURPLUS_EXE=$(echo "$SURPLUS_CMD" | awk '{print $1}')
# ensure commands exist
if ! command -v "$SURPLUS_EXE" >/dev/null 2>&1; then
if [ "$SURPLUS_EXE" = "surplus" ]; then
printf "s+ow: error: surplus is not installed.\ninstall it with 'pip install surplus'. see <https://surplus.joshwel.co> for more information.\n"
else
printf "s+ow: error: custom surplus command '%s' is not accessible" "$SURPLUS_EXE"
fi
exit 2
fi
if ! command -v "$TERMUX_EXE" >/dev/null 2>&1; then
if [ "$TERMUX_EXE" = $LOCATION_CMD_DEFAULT ]; then
printf "s+ow: error: termux-location is not installed.\ninstall it with 'pkg install termux-api' and with installing the termux:api app from the play store or f-droid.\n"
else
printf "s+ow: error: custom location command '%s' is not accessible" "$TERMUX_EXE"
fi
exit 1
fi
@ -74,6 +120,13 @@ touch "$SPOW_NETLC_OUT" "$SPOW_GPSLC_OUT" "$SPOW_LOCTN_OUT" \
"$SPOW_WEEK_OUT" "$SPOW_WEEK_ERR" \
"$SPOW_BRIDGES" "$SPOW_FAKE_OUT"
# disable logs if private
if [ -n "$SPOW_PRIVATE" ]; then
SPOW_SESH_OUT="/dev/null"
SPOW_SESH_ERR="/dev/null"
SPOW_SPLUS_ERR="/dev/null"
fi
# 0 is nominal
# 1 is an termux-location error
# 2 is a surplus error
@ -86,7 +139,7 @@ bridge_returns=""
locate() {
# spawn termux-location processes
(
termux-location -p "network" >"$SPOW_NETLC_OUT"
$LOCATION_CMD -p "network" >"$SPOW_NETLC_OUT"
if [ -s "$SPOW_NETLC_OUT" ]; then
printf "net" | tee -a "$SPOW_SESH_ERR"
else
@ -97,7 +150,7 @@ locate() {
tl_net_pid="$!"
sleep 1
(
termux-location -p "gps" >"$SPOW_GPSLC_OUT"
$LOCATION_CMD -p "gps" >"$SPOW_GPSLC_OUT"
if [ -s "$SPOW_GPSLC_OUT" ]; then
printf "gps" | tee -a "$SPOW_SESH_ERR"
else
@ -108,7 +161,7 @@ locate() {
tl_gps_pid="$!"
# wait until timeout or both finished
printf "running termux-location" | tee -a "$SPOW_SESH_ERR"
printf "running '%s'" "$LOCATION_CMD" | tee -a "$SPOW_SESH_ERR"
while [ "$LOCATION_TIMEOUT" -gt 0 ]; do
# get process statuses
kill -0 "$tl_net_pid" >/dev/null 2>&1
@ -121,7 +174,7 @@ locate() {
break
fi
# exception: if network is proritised: just use that
# exception: if network is prioritised: just use that
if [ "$tl_net_status" -eq 1 ] && [ -n "$LOCATION_PRIORITISE_NETWORK" ]; then
# break only if theres an actual response
if [ -s "$SPOW_NETLC_OUT" ]; then
@ -179,7 +232,7 @@ locate() {
}
gensharetext() {
surplus -td "$1" >"$SPOW_SPLUS_OUT" 2>"$SPOW_SPLUS_ERR"
$SURPLUS_CMD "$1" >"$SPOW_SPLUS_OUT" 2>"$SPOW_SPLUS_ERR"
ret="$?"
cat "$SPOW_SPLUS_OUT" >>"$SPOW_SESH_OUT"
cat "$SPOW_SPLUS_ERR" >>"$SPOW_SESH_ERR"
@ -237,7 +290,7 @@ send() {
done <"$SPOW_FAKE_OUT"
if [ -n "$fake_first" ]; then
printf "$fake_rest\n" >"$SPOW_FAKE_OUT"
printf "%s\n" "$fake_rest" >"$SPOW_FAKE_OUT"
fi
fi
@ -283,7 +336,7 @@ send() {
fi
done <"$SPOW_BRIDGES"
else
printf "s+ow: warning: no '$SPOW_BRIDGES' file; message is not sent.\n"
printf "s+ow: warning: no '%s' file; message is not sent.\n" "$SPOW_BRIDGES"
termux-notification \
--priority "default" \
--title "surplus on wheels: No bridges" \
@ -341,7 +394,7 @@ run() {
notify "Waiting for the 30th second to pass..."
printf "waiting for the 30th second to pass...\n"
while [ "$(date +'%S')" -lt 30 ]; do
printf " $(date)\n"
printf " %s\n" "$(date)"
sleep 1
done
printf "proceeding\n"
@ -352,7 +405,7 @@ run() {
# termux-location
location=""
for locate_run in 1 2 3; do # run three times in case :p
notify "Running termux-location" "$locate_run"
notify "Running '%s'" "$LOCATION_CMD" "$locate_run"
if [ "$locate_run" -gt "1" ]; then
LOCATION_TIMEOUT=75 locate
@ -371,14 +424,20 @@ run() {
fi
done
if [ -n "$SPOW_PRIVATE" ]; then
cat /dev/null >"$SPOW_GPSLC_OUT"
cat /dev/null >"$SPOW_NETLC_OUT"
cat /dev/null >"$SPOW_LOCTN_OUT"
fi
time_locate_end="$(date +%s)"
time_locate=$((time_locate_end - time_locate_start))
time_surplus_start="$(date +%s)"
# surplus
printf "running surplus... "
notify "Running surplus -td $location"
printf "running '%s'... " "$SURPLUS_CMD"
notify "Running $SURPLUS_CMD $location"
if [ "$status" -eq 0 ]; then
if gensharetext "$location"; then
# surplus ran nominally
@ -402,7 +461,7 @@ run() {
notify "Waiting for the new hour..."
printf "waiting until the new hour...\n"
while [ "$(date +'%M')" -eq 59 ]; do
printf " $(date)\n"
printf " %s\n" "$(date)"
sleep 1
done
printf "proceeding\n"
@ -410,12 +469,13 @@ run() {
time_sendmsg_start="$(date +%s)"
# mdtest/send message
# send message
printf "sending message(s)... "
notify "Sending message(s)"
sent_type=0 # 0 for freshly made sharetext
# 0 for freshly made sharetext
# 1 for recycling a last location
# 2 for using fallback template
sent_type=0
bridge_failures=0
sharetext=""
send_error_notif=false
@ -436,9 +496,9 @@ run() {
else
# no last location, use fallback
sent_type=2
# shellcheck disable=SC2059
sharetext="$(printf "$LOCATION_FALLBACK" "$status" "$locate_run" "$sent_type")"
sent_type=2
printf "using fallback... \n"
fi
@ -451,6 +511,13 @@ run() {
send_error_notif=true
fi
# delete s+ logs
if [ -n "$SPOW_PRIVATE" ]; then
cat /dev/null >"$SPOW_SPLUS_OUT"
cat /dev/null >"$SPOW_SPLUS_ERR"
cat /dev/null >"$SPOW_MESSAGE"
fi
time_sendmsg_end="$(date +%s)"
time_sendmsg=$((time_sendmsg_end - time_sendmsg_start))
@ -475,7 +542,7 @@ run() {
if [ -z "$SPOW_TARGETS" ]; then
echo "s+ow: error: SPOW_TARGETS are not set"
exit 1
exit 3
fi
run

View file

@ -1,22 +0,0 @@
#!/bin/sh
set -e
# get packages
yes | pkg upgrade
yes | pkg install python cronie termux-api termux-services wget
# install pipx
pip install pipx
# install surplus
pipx install https://github.com/markjoshwel/surplus/releases/latest/download/surplus-latest-py3-none-any.whl
# install s+ow
mkdir -p ~/.local/bin/
curl https://raw.githubusercontent.com/markjoshwel/surplus-on-wheels/main/s+ow > ~/.local/bin/s+ow
chmod +x ~/.local/bin/s+ow
# setup path
echo "export PATH=\$PATH:\$HOME/.local/bin/" >> ~/.profile
printf "\ndone\n"

View file

@ -1,12 +0,0 @@
#!/bin/sh
# enable cron service and add to crontab
sv-enable crond
printf "59 * * * *\tSPOW_TARGETS=\"\" SPOW_CRON=y ~/.local/bin/s+ow\n" > s+ow.cron
crontab s+ow.cron
rm s+ow.cron
# open editor
crontab -e
printf "\ndone\n"

View file

@ -0,0 +1,26 @@
#!/bin/sh
SURPLUS_CMD_DEFAULT="surplus --debugp -tp"
SURPLUS_CMD=${SURPLUS_CMD:-$SURPLUS_CMD_DEFAULT}
# parse SURPLUS_CMD to see if "-p" or "--private" is in the args
set -f
# shellcheck disable=SC2086
set -- $SURPLUS_CMD
for arg; do
case "$arg" in
--private)
echo YAY
break
;;
--*)
;;
-*)
if echo "$arg" | grep -q "p"; then
echo YAY
break
fi
;;
esac
done
set +f