#!/bin/sh
#
# @package      hubzero-invokeapp
# @file         toolparams
# @author       Derrick Kearney <dsk@purdue.edu>
# @copyright    Copyright (c) 2013-2014 HUBzero Foundation, LLC.
# @license      http://www.gnu.org/licenses/lgpl-3.0.html LGPLv3
#
# Copyright (c) 2013-2014 HUBzero Foundation, LLC.
#
# This file is part of: The HUBzero(R) Platform for Scientific Collaboration
#
# The HUBzero(R) Platform for Scientific Collaboration (HUBzero) is free
# software: you can redistribute it and/or modify it under the terms of
# the GNU Lesser General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# HUBzero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# HUBzero is a registered trademark of HUBzero Foundation, LLC.
#
# ----------------------------------------------------------------------
#  TOOLPARAMS
#
#  Used to execute a tool within a HUBzero container, taking parameters
#  passed in via the URL.  These parameters are stored in a file.  The
#  name of that file is passed in via the TOOL_PARAMETERS environment
#  variable.
#
#    USAGE:
#    % toolparams templ ?-or templ ...? ?-default command?
#
#  where "templ" is a template string used to invoke the command.
#  For example:
#
#    toolparams 'firefox @@file(#1)'
#    toolparams 'firefox @@file(url)' -default firefox
#
#  Each target '@@file(name)' gets substituted with a parameter that
#  might have been passed into the tool invocation.  The '@@file' part
#  means that we're expecting a file name.  The ()'s contain the name
#  of the desired argument or its position (e.g., #2) on the invocation
#  line.
#
#  This command takes at least one template and tries to match all
#  required parameters.  If the first template doesn't match, then
#  the next is tried, and so forth.  If none of the templates match,
#  then an optional -default command is invoked instead.  If there
#  is no -default command, then this script pops up an error.
#
# ======================================================================
#  AUTHOR:  Michael McLennan, Purdue University
#  Copyright (c) 2004-2013  HUBzero Foundation, LLC
#
#  Bomb icon by Angel Corral Arias
#  http://www.softicons.com/free-icons/designers/angel-corral-arias
#  used under CreativeCommons 2.5 license
#  http://creativecommons.org/licenses/by-nc-nd/2.5/
#
#  See the file "license.terms" for information on usage and
#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# ======================================================================
# \
exec wish "$0" ${1+"$@"}
# wish executes the rest...

package require Img
set xicon [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAAA0AAAAMCAYAAAC5tzfZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdp
bj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6
eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0
MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJo
dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlw
dGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAv
IiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RS
ZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpD
cmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCIgeG1wTU06SW5zdGFu
Y2VJRD0ieG1wLmlpZDozRUI5QzRFOTc5NzYxMUUyOTkzRkExQTM2NTkxNTYzRCIgeG1wTU06RG9j
dW1lbnRJRD0ieG1wLmRpZDozRUI5QzRFQTc5NzYxMUUyOTkzRkExQTM2NTkxNTYzRCI+IDx4bXBN
TTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjNFQjlDNEU3Nzk3NjExRTI5
OTNGQTFBMzY1OTE1NjNEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjNFQjlDNEU4Nzk3NjEx
RTI5OTNGQTFBMzY1OTE1NjNEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4
bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+wQWuxwAAAINJREFUeNpi/P//PwOpgBGIBYHYGE18
DxJbCYox5FYB8X8knAYVBxn2Dkm8HNlkQTTJu1DT7yKJ7cbmVBc0296hsQVx+bEDTSMMhyIrYkLT
dBaLQe9xiMND6R0Om87g0rQbzQ/laBrL0TWgK4DF2xkc4mAGtjjCFqKgKBBkJCcZAQQYAIP5RJPC
I+hNAAAAAElFTkSuQmCC
}]

set bombicon [image create photo -data {
iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAg
AElEQVR4nO29aaxt2XHf96u11h7OcKc33Tf164nsJrtJkRKpyI5EuhlZjGTZEaKERCyKBixFMBAF
cCJDQQx/IJgYloPYiWQgAewgDmwTckJ9UOzElOUoMilFIsRBpCjOzWaPb3733fGcs/deQ+XD2vvc
+5rdzdfDe6TsLmDjnnvuOfvsXVWr6l//qnWu8Lq8EpHP/H3c/iX045B+/lHGz/wWLe+Ae09Ta4ue
ej8Ht3Mic4cv9N84+ej7sFf+MeO1FvOOd7D+6JeRkWP80GOsvfkNnLJXMJN1VhXkds7n7vQF/5si
j/89qs3zTP1zeHeKU/YyV8uC4+/5Udo2UEyEIllO+gXPuIZu59dZu3iN7txfYf5S570tK/3bKh99
H/aRR7Bn3khdllS2ZmQcRYRVucn1eJY1+wS77RSnEa3OsGlmXD/4CjdWvp+z4Qa7T32JmwBv+TDd
C33G6yHoJeSRxxg9+Kc4O1nhlIGSBnQb1RaVkzxgdqntCuvlcU7YmpIdgnGM3AWOh47aX6TZvEDV
XEY/9CK6fn0FvIgoyK+B+XO/yonyBGc8ON2jK47zSLrOZTeiTjVrcYuLss7IHrClEMVRdgXBJWb7
X+aKTtHxfUy1JX3tOtvv/Cv4o5/zeg74VpEn/0fW2oc49eMzZpd+lxvn3kUlK1yQRKGJ8+4MD/Is
n9WKUwZaUVaSpTANN9Map802W9LRjb+HNxVKwGG3rvL0hQ0qVYIIOnzY6wZ4ARk/QGUMa7rOPafe
w7OmI6aC83YNq54mFpwzNQ9KYkOENo14iwl83ThKAidSTcUqF5zio3LV7HFtnIiP/xbtyS8hcGgA
+x28z+9KUZCPRRZveASRmmOu4JStWLU32UlrPEqglkChFfeawFQt6yYx1USVwBnLhhFQxzEsIxe4
Eiccmz/J1vh7KDlP/Uv/B83wea/ngCPy7EcZrRznbL2NWezj6xLDMe7H8YCNOLOgSsd5Gw2qlg0M
K8zoRLEKQRLXGbFgjy9RATUxtNwwI0IyXPfXudLtM5/XLO79ANvwOgq6Rc6/n2b2DS6nkrZ8kGN6
jLMEMC07SRnFmk31VCpsUnOaGZaWaRJOJOEeDI/SckYimwJjWsBC2uWK22cuJXa8ju4XzIbPfD0E
9fKvP4Rb/TmmxTVs+3ssLMzL02yYmvspuA/DWYRVKTgukZNE1s0uUVtGZo5xczoNTIFjRrEqoCNq
03FVCw50xMS1bF/d5dqlnyb+eEZZ+noS7uUxSPMRE97BafkBJiFhoqfUlmQhMWZFKs5J5IROOSnb
CI516zFElJZO9klmTJGmnDUtNyJclynrxQ6XdUYTppw8e5Ly2L8iGGVX38v111dALx/+BPpDm/jV
U8xH++y7jrmNWCk4zpjzwMRsY0SZaGJVWmo7p5SWUmZU5oCpKKVaBEuHckVgn4KF3+AsUzZUESyV
W7Cz8ym2Vt+D/5O4Asp77334B8vJ6jtSCvcEH8xitntjZ2fr8a6ZfQr4JpBe7km/+FHKC46pmzD2
DVUNY1NyItScoWBDHaexbGhkKglnPU49hd2XkplxuhuFUxgKgjjGOuKN6lhJicZt86SJbGnLXurY
DgX7nM2f+yfGAD//1//W8eeeuvhTO9s7/1Xw/vxisU/XzKlGE4y5j4dHE2IMafv6pa8d7G7/Kq74
P5994gtPA/vDOa784++ZFA+NNurGnmF99bybX307KRbsxCpM465441PpzGh0cw/puuRixWxRSpCZ
JN8huk4Rj4kwUiO1RCnZF2E7wphETUuBqCFKS4fnphmzExPXpWA/bFDGGSXPopc/lyviPxEw9B/+
w4+d/O1PffJ/fvqJx3/iuae/WuxuXQFjGE9XqUcrWOtwzlFWY9Y2TmJdyWK+d7NdHPzGM49/8Vf/
2f/whq+f8Nd+uK6nfzrY2Tt137/R39gpvTeEgwVtgFGd0LpgugpSWV09sxpVQlutW1HTBVu2rnBd
Qdc5QxJz0SM7IDdRUoqs4RnRaMUiFcxTzXXp+Exa4SqWmUSeSw1bybPnK3a2r3Lx/r9M892+AuSx
xx6zX3nu2b916dmn/6Nvfv1z0rULTp29H2stimLEElPEuZLp6gb1eAXftmycOHessosP/MTbFj9m
rz67f3l773TTbFXPfepmVzn9HduGP4oz+2mR6No9dqsJJ0zNqrVmsz6XHtO0s3LsfDxjS8v0TJw4
Q3H8vCYj2hQjfF1Q2FWSWAxCEEPUkoihYUTCEBW2dME1GTNVy3lTgFYszDfZfeqfEuA7tAIeeeSR
8vLly6Ou60YxxrIoprWq2o4Wug4oocRsTCbmT/97f+EtRXXsV557+hsnn/z657PyjcVYS/CeEBqC
72gWM4xxGGvYOH6ad77lfn7oxKc5W1zmK7+/xXM7RequzP/mD/xI+JX3/6+ZIn4BkSc/RHX632FT
S84Yz4YK58yICykxFWXdWM5Ix8k05ZSZUWrESEdCUbFEdSwQrmrkoo55mn0+axw7nadIc55onua5
6Ts5liCMf4fLd80A58+fP3bQNG/VqI+I8DCYe0DOC5wQI6dUGacYTUoRVQURFXR274NvDmfvfXTt
0jPfkJQiRVnlv6viu4aUIgBtMyeliIjyzgcDf+nRBXsXb/KH1x9ib/oAX91LbG1d/tI3vvpH/3kI
zcdf6Bo/9CHMzz/KeNQwLqas2zGbqea+5FmxCbTiXmmZas1pPCcZc1YyDBU8EYPi2cLynLR8Iaz3
dVbHMyrsYbjcPsUXf/kvs/fYY5j3fJxwxw1w+vQ939+F7mdTjO8S6046a1fFuKqsaoqywrkSMQZN
ijEGMQbftnR+wWK2x5lz93Lmwpu5dvmZrGwF6xyL+T7G5PuLwRNjJPg573k48pNvnXPxazf4337X
cWVyivsf+VMYU3Di9AU+98nf+PrFp7700/P5/NMvdL0ffR/2B/8s1fqYNbfGWnSs9/zOZio4YTpS
NJyyFfeIME4FUxKVeAxz9khspYq5FjxrdnhKxpR4bKp4Lj7FH93cZfueX2AxfN6dyAHmxIkTm2Lt
u8H+NZ/S91f1lKoeUZQj6tGU0WQVYy2aEjF6UgzZAK5/rg40i5Kb1y4i4jh/3xsQW/DU1z/PaLxC
18xxriDGCJpIKeK7BW86Z/kP3r7gj3/zKv/s6ZKvhJK0vcXOJ3+Td/zgn0fE8Oj3/pmHdrau/PX5
fP4zwM7zL/6BDUwRMFqhaUZjV9gVT5sqVHd5TkdsWjBq0HTAtqk5l0o2JLKviW1dYU0Fb69zVe/j
ofRNfk/Pcl5uYNMZ1s//S64e/bzX1ACbm5v3R5WfROz7xdjvG41X3GRlg/F0nbIeUZY1gmCsBYQQ
OkQMXTNHezChKYIIeztbWOtYO36W++57A1cvXWQ8XgExIELXtQTfoikb4PjU87Nv9zz9xZt89OKE
JzohpYCmSPSer3/pk0zXjuFcyfn7Hv7Rrtn+kd3dg197/j288x/gP/P3YfM5Yv0gs8kOa26TtTjj
BoqK4gBlj2cFXBIKSWzFlqtSUYnQ0KJ6ijP6Zf4/PUnQ63yJiqJQ4jfehePXiK+5AU6dOf/TMaX/
uqxHb6yqSTlZ2eDYqfOMxivUoynWOpImgu9AFUVBIaWY/xYTIXSAovN9ZvvbrB3b5PT5B7hw333s
7lxne+sy84M9VlaP0XUtezvX8d6TUuS991zl2WeU//33PZdYBW37XJE/4/rlp3niK5/hngfewni6
Mipr94vs8i0GAOi7Vl7fh93/IOc0klxBm3aY6ZSVtOCZwjJKJSsy55lYEY1njzH3qjKTmzybzvNm
OYOTjqd1izn3Yqo/5MYbfvHW3vCrNYA5c+a+hyLxbwvmJ6YrG0xW1jl28jyrG6dwzlHVU8bTNQCC
b3vkko2AQIoR4xzRd0grpBgoypqqGnHy9AXOX3iQlemEf/eH3s3Nm9v84Sf/X9o2J9/142fY2bpE
s5jz0U+XnNRdvjp32MLjbO57RAXEoCny+Jc+ybkLD+OcY1zK9z949tg9T1y6+eyL3dz+X2Rdxhi7
z1a3z76c5LSZsQiBXXec9TQjiKMlsGNgkQIptlRiuSwLbsplrqfjtGGd+d/9YbY//AIV+qsxgDt9
7sIHFPlrVTF5y2iywonNC2ycOMdoskpVTyjKEhBcUWKMoSxrGEINgCqL2T5VPVmGoMXBHvu7Wxzf
vIfz9z/KPffeS1WXFNby7sf+DCl6Pv/p32F+sIeq4oqKSpWZn/BUqqjGHo0hryxRIIEkkgAoN64+
iTUJCOy0/iHgRQ3QBNr0OZ7295LW1pmUkcSUxeJJDqoa0QJN2+xGx3zhmU0SM7tDSMfwzRfYqx5m
6i8y/8OPsPdCyn/FBnj44YdXbm7v/23UfnA0XVmZrh7n7D0PsX78DOPpGpPpClVdI2Iw1rCYLVBN
SwjpnCP1sduYXEjFEOjaBaPJCiG0rG2c4vT5+5muTFAgopzaPMNjP/xn2dm+wpOPf5Wta5dwRYEm
pa4nxNjiUbCGGCDGhFjBCEQSSZXFbBdnI5oCqjJ7qfs8Ot127UNYeRcp/DHP8TDTdEATx+A6GqPo
vrKoI4HjmHiT5omvMFuzLD6yhf/wx1+cm3rZBtjc3Dx1c3f+37ly9MHxyppdXTvBPQ+8lfVjm1Sj
Kc4VVPWI1dVVxtMxvvVMp1MUMCKEEDHGEEOgWTSkyZSqqokxMJ/NmO3vIGJoFjPqsmQyHuN9QHGI
KhvHT/K+n/pP+f3f/dd87g8+wTPf/CpiLCogIvncvkNEMQIq/YyaAU2QwoJmfp2u9der6uQXOESE
LynpQXTxNZ45+fssDh6h9Ns0ybOz57CrC2RfacsFbblCcfObzN/5Dwgc6f2+mLwsOvr++++/N6r9
e0U1+k+mqxt2df0kFx54KxsnzrKydozReMJoMqYqS8qqpK7KJU9TlSWucBRFQVFYXOGwzjGejLHG
9MkyZY8GVBNdO+P8hftzKFPFh0SMkaSGjWOnWFk7jnEl+7s3IEV8OyeGFmMEIaExohqBhBGoq4Ky
iMz2b0ZrR7906crWx29HSQB/59fx//3H6Hgf8t5n6a4bwqlLzObrcPOzLB56I+3kg7S/9Aj+lyF8
4hO3d97bLsTOnTt3PkTzkaIev3syXZfJygb3PPAWTp65l6oas7q2xngyYjIZY42lrApAMcaimtCk
xHR4TSlGkiqalBADbdvhO4/3nv29PWYHu9y8fon7H3yAd/7AD2Kt6cOWEkJkvmjY3z/gyW88zmzv
Ktcufp2LT30ZjTMWs3185/PrY8AYcE4REj4EQrDP3H//m3+qnq7/wcc//vFwuzp4IVEQuU0jvpDc
1gpYPX/+mEn275T1+C8cKv9RLjzwKBvHjrN+bJ21tRVGo5qiKKiqEucszmWPL8sCZy2uyM+JEYyx
FIXDFRYjFmMMSRPeB6y1hBCxtmTr+rV+payQktJ2nv29Aw5mM65eucLB3i6Xn32C2WyfzTNnOXb8
OEaEwiXqCqrK4GyClAg+0rSKhrA2m++7/Zn/7Z2dnebba+DF5cOv5s3cngHcxmTtw2U1/tnJyoYd
T9c5fvIcZy88zHR1jenKlNWVKXVdZ7RSuBxiXD6MMRgRxAjWWEQkJ2eTYzYISRUjgrGG8WiEsQZj
HUVZogpPPv4VDg52KKoJIUQOZjNu3tji5tZ1bl6/xGx/i72bV7j83JNcee4Z9nd3CD7ifcg/u0TX
RmKMGFEKB953b/PdXDZOxN/b2+NVrYJXI9/WAJtnzv1VMcXfmKysl9O146ysbHD2vjexcfwU09VV
VldXcK6grHKsd85RFo7SOay1WGtwzmQG00h+zkg2imTjRNWcJ61FNYcYVUUEnCtJSbl+9TIXn3kc
V4yYz+fcvHGN7a3LzPa2me3dYHGwQ9fO6JoD2mZG18zxXdfzRCEzZqJM6gwGNCmq8W2hsxfnjX7+
Luj6BeUlDXDmzD3vTmp+ZbK6sTZd2WA0XmHt+CYXHngTa+vrrK5MqaqSqi5zuHGWwlms7T2/V74Y
04edfjWIIICzButsv2qK/KF9Voohx3tFEbHEGNjf2eaJr36eZjHHdy27N6+yvXWJvZ1rLOa7NPNd
YtegMSAkjCiGhJBwFiY1VKXBGukJwFSlxJvqkt9adNy4w7p+QXlRGLq2dmEjCb9Qj6en6tGUsh5T
ViM2z1xgZWWVyWRCPaqpqiLHcptDjrUG0ytbjBzO4amSFBDFmOzdqkpMCSEjoBgiwUeMGKq6BHKt
MJ6MmR/UTFfXgcSNK08Tuoa2zYzpYraLbw+IoUOTR4gYo9hMG1E6GFVCXWXjtz4Ro5IKSKoPK/a/
hfgBeOER8jspL2qAesx/bG3xY3U9laoek48JqxunKMsyJ9rCZe/tvT97fQ4zImBMdudM78sS9aSU
QCBGhaTZ01UxvcZiSoSYq2VrLW2bOLF5hqKvF3y3wBcWY8FKwEhDKMEvIPiM/0snTGqhcIIzirNg
DIQYSRGiFVSF5JTYxf/w+Grxc1t7/n+6W4of5AVD0MmT951Wwq+PxqvT8XSN0WSVejTlxOnznL/3
ASbTCXVdUlUFZVFkzzcGsZLDyjLOHwk50seWfkmo6tIwRsjG6fmhGBNC7g+EEDBi6LoOTRHvO1Lw
RJ+nvEOIlOWIqqqpqorJeMRkXLO2UrC64hiPHZMxVKX0n5cdI6VcnCqgCROTPjqtq/9r1sbtu6H4
QV5oNNFFXXzYlfWxwfNdUeOKkvF0bQklB4QjQo9yWIYeIznJ5t/7QziSfHtUZGUJoocqVgBrctIu
nMX1idkYQ9csiMETgscWJdYWlNUIax3WlVT1iNFkwmQ6ZrpaU9U1ReEAR4z9ByXtkZBgDf11gRE9
m9R/ECi+owY4vrn5DmOKP1/VY4qqxrqSoigpqprJdJXCFThrsqL7Q47QAMZkpSKHNZ4wJN4jhhl+
N5ITuM3RUESwzlHVFTElXOEO0ZN1pKS4sqIeTcBkuGqtQ4g4lxUqYhARylIoCwUUZ6Bw4ByHCVqg
KvNzhaNA9P3HRpy+W8qHbzWAEzU/XpTl6aKsKMvcRDHWIsZSj0ZZ0dbgbB92em+WpVJ7hSOwDD/Z
DFnBw0MByfxMjIkQA6pK4RzGwGK+wIfAbLag6zyL+Zyu8zjn0ARd2yEIVVUjRnCuBIqcP4JnMU/M
59C2ORRaJ5SFUJWWuhSqAsr+cLY3jtE3m7r4sbuo/1sNcOLEiZOC+fGiqk3hqj6ZGlxRULiSsqqw
1jAUTxmryy2HMWap6GFl0Bth+N0eMRo9GoL8XkVJMWGtxVlHPapJMRKCz0a2BdY5yrLKxFsMgCFh
SD31IaZAqeg6Q9dJn3dMH/IUa6EeZaVDDkUDmaAh/gJQf0cMIM59L8a8zdoC6wqMK3BlhRjTtwtz
4hqCS1b6gNX7Z3tl5tcNPweqRPoEnF+nSY+QKRkdBR9Immh9h/c+5wTnqOoRrijRlHmlznf4rqPr
OlKf1FNM5Eu0WJcV731iMe+Lu5TrAefA9Ncs/fU4A7mHkx5eX7E/egd1fovcYoAU+RnnCuusy57E
4D1grcP7XLGrZmXFlPG0Jgat9qpOPaOZn4OMQCCvmsEcOScOMDQ/ps8NVVn23JJjNBrlyjUlYvCI
sb3HDufNfHNKkDQjnGbREb3HmN6wAUIwWGP6682OkQvCfApr+5Yz/NzzdXOnZPkh586dO66q/75z
5dLzrSv6JroDhGYxp2+zZgX2YWgwyKDI5d+AlCCmdKvi+xcJLJPygKZijITY8zghLllNY2zf4LHE
4HvIatCUaJoFzWJOShBCIMZEjJCS0PsMqhCC0nWxzzuCs4Lt6wNrDxGRxviWk6vVA3fVAG0b3iti
p8ZajOSnrS0YjVdwrsQVJV3XEWMkhkiMKSt9aYB8RE254u1DzNAYzyFm+HuugGPIq6jtstKOnmuo
lOkLODF5Kapmzqgoyh4AZJq66/JsUEoJ39MYYksES0yGEISUS3Fs3yUbHMaaQ1xgDBjDepfC991V
A8QYf8y6ok9igqZI8C3N4gBXZAO0TUsIASXH1JRSb4jDCjfGPjQtw48uPX5YLaiSYm+EGFFNS8MO
MS/GRNO0HOwfcLC3x2IxY36wR9fOaecHLOb7hOABwUhmWbuuJSbwPhCT4kMkRxuTYwsO3+UKPCWI
/eowveIHgCawIuhbuQujmw5gc3NzsujC99XWZuKMjHSyYgLN4gBrHfV4hf29vUwZi+CDxZhEkDzm
YjkanoR0pBZAlTiEqqh9mOhziLJstHR9Yg0h0jYti/mCplnQNYtlg0WHXJIibZuLs5RySEopYawj
xZBfL4qIksiZyTnp64TcpAk+c1RDCxN60JZ46ARMbxwZb79jBgghXFBlVYzN/qdxmU6HIirFSIqB
2WxG2+a2n/GBaM0tVEPPJqC5IsJAH55S33Y89HwfIqEn4Lz3+feYCDFlBCS5ACvKkq6Z03ULurZB
NZE09qOKivQFGaoYMSQf8pB+zydhBLGgSPZ+EkpCTE8MkusR6TEHBlLU+9oxU+Z3wQBNCGcLW42W
ZAkmx/B+gEpTQjXRNnOKomRnZ5eyKilgiYxSSpmKdpk6EOjjNstlkVSPhK3D9qIPga7zhB7vxxD6
PJMN08znzGf7NPN9unZBSoEUQ67lJI+9oErwIYelmHAut0RFE0k9MSo+eXCZKY1B6bwSIgNQOwTL
GbGdi5HRnVT+0gBWzWkRqUVyRZI9LFPBwXu877CupaoneN8xn804OBgDgrMZErrCLg0RrT0stmCJ
0w+TdeqVHbPiQ8h94abDB0/wIYefZk4zP6BdLIihy23MsqJpAsY4XB4SxHctSROqgmJICrFpsHhE
WywBKx5rIiHo8n35eiH0sFSH4ZEMbTcL1bq9GwYwxhwXqJZQAEVjho4xdn2MjXTdAmMd8/kBOzcL
iqJAizLfiCasTbmdGGLu/fZIAwZEQ18sZe8fmvAhBHzIM6G+y16ck3KO49Y5XFESeiNY62jafULX
4oPHdw1NM4MUiaGB2EEKJEJGGaYPpckQSbk2iGSE1V9fHELQkipRV42qswdd++U7boCU0opxFDnx
Zg/Vfv5+WMopBnzXsrp+EmMs8/kBe3s1a2urKEqMsY/XDmsscFi0gRBTJMXUd7oiMeZpiIzbM6Jq
2zwbmlLC9zOkxhgWs126tqFdzOi6hmZxQNc1OS+0i2WV7rs2F2opYEXJKzrnmiSKM4eJvyhyDZGd
op8Z6g89DJl3nJjrk7A3rqjy+MgQekKHsSbzMF2eYhZjaBYHlGlMPRozOzhAU2IynVAUBdaafqoh
tyMHBjTD2uz1SROd90vYGkLIsDEEFosFwXvms326rsG3TYabviPGwOxgB9+1eN8Qgwe0P7cuKYqc
e/KYe0geUshNDwOkvkuGIFGJKXu+ArqkxQ+J3K7r7vg23mVHbEi2qT80JVLMDRBXVLieBmjm+6QQ
erQEvutIKTEajbCFQ0SoyxKTTG6s9L0BHwP0hViMEUEIPtB5j+86msWCtl2gCl3XYKzLBJwYvG+Z
7+/kcXRNvbIzRE4xX2dKsS+tLTEERJUUErZXaojac9VDDaK9AbMR6O+nbxlkiXepDsgVbfb+rFhd
3mhKnhhzEwQRuqLJ4Sl0TNIG1hX4rqUej1ldXetHA0NP0OXqxjmHwJEqOmKdzagopsM2peYJ6uh9
H0462naejTqa0llLszjokVTsz5dXR4gBjTFPQYSOFFskeaJErCQK27NUKdshDuxsvwJCYEmd9LXi
4RD/nTaAcQbpia2kCaNDnA5IMPiuQfrk57tsAGcLFrM9rC365zt82zKerOSxQ5unI3Ji9X3jJnM9
KcYlrTGsoGVM75qMamKkbWY08xneN3TtnBg9XbPA+/z3GD0x5fA11CkxBmJf7OX+RO4zJxRSyCWv
Hgn0vdeHmFfCYICkYK1N+DtrhgxDxbYphaQpmhQjSQySMgWdYiTEgHQLhmTMOMNVGwpi8BRFRQgd
IbQ0ixllNWIyWSGRsMYt8bWRzFQOlWzXNH3YSXTNgrad0yz2CT433mPwtM0c24cj3za94sNyZ8yS
ZU2xN0xGUUJewb3+IQ1wuO83iy5hZ9JD7096uAKKUXlAc3vDu6/KAN7761ZpYozj6D3GOiTluJpS
IgVPEMEYh6clHkTKMjdKrCtynnCOEFqsLWgWM5rFjGo0xrmSoigQEZquZdixgrAcnGoX82XdYU0B
Lm8vGnbTDIkYHfaU5aHbFEOuJ3r0E0NA+0nwGNJhVzQlkiSsyRSIPcL7DAZA8s/hUMDPFt+8o9pn
WQfYm6qpU01j1cy3iJBvkJy4hrwQY0lR1ljraBfzJUYXqXuuJntl8C3N/ICiqinKejmJ4FyRm+sp
9rRyolkc5Oq337DXtpn7CaEj9OEGcqsxBN8bxy9zwHJV9Nee4uEGkJQAycy/Ru0hfr75W3pI5BAU
Y4+GVHaD0Zf8zs/XzADOyWXvY5MhaD4kJZKJaMzLVl3uIPXoHshNGhsdMUWC7xBjcK5AxBCtzYks
eto+caqm3EA3Jk9Np0jbLHroG4h9URWD77cztbk/0Ic3lCXJFmN+fYp+Od6SlWowlp5lzTNGWDJy
6mFxIh3CzSPNupgg9uEnwWXT3ubmgVdrgLqun+66/YMYfb9hLmZli/R7rXITRERwqvgehZRlTbLF
skFiXU7IIjZ3mJyja+YYaw5XUM/z5Km3tERbiCHGbIDQtT29EA4hJvSrJBxRfsjkXu/92TUOe9XD
1N0wZxQ1YSQ/t+xRH1HG0fiv8HQDL7mD5jUzwLVr167V9ejpGMIbkgukaPuLFFJ/icbYfhdjflNK
SpcS1hWZ9TSGEDqKokJRjHGEbtiSqsvJuOi7XDmHkI28DCG+7xennp6OvRfHfmA30yHRe4Lv8us4
bILmCj47jko/bqGJ2G99zR23nCGMHDFAjrB9C7VHQfm834Db+wLuV20AQI1xvxVZoLUAAAnXSURB
VJ1i+OEYIyIxV77xEIKJCCnJEoPnprcsN9xFnzJf05Mpkf7GrckUceoV1sf+wasHpnXw5rSsPyKx
Zz0HNBZ7nJ/HWTJTa8T05K1ipN9BE0NvvIFW4ZbYr3JohHxvt6BSVGkR8xVId3xWdFkJl+XoX8wX
e38zxiDWFsSYE6SJFvJmR4xRQhi6XDkOC8MoSlae+G5gd/NXCYTcXcujgMuGMdAbr/f0rNS0hJgI
aD8rtFRkPAxFGUkZUuyWYSpPRkSGXDbIMAaZ+pF37Y9bVsDRKljZdcZ8/hV879MrN8DOzrUvVHX9
xRTDW0Po+kGn7Pkx9Km3rya9b5czQyxDlMHEAfrl7Cb9dzkMvYVhPgjkEMejmd8fCj+kh6QpGy4O
eD9X60M4y0xrODQYLHvQwzTG4WOO/MxKT/2qEF1e7jIMCXJxEcIX7pDOb5FbyKa6qiYxpvdm5eZQ
slSYan+j2V2U1Cs2I5jBo2McOhy6bI+lmJZdttwT7vsNfXsx7yPTJRmI5sSaev5pMEKKnuD9Mqzo
EvYe9fzD1TAofni8lOHy+odHH6uCLcr/Jcb4m3dS8YPcQjZVVfUgyCetdSdtUeTv3zGZUhCTY7mx
mXAzLs9kmn5oy9qiX9J2iUIY+CD6WA/kZd2HrD7+59dktnTZiRsQU8wNmiFEDX9bJu9w66zSkLQH
GnxYCd/25ofnhKYejR+Yz+eXXxMNfxu5ZQXEGH1RuDer6vfIMCbAUL4PtWPvWfkP2fOGef8QiCkX
cZriLV59SPBp7ufGkAu8/vcl8vFhSf5pH5aysXrSXvLrUgiHYY3B07+Vt3kx5b+YGGs/0nXdR162
Jl+hPJ/v7owpypTiexFT5Rsbhqp0ibXzPM6tb83ds7wJmyMJL6VDsJij2bfuFQgh9Ht6h88Y8k4f
avrYH6Jfopxhk4f0s6gDDH3+Nb08kX3V9J8Bd8X74QV2yEwm9W8cHBx8PQX/TllOHOSpCLEs46vp
bzbPEeXukrEu4/ulUvqxIz00QIoRY91h4aSalS9CCiEn1h52pv6ra8zQOuyNkZU/JPLcmEkph7LD
1fZylQ/GyMdS0m+8Ik2+QvmWjk/TNG1RFFdTSu/L955j/4A88n3JUoHLx8KtybRPkKlvN6LaF1D9
xFz//RCZSj6seOPycejPcxiGbpV8HhHp4346ck2vSLaNMf+Nqv7xqznJy5UX6/jYsiz/kap+wNqi
3x9g+jkdt+ReMv7PcaQoyuyVukx9S7wPHCpHcktQObJfjDzRkH/eiuXFmNyBE+kp43jk/ekI2hmo
jVth5+2KtfbXYow/zV3eqPeiLbeqqt4QQvpX1pr7s/KHzRhmuQcAstebWzZgDwQ8tyAU6VfIIOlI
cTYUTUNuGAaugCWzeVg56/I9Q7gZbuXW31+GEkSujUaj753P55de9ptfpbxo0znGuO+cJaX4bqCQ
pScfep4sUY72RVPoQ0iuCzLEPMLRaPb2Zd956O8y0MQ5HwyefLTCXZJ2t8DXw2t6Kbj5bWTfWvtX
u677vVfy5lcrL9X1TymlL9uieEeK8Y3Sf7XA4ZIZNljkwupooSa98lOKS9pAgNjH9aXyY18J91BW
+ymJQ8UPifpwWmP4fXkVS3bjFSk/GWP+SUrpl+HWf65zt+Tbdv2n09Mn5/Mbvwv68LAhb3jbUEBJ
P5085Am4VSFL2AmHaCgdbtDm6F97dHPo0XILvcCR97xCpR+Vz9V1/ZNN0zz1ak/0SuXbzr103cHc
ueozKumHUD0xPD/s94IB1+uSRrglph9V0jJ8PR8qHnl8RNmHmz4OibxXmmSfLyLytaIofqbrujs6
+fbt5LYGj1IKlwrnno0x/ggwHqahX8jLD+MxfWjisJBj2LQBPfeIHn1NX0wd3XkzyIs9fiUiIk+r
6l9KKf3BqzrRayC3O/mlMcavTSaTi977x4DRoKBhJ8stdMMtCrz1d5FvTZbLavklcPwLGf0VyiVb
lv+lxvj/vNoTvRbyskbvvPd/XJbl4zHG7wWODwo5GkoO5TBmD0YZ0M3hwdL7v7XQ6s9yy+tffdix
1v4XMYR//qIf+CdAjHPuXcaYb4iIHh5Gjbn1EJFveW44rLVqrV2+7vkHsPz5Whwi8ingbXdXVXdQ
RqPRORH5bfLXDi4V9moOXiNlP+9oROQ36rq+727p5m7KhjHmb4jIZb69B95NpQ/HE8aYXwRW7rgm
voNSlmX5Vmvtx7izynx5Icfa/7soirfzb9H/SquLov5ZkK8ADd8ZxS9E5AtlWf5FbqPI/G6QV+Id
Qu4pOvK8RA3rY6bro2TcN1fq6ScScVugBD35Cj/jZV6RzK0rPlu4+p+Uk9W/a9n4gvephnEJaxZm
/ZcRANlQ3zXycrzEkpVewGrJpCrr0pWFNXWKUlkjtTXUSVxtEnUSf0pDe3+7mD3mu+btKaXJa33x
xphZWY4+6+rx7zhTPylFcc1oaJLSxKRtTNqESCM2tk0XW2aNh72OzPsE7s4WgJeU2zGAAQo4UbLS
luNqvSp8W0dramuq2hgdJdyoEB1HdCyYsYiOBMYYGZNkkjRsdO3sTX4xf4MP3Yam5FTVgL4MBxAV
kSQioSirrbKePF5UK181Irugc9C5wlxJc1VZWGSuGucJFinJIqa2sbFsvJ83c9u27NctXB+M8R1b
Fbfz5d19yAkWHdsqBheKwjlDYUTKJJSGWCVMZbAVaC2YEeiIJGPQqcC4cPWuGbvHC41ryfuNlMI4
xlCllByoVVVBVTI1LTAgJSRiTHDWNWLczLpix1q3a4zdF+KKYmLeDo4KmsAmEclbNMRFS4xRJBTG
hWCiS6ZwU2/DAZ0lr+r8XfbfIbkdA0QgwI5wsE43KSWWIGJVCJoCyRQuSdSIhCjYkCR1gmkRbQUW
KubAOLODMVOjaZJMMVFNoyJpraRSNRWoOhSTx3TJX/QsEhDjjTEtSGusnYvKzFgzE2NnCjODzBQW
oHNRmqQsDGGOlYWGMO+SNtGxoKEJThvnU3tw0LWw3fFdEIZeLlKw5C+1czkP1EVd2qqMtkzOVNZI
lQyVTdRG8mMjUmmiFEclSUpUChFKFS1E1YE4FbGgFmUYGlT6DqQoATSoiBdVr2q8iHZJ6cRop0or
qp0qTUraGUMTE22MqTNRG+9TuzChY9Z2sOv5Lor/8OqgmjlyWDjhWPOOOHLjFFyqikJTdGXhCk3O
ORedJuucNU5VraqxVtWoVYtao4f5YDl8JCIJoopIjDEmERPFmBBCjGJiCMEGMdEbb0NrfDCt98a4
cOAaz46LcGNQdDpyfFfJncDKRxU5HOZ5P48+D6wP8yvPux7RfGwPihsaA8PP5z8ekul3FdR8XV6X
1+V1+S6V/x/xfqgoLz3uJQAAAABJRU5ErkJggg==
}]

option add *side*background #bbb startupFile
option add *Text.font {Helvetica -14} startupFile
option add *Text.borderWidth 0 startupFile
option add *warn.close.relief flat startupFile
option add *warn.close.overRelief raised startupFile

set Wait 0  ;# non-zero => wait to exit (for warnings)
set ParamTypes {file directory}

# ----------------------------------------------------------------------
#  MAIN SCREEN -- used to display major failures
# ----------------------------------------------------------------------
wm title . "Oops! Error"
wm withdraw .

frame .cntls
pack .cntls -side bottom -fill x
frame .cntls.div -height 1 -borderwidth 0 -background black
pack .cntls.div -fill x
button .cntls.ok -text "OK" -default active -command {exit 1}
pack .cntls.ok -padx 10 -pady 10

frame .side
pack .side -side left -fill y
label .side.icon -image $bombicon
pack .side.icon -side top -padx 10 -pady 10

frame .info -width 4i -height 1i
pack .info -expand yes -fill both -padx 10 -pady {10 0}
pack propagate .info off
text .info.message -font {Helvetica -14} -wrap none
pack .info.message -expand yes -fill both

bind .info <Map> {text_message_size %W}

.info.message tag configure heading -font {Helvetica -18 bold} -spacing1 6 -spacing3 10
.info.message tag configure first -spacing1 6
.info.message tag configure code -font {Courier -14} -lmargin1 10
.info.message tag configure codebold -font {Courier -14 bold} -lmargin1 10

proc fail {message} {
    text_message .info.message $message
    update idletasks

    set x0 [expr {([winfo screenwidth .]-[winfo reqwidth .])/2}]
    set y0 [expr {([winfo screenheight .]-[winfo reqheight .])/2}]
    wm geometry . +$x0+$y0

    wm withdraw .warn
    wm deiconify .
    raise .
    focus .cntls.ok

    vwait forever
}

# insert error text into a text widget (with appropriate styles)
proc text_message {win mesg {how -overwrite}} {
    puts stderr "$mesg"

    $win configure -state normal
    if {$how eq "-overwrite"} {
        $win delete 1.0 end
    }

    set first 1
    foreach line [split $mesg \n] {
        if {[regexp {== *(.+) *==} $line match title]} {
            # insert a line of text with the "heading" style
            $win insert end "$title\n" heading
        } elseif {[regexp {^!!} $line]} {
            # insert a line of text with the "code" style
            # make @@type(name) parts bold
            $win insert end " " code

            set line [string range $line 2 end]
            while {[regexp -indices {@@([a-zA-Z]+)\(([^)]+)\)} $line param type name]} {
                foreach {s0 s1} $param break
                set pre [string range $line 0 [expr {$s0-1}]]
                $win insert end $pre code
                set param [string range $line $s0 $s1]
                $win insert end $param codebold
                set line [string range $line [expr {$s1+1}] end]
            }
            if {[string length $line] > 0} {
                $win insert end $line code
            }
            $win insert end "\n" code
        } else {
            # insert a normal line of text
            if {$first} {
                $win insert end "$line\n" first
            } else {
                $win insert end "$line\n"
            }
        }
        set first 0
    }
    $win configure -state disabled

    # check the size on next configure for parent container
    after idle [list text_message_size [winfo parent $win]]
}

# adjust the size of the frame containing the text info area
proc text_message_size {win} {
    update
    set changed 0

    foreach {x0 x1} [$win.message xview] break
    if {$x1-$x0 > 0 && $x1-$x0 < 1 && [winfo ismapped $win]} {
        set neww [expr {[winfo width $win.message]/($x1-$x0)}]
        if {$neww > [winfo screenwidth $win]} {
            set neww [expr {[winfo screenwidth $win]-200}]
        }
        $win configure -width $neww
        set changed 1
    }

    foreach {y0 y1} [$win.message yview] break
    if {$y1-$y0 > 0 && $y1-$y0 < 1 && [winfo ismapped $win]} {
        set newh [expr {[winfo height $win.message]/($y1-$y0)}]
        if {$newh > [winfo screenheight $win]} {
            set newh [expr {[winfo screenheight $win]-50}]
        }
        $win configure -height $newh
        set changed 1
    }
    if {$changed} {
        after idle [list text_message_size $win]
    }
}

# ----------------------------------------------------------------------
#  POPUP WARNINGS -- used to display warnings down in the corner
# ----------------------------------------------------------------------
toplevel .warn -borderwidth 2 -relief solid
wm overrideredirect .warn on
wm withdraw .warn

frame .warn.side
pack .warn.side -side left -fill y
label .warn.side.icon -image $bombicon
pack .warn.side.icon -side top -padx 10 -pady 10

frame .warn.info -width 2i -height 0.5i
pack .warn.info -expand yes -fill both -padx 10 -pady {10 0}
pack propagate .warn.info off
text .warn.info.message -font {Helvetica -12} -wrap none
pack .warn.info.message -expand yes -fill both

bind .warn.info <Map> {text_message_size %W}
bind .warn.info.message <Control-ButtonPress-1> {text_message_size [winfo parent %W]}

.warn.info.message tag configure heading -font {Helvetica -14 bold} -spacing1 6 -spacing3 10
.warn.info.message tag configure first -spacing1 6
.warn.info.message tag configure code -font {Courier -12} -spacing1 2 -lmargin1 10
.warn.info.message tag configure codebold -font {Courier -12 bold} -lmargin1 10

button .warn.close -image $xicon -command {wm withdraw .warn; set Wait 0}
place .warn.close -relx 1 -rely 0 -anchor ne

proc warn {message} {
    global Wait

    # always start with a "Warning" heading
    set info [.warn.info.message get 1.0 end-1char]
    if {$info eq ""} {
        text_message .warn.info.message "== Warning =="
    }

    text_message .warn.info.message $message -append
    update idletasks

    # put this popup in the lower-right corner
    wm geometry .warn -0-0

    wm deiconify .warn
    raise .warn

    # don't exit the program until the popup is dismissed
    set Wait 1
}

# ----------------------------------------------------------------------
#  Load info from a parameter definition file
# ----------------------------------------------------------------------
set Params(all) ""
set Params(orig) ""

if {[info exists env(TOOL_PARAMETERS)]} {
    # if we can't find the file, wait a little
    set ntries 25
    while {$ntries > 0 && ![file exists $env(TOOL_PARAMETERS)]} {
        after 200
        incr ntries -1
    }

    if {![file exists $env(TOOL_PARAMETERS)]} {
        # still no file after all that? then bail out!
        fail "== Tool Invocation Error ==\nCan't read tool parameters in file \"$env(TOOL_PARAMETERS)\"\nFile not found."

    } elseif {[catch {
        # read the file and parse the contents
        set fid [open $env(TOOL_PARAMETERS) r]
        set info [read $fid]
        close $fid
    } result] != 0} {
        fail "== Tool Invocation Error ==\nCan't read tool parameters in file \"$env(TOOL_PARAMETERS)\"\n$result"

    } else {
        # parse the contents of the tool parameter file
        set num 1
        foreach line [split $info \n] {
            set line [string trim $line]
            if {$line eq "" || [regexp {^#} $line]} {
                continue
            }

            if {[regexp {^([a-zA-Z]+)(\([^)]+\))?\:(.*)} $line match type name value]} {
                if {$name ne ""} {
                    lappend Params(orig) "$type$name:$value"
                } else {
                    lappend Params(orig) "${type}(#$num):$value"
                }

                if {[lsearch $ParamTypes $type] < 0} {
                    fail "== Tool Invocation Error ==\nInvalid parameter \"$type$name\"\nType should be one of the following:\n!![join $ParamTypes {, }]"
                }

                switch -- $type {
                    file {
                        if {![file readable $value]} {
                            warn "File not readable:\n!!$value"
                            set last [lindex $Params(orig) end]
                            set Params(orig) [lreplace $Params(orig) end end "$last (ignored)"]
                            continue
                        } elseif {[file isdirectory $value]} {
                            warn "File is not a plain file:\n!!$value"
                            set last [lindex $Params(orig) end]
                            set Params(orig) [lreplace $Params(orig) end end "$last (ignored)"]
                            continue
                        }
                    }
                    directory {
                        if {![file readable $value]} {
                            warn "Directory not readable:\n!!$value"
                            set last [lindex $Params(orig) end]
                            set Params(orig) [lreplace $Params(orig) end end "$last (ignored)"]
                            continue
                        } elseif {![file isdirectory $value]} {
                            warn "Not a directory:\n!!$value"
                            set last [lindex $Params(orig) end]
                            set Params(orig) [lreplace $Params(orig) end end "$last (ignored)"]
                            continue
                        }
                    }
                }

                set Params($num-type) $type
                set Params($num-value) $value
                lappend Params(all) $num

                if {$name ne ""} {
                    # name is like "(foo)" -- get rid of ()'s
                    set name [string range $name 1 end-1]
                    set Params($name>num) $num
                    set Params($num>name) $name
                }
                incr num
            }
        }
    }
}

# ----------------------------------------------------------------------
#  Parse command line args...
# ----------------------------------------------------------------------
set default ""

if {$argc == 0} {
    fail "== Tool Invocation Error ==\n\nUsage:\n!!toolparam command ?-or command ...? ?-default command?"
}
set templates [list [lindex $argv 0]]
set argv [lrange $argv 1 end]

while {[llength $argv] > 0} {
    set arg [lindex $argv 0]
    set argv [lrange $argv 1 end]

    switch -- $arg {
        -or {
            if {[llength $argv] == 0} {
                fail "== Tool Invocation Error ==\nMissing value for -or option\n\nShould be:\n!!toolparam command ?-or command ...? ?-default command?"
            }
            lappend templates [lindex $argv 0]
            set argv [lrange $argv 1 end]
        }
        -default {
            if {[llength $argv] == 0} {
                fail "== Tool Invocation Error ==\nMissing value for -default option\n\nShould be:\n!!toolparam command ?-or command ...? ?-default command?"
            }
            set default [lindex $argv 0]
            set argv [lrange $argv 1 end]
        }
        default {
            fail "== Tool Invocation Error ==\nBad option \"$arg\"\n\nShould be:\n!!toolparam command ?-or command ...? ?-default command?"
        }
    }
}

#
# Scan through all templates and look for a match.  Substitute as
# many parameters as we can.  If we find outright errors in the
# template (e.g., wrong type for a parameter), then we must complain
# and fail.
#
# If we find a matching template, then check for other subtle errors.
# If a template uses only 2 of 3 parameters (extra parameters left
# over), then warn about that.  Or if there are parameters but no
# matching templates, warn about that and use the default command.
#
set cmd ""
if {[llength $Params(all)] > 0} {
    foreach str $templates {
        set orig $str
        set match 1
        set paramsLeftOver $Params(all)

        # look for any @@type(name) fields in the command string
        while {[regexp {@@([a-zA-Z]+)\(([^)]+)\)} $str param type name]} {
            if {$type ne "" && [lsearch $ParamTypes $type] < 0} {
                fail "== Tool Invocation Error==\nError in argument \"$param\"\nBad parameter type \"$type\"\n\nShould be one of:\n!![join $ParamTypes {, }]"
            }

            # name can be something like "#2" or "foo"
            set num 0
            if {[regexp {^#} $name]} {
                set num [string range $name 1 end]
                if {![string is integer -strict $num] || $num <= 0} {
                    fail "== Tool Invocation Error ==\nError in argument \"$param\"\nBad parameter identifier \"$name\"\nShould be #N or parameter name"
                }
            } elseif {[info exists Params($name>num)]} {
                set num $Params($name>num)
            }

            # see if the requested parameter has been specified
            if {![info exists Params($num-type)]} {
                # this parameter set doesn't have the specified param
                set match 0
                break
            } elseif {$type ne "" && $Params($num-type) ne $type} {
                # parameter type doesn't match what was requested
                set match 0
                break
            }

            # substitute the parameter value into the template
            set str [string map [list $param $Params($num-value)] $str]

            # mark this parameter off the list
            set i [lsearch $paramsLeftOver $num]
            if {$i >= 0} {
                set paramsLeftOver [lreplace $paramsLeftOver $i $i]
            }
        }

        if {$match} {
            # found a template command that works!
            set cmd $str

            # if there are any parameters left over, warn about this
            if {[llength $paramsLeftOver] > 0} {
                set plist ""
                foreach num $paramsLeftOver {
                    if {[info exists Params($num>name)]} {
                        set name $Params($num>name)
                    } else {
                        set name "#$num"
                    }
                    lappend plist "$Params($num-type)($name):$Params($num-value)"
                }
                warn "Extra parameters have been ignored:\n!![join $plist \n!!]\nFor command:\n!!$orig"
            }
            break
        }
    }
}

# if a template didn't match, use -default
if {$cmd eq ""} {
    if {$default eq ""} {
        set cmdlist [join $templates "\n!!"]
        fail "== Tool Invocation Error ==\nMissing required parameters.\n\nShould match one of the following commands:\n!!$cmdlist\n\nInput parameters:\n!![join $Params(orig) \n!!]"
    } else {
        if {[llength $Params(all)] > 0 && [llength $templates] > 0} {
            set cmdlist [join $templates "\n!!"]
            warn "Specified parameters did not match\nany of the following invocations:\n!!$cmdlist\n\nInput parameters:\n!![join $Params(orig) \n!!]"
        }
        set cmd $default
    }
}

# execute the command that we finally settled on
if {[catch {eval exec $cmd} result]} {
    puts stderr $result
    set status 1
} else {
    puts stdout $result
    set status 0
}

# need to wait for warning messages?
if {$Wait} {
    vwait Wait
}
exit $status
