tclhttpd

Changes On Branch 4_0
Login

Changes On Branch 4_0

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch 4_0 Excluding Merge-Ins

This is equivalent to a diff from 16399ebdeb to ffc189660f

2015-05-14
10:31
Converted the last of the lassign-brent calls to straight-up lassign Adapted the http::compat to be user selectable as far as how far back we intend to support Adding a qwiki object called MAIN to the default httpd thread Fixed the examples of Taourl so far to now employ the "puts" to buffer architecture. Merging in upsteam changes from tao Broke out the base security system and urls into layers Leaf check-in: ffc189660f user: hypnotoad tags: 4_0
2015-04-03
07:35
Added more documentation Renamed the cookieSet method to httpdCookieSet, and moved it to httpd.meta Moved httpdHostName it to httpd.meta Implemented logins using encrypted password hashes Added a module to store javascript password hashing routines. Added a "cat" command to dump files Added the pageHeader and pageFooter methods to httpd.meta Community and its decendents now render pages in bootstrap/jquery. Added jquery to our bootstrap distribution check-in: 80751cdeac user: hypnotoad tags: 4_0
2015-04-02
10:07
Bumped the version to 3.5.3 to fold in all of the fixes thusfar, and to account for the incomplete way that 3.5.2 was rolled out. Updated the version numbers in all distribution files The 3.5 series is now in pure bug fix mode, new development is along the 4.0 branch Leaf check-in: e7e4dbf86a user: hypnotoad tags: 3_5_3
2015-03-28
08:26
Creating a "branch" to maintain our feature set as released in 3.5.1 Leaf check-in: d2a3620b0e user: hypnotoad tags: 3_5_1
08:25
Starting the branch to tclhttpd 4.0 check-in: de06e800ad user: hypnotoad tags: 4_0
08:17
Merged with trunk Closed-Leaf check-in: d5c61ebd08 user: hypnotoad tags: Supports8.6
2014-09-10
12:45
Added support for "-dispatch" option to Url_PrefixInstall. This allows for custom thread dispatchers and per-session threading. Leaf check-in: 16399ebdeb user: clif tags: trunk
2014-08-17
16:06
Added support for config::cget MailServer. That's what's defined in tclhttpd.rc. I think Config(mail) was a previous incarnation of Config. I left that for consistency with older (much older?) systems. check-in: 973cd248ed user: clif tags: trunk

Changes to ChangeLog.








1
2
3
4
5
6
7







2005-04-26 Michael Thomas <[email protected]>
        * bin/httpd.tcl:  Don't [fork] if we're in a threaded interpreter
          since [fork] doesn't play well with threads.

2005-04-09 Colin McCormack <[email protected]>
	* bin/httpd.tcl: changed version number to reflect actual
	version (3.5.2)
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
2015-03-28 Sean Woods <[email protected]>
	* Started work on v4
	* Tclhttpd now targets 8.6+
	* Many evals replaced with the expansion operator {*}
	* "lib" directory restructured into a tcllib style "modules" directory
	* NOTE: Changes are now maintained in the fossil repo

2005-04-26 Michael Thomas <[email protected]>
        * bin/httpd.tcl:  Don't [fork] if we're in a threaded interpreter
          since [fork] doesn't play well with threads.

2005-04-09 Colin McCormack <[email protected]>
	* bin/httpd.tcl: changed version number to reflect actual
	version (3.5.2)

Changes to DIST_build/DIST.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh
#
# Create a super distribution of TclHttpd, Tcl, Tcllib, and Thread

WELCH=/panfs/panwest/home/welch

HTTPD_VERSION=3.5.1
HTTPD_TAG=tclhttpd-3-5-rel-1
HTTPD_TAG=HEAD
WIN_VERSION=351
DISTDIR=${WELCH}/dist
SUPER_DIR=${DISTDIR}/tclhttpd${HTTPD_VERSION}-dist

TCL_VERSION=8.4.5
TCL_DIST=${DISTDIR}/tcl${TCL_VERSION}-src.tar.gz

TCLLIB_VERSION=1.6
TCLLIB_DIST=${DISTDIR}/tcllib-${TCLLIB_VERSION}.tar.gz

# There is a configure error in CVS right now
#THREAD_VERSION=2.6




|

|
|
|




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh
#
# Create a super distribution of TclHttpd, Tcl, Tcllib, and Thread

WELCH=/opt/odie/sandbox/tclhttpd

HTTPD_VERSION=4.0.0
HTTPD_TAG=tclhttpd-4-0
HTTPD_TAG=4_0
WIN_VERSION=351
DISTDIR=${WELCH}/dist
SUPER_DIR=${DISTDIR}/tclhttpd${HTTPD_VERSION}-dist

TCL_VERSION=8.6.4
TCL_DIST=${DISTDIR}/tcl${TCL_VERSION}-src.tar.gz

TCLLIB_VERSION=1.6
TCLLIB_DIST=${DISTDIR}/tcllib-${TCLLIB_VERSION}.tar.gz

# There is a configure error in CVS right now
#THREAD_VERSION=2.6
32
33
34
35
36
37
38
39

40

41

42


43
44
45
46
47
48
49
SCRATCH=${WELCH}/scratch
mkdir -p ${SCRATCH}
cd ${SCRATCH}

echo "*** Checkout tclhttpd ${HTTPD_VERSION} ***"

rm -rf ${SCRATCH}/tclhttpd${HTTPD_VERSION}
cvs -d [email protected]:/cvsroot/tclhttpd checkout -r ${HTTPD_TAG} tclhttpd 

#(cd tclhttpd ; cvs -d [email protected]:/cvsroot/tclpro checkout config)

mv tclhttpd tclhttpd${HTTPD_VERSION}

chmod -R a+r tclhttpd${HTTPD_VERSION}


chmod a+x tclhttpd${HTTPD_VERSION}/bin/httpd.tcl
chmod a-x tclhttpd${HTTPD_VERSION}/bin/httpdthread.tcl
chmod a+x tclhttpd${HTTPD_VERSION}/htdocs/cgi-bin/junk*
chmod a+x tclhttpd${HTTPD_VERSION}/htdocs/cgi-bin/env
find tclhttpd${HTTPD_VERSION}/htdocs -name "*.cgi" -exec chmod a+x {} \;
cp tclhttpd${HTTPD_VERSION}/license.terms tclhttpd${HTTPD_VERSION}/htdocs
mkdir tclhttpd${HTTPD_VERSION}/htdocs/links







|
>
|
>
|
>
|
>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
SCRATCH=${WELCH}/scratch
mkdir -p ${SCRATCH}
cd ${SCRATCH}

echo "*** Checkout tclhttpd ${HTTPD_VERSION} ***"

rm -rf ${SCRATCH}/tclhttpd${HTTPD_VERSION}
mkdir -p ${SCRATCH}/tclhttpd${HTTPD_VERSION}
chmod -R a+r ${SCRATCH}/tclhttpd${HTTPD_VERSION}

fossil clone http://core.tcl.tk/tclhttpd /opt/odie/download/tclhttpd.fos
cd ${SCRATCH}/tclhttpd${HTTPD_VERSION}
fossil open /opt/odie/download/tclhttpd.fos ${HTTPD_TAG}

cd ${SCRATCH}

chmod a+x tclhttpd${HTTPD_VERSION}/bin/httpd.tcl
chmod a-x tclhttpd${HTTPD_VERSION}/bin/httpdthread.tcl
chmod a+x tclhttpd${HTTPD_VERSION}/htdocs/cgi-bin/junk*
chmod a+x tclhttpd${HTTPD_VERSION}/htdocs/cgi-bin/env
find tclhttpd${HTTPD_VERSION}/htdocs -name "*.cgi" -exec chmod a+x {} \;
cp tclhttpd${HTTPD_VERSION}/license.terms tclhttpd${HTTPD_VERSION}/htdocs
mkdir tclhttpd${HTTPD_VERSION}/htdocs/links

Changes to DIST_build/DIST.exp.

1
2
3
4
5
6
7
8
9
10
11
# Expect script to drive DIST, and handle the CVS password prompting.

set v 3.5.1
set vv 351

stty -echo
send_user "CVS Password: "
expect_user {
    -re "(.*)\n" { set Password $expect_out(1,string) }
    timeout { return -code error "You must enter a password!"}
}


|
|







1
2
3
4
5
6
7
8
9
10
11
# Expect script to drive DIST, and handle the CVS password prompting.

set v 4.0.0
set vv 400

stty -echo
send_user "CVS Password: "
expect_user {
    -re "(.*)\n" { set Password $expect_out(1,string) }
    timeout { return -code error "You must enter a password!"}
}

Changes to DIST_build/README.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
This is a bundled distribution of TclHttpd, Tcl, the
Standard Tcl Library, and the Thread extension.

If you already have tcl 8.4 or 8.3 installed, then you can probably
run the Tcl Web Server directly from this distribtuion without
doing any installation steps (The directory will really be
named something like tclhttpd3.5.1) :

cd tclhttpd3.5/bin
tclsh httpd.tcl -port 8001 -debug 1

If you get complaints about missing the Standard Tcl Library,
then you can install just that by running the install.sh script
in the tcllib1.6 directory.

If you want a clean install of everything, including a Tcl 8.4.5
that has thread enabled, then use the Makefile in the top-level directory.
This will compile things under the build directory, segregating
by platform into different subdirectories.

More Docs
There are a few more README-like files you should read:
tclhttpd3.5/INSTALL
tclhttpd3.5/README
tclhttpd3.5/WHATSNEW
tclhttpd3.5/ChangeLog
tclhttpd3.5/certs/README.ssl

Information about TclHttpd is at

http://www.tcl.tk/software/tclhttpd

The mailing list is
mailto:[email protected]






|

|













|
|
|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
This is a bundled distribution of TclHttpd, Tcl, the
Standard Tcl Library, and the Thread extension.

If you already have tcl 8.4 or 8.3 installed, then you can probably
run the Tcl Web Server directly from this distribtuion without
doing any installation steps (The directory will really be
named something like tclhttpd4.0.1) :

cd tclhttpd4.0/bin
tclsh httpd.tcl -port 8001 -debug 1

If you get complaints about missing the Standard Tcl Library,
then you can install just that by running the install.sh script
in the tcllib1.6 directory.

If you want a clean install of everything, including a Tcl 8.4.5
that has thread enabled, then use the Makefile in the top-level directory.
This will compile things under the build directory, segregating
by platform into different subdirectories.

More Docs
There are a few more README-like files you should read:
tclhttpd4.0/INSTALL
tclhttpd4.0/README
tclhttpd4.0/WHATSNEW
tclhttpd4.0/ChangeLog
tclhttpd4.0/certs/README.ssl

Information about TclHttpd is at

http://www.tcl.tk/software/tclhttpd

The mailing list is
mailto:[email protected]

Changes to INSTALL.

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
blocks.  Without threads, you are forced to put your blocking
operations into CGI scripts so that the external CGI process blocks.
The server continues to service requests until the pipe connected
to the CGI process produces data.

5. Starkit Distribution

The tclhttpd3.5.0.kit file is a starkit that is used with the
tclkit Tcl interpreter.  There is more information about Tclkit at
  http://wiki.tcl.tk/tclkit/
but the basic idea is simple.  All you need is a tclkit binary
installed for your platform, and the platform-independent tclhttpd.kit.
Start the server like this:
  tclkit tclhttpd.kit -port 8001 -docRoot /your/htdocs -library /your/code
If you don't supply a docRoot or library, then you get the sample







|







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
blocks.  Without threads, you are forced to put your blocking
operations into CGI scripts so that the external CGI process blocks.
The server continues to service requests until the pipe connected
to the CGI process produces data.

5. Starkit Distribution

The tclhttpd4.0.0.kit file is a starkit that is used with the
tclkit Tcl interpreter.  There is more information about Tclkit at
  http://wiki.tcl.tk/tclkit/
but the basic idea is simple.  All you need is a tclkit binary
installed for your platform, and the platform-independent tclhttpd.kit.
Start the server like this:
  tclkit tclhttpd.kit -port 8001 -docRoot /your/htdocs -library /your/code
If you don't supply a docRoot or library, then you get the sample

Changes to Makefile.in.

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
includedir = @includedir@
oldincludedir = /usr/include

DESTDIR =

pkgdatadir = $(datadir)/@PACKAGE@@VERSION@
pkglibdir = $(libdir)/@PACKAGE@@VERSION@
cryptlibdir = $(libdir)/@CRYPT_PACKAGE@@CRYPT_VERSION@
limitlibdir = $(libdir)/@LIMIT_PACKAGE@@LIMIT_VERSION@
pkgincludedir = $(includedir)/@PACKAGE@@VERSION@
SERVER_ROOT = @SERVER_ROOT@
htdocsdir = $(SERVER_ROOT)/htdocs
customdir = $(SERVER_ROOT)/custom

top_builddir = .








|
|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
includedir = @includedir@
oldincludedir = /usr/include

DESTDIR =

pkgdatadir = $(datadir)/@PACKAGE@@VERSION@
pkglibdir = $(libdir)/@PACKAGE@@VERSION@
cryptlibdir = $(libdir)/@PACKAGE@@VERSION@/@CRYPT_PACKAGE@
limitlibdir = $(libdir)/@PACKAGE@@VERSION@/@LIMIT_PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@@VERSION@
SERVER_ROOT = @SERVER_ROOT@
htdocsdir = $(SERVER_ROOT)/htdocs
customdir = $(SERVER_ROOT)/custom

top_builddir = .

304
305
306
307
308
309
310

311
312
313
314
315
316
317
318
319
320
321
322
323
324
	    $(INSTALL_PROGRAM) $$i $(DESTDIR)$(prefix)/bin ; \
	done;
	@for i in $(srcdir)/bin/*.rc ; do \
	    $(INSTALL_DATA) $$i $(DESTDIR)$(prefix)/bin ; \
	done;
	@echo "Installing sample boot script"
	$(INSTALL_DATA) $(srcdir)/bin/tclhttpd.etc.init $(DESTDIR)$(SERVER_ROOT)


install-libraries: install-custom installdirs 
	@echo "Installing script files in $(DESTDIR)$(pkglibdir)"
	@for i in $(srcdir)/lib/*.tcl ; do \
	    $(INSTALL_SCRIPT) $$i $(DESTDIR)$(pkglibdir) ; \
	done;
	$(INSTALL_SCRIPT) $(srcdir)/lib/mime.types $(DESTDIR)$(pkglibdir)

install-htdocs:
	@echo "Creating htdocs tree in $(htdocsdir)"
	-chmod 755 `@CYGPATH@ $(srcdir)/htdocs/cgi-bin/*.cgi`
	$(TCLSH_PROG) `@CYGPATH@ $(srcdir)/bin/CopyDist` `@CYGPATH@ $(srcdir)/htdocs` `@CYGPATH@ $(DESTDIR)$(htdocsdir)`
	-$(mkinstalldirs) $(DESTDIR)$(htdocsdir)/links
	@echo "Copying some READMEs into $(htdocsdir)/links"







>



<
|
<
|







304
305
306
307
308
309
310
311
312
313
314

315

316
317
318
319
320
321
322
323
	    $(INSTALL_PROGRAM) $$i $(DESTDIR)$(prefix)/bin ; \
	done;
	@for i in $(srcdir)/bin/*.rc ; do \
	    $(INSTALL_DATA) $$i $(DESTDIR)$(prefix)/bin ; \
	done;
	@echo "Installing sample boot script"
	$(INSTALL_DATA) $(srcdir)/bin/tclhttpd.etc.init $(DESTDIR)$(SERVER_ROOT)


install-libraries: install-custom installdirs 
	@echo "Installing script files in $(DESTDIR)$(pkglibdir)"

	$(TCLSH_PROG) autosetup/install.tcl $(srcdir)/modules $(DESTDIR)$(pkglibdir)

	$(INSTALL_SCRIPT) $(srcdir)/modules/httpd/mime.types $(DESTDIR)$(pkglibdir)

install-htdocs:
	@echo "Creating htdocs tree in $(htdocsdir)"
	-chmod 755 `@CYGPATH@ $(srcdir)/htdocs/cgi-bin/*.cgi`
	$(TCLSH_PROG) `@CYGPATH@ $(srcdir)/bin/CopyDist` `@CYGPATH@ $(srcdir)/htdocs` `@CYGPATH@ $(DESTDIR)$(htdocsdir)`
	-$(mkinstalldirs) $(DESTDIR)$(htdocsdir)/links
	@echo "Copying some READMEs into $(htdocsdir)/links"
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
	  if test -f $$p; then \
	    ext=`echo $$p|sed -e "s/.*\.//"`; \
	    if test "x$$ext" = "xdll"; then \
	        echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \
	        $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
		lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
		if test -f $$lib; then \
		    echo " $(INSTALL_PROGRAM) $$lib $(DESTDIR)$(libdir)/$$lib"; \
	            $(INSTALL_PROGRAM) $$lib $(DESTDIR)$(libdir)/$$lib; \
		fi; \
	    else \
		echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libdir)/$$p"; \
	        $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libdir)/$$p; \
	    fi; \
	  else :; fi; \
	done
	@list='$(lib_BINARIES)'; for p in $$list; do \
	  if test -f $$p; then \
	    echo " $(RANLIB) $(DESTDIR)$(libdir)/$$p"; \
	    $(RANLIB) $(DESTDIR)$(libdir)/$$p; \







|
|


|
|







373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
	  if test -f $$p; then \
	    ext=`echo $$p|sed -e "s/.*\.//"`; \
	    if test "x$$ext" = "xdll"; then \
	        echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \
	        $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
		lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
		if test -f $$lib; then \
		    echo " $(INSTALL_PROGRAM) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \
	            $(INSTALL_PROGRAM) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \
		fi; \
	    else \
		echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
	        $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \
	    fi; \
	  else :; fi; \
	done
	@list='$(lib_BINARIES)'; for p in $$list; do \
	  if test -f $$p; then \
	    echo " $(RANLIB) $(DESTDIR)$(libdir)/$$p"; \
	    $(RANLIB) $(DESTDIR)$(libdir)/$$p; \

Deleted README.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
This HTTPD is written in Tcl and Tk.
Written by Stephen Uhler and Brent Welch of Sun Microsystems Laboratory.
Brent is now at Panasas, Inc.
See the file "license.terms" for information on usage and redistribution
of this file, and for a DISCLAIMER OF ALL WARRANTIES.

Version: 3.5.1
Tue May 18 21:15:39 PDT 2004

STARKIT QUICK START

tclkit tclhttpd3.5.1.kit -port 80 -docRoot htmldir -library tcldir

The server loads all the tcl sources in the library.  Try also
tclkit tclhttpd3.5.1.kit -help

STANDARD QUICK START

It requires Tcl 8.3 (or higher) and the Standard Tcl Library.
This uses the cmdline, base64, ncgi, html, and counter
modules of the Standard Tcl Library. If you must, you
can probably get by with Tcl 8.0 or later if you install
the Standard Tcl Library.

The Web server runs under either tclsh or wish.
With wish you get a simple GUI that shows some counters.

For a quick test that runs a server on port 8015, do
UNIX:

1) Test preconditions
	Tcl interpreter: tclsh8.3, tclsh8.4, tclsh8.5, or tclkit (or wish)
        tcllib 1.3 or higher
Try
        tclsh (whatever version)
	package require counter

2) If you can do the above, then you should be able to run the
server directly from this distribution directory without bothering
to configure, make, and install it. e.g., 

	tclsh8.4 bin/httpd.tcl -debug 1
Windows and Macintosh:
	Run wish or tclsh and source bin/httpd.tcl

3) For more detailed installation instructions, see the INSTALL file.

For a complete set of command line options, do
httpd.tcl -help
This lets you set basic parameters like port number and server name.

VERSION SUMMARY

Version 3.5 has various bug fixes, improvements to the docs, and
some sample applications.  3.5.1 adds a mail client module.

Version 3.4.3  fixes loading code from the custom code directory,
which broke in 3.4.2

Version 3.4.2 has bug fixes in the directory listing code (dirlist.tcl).
Prevent listing of directory trees outside the URL tree, and get them to work
at all.  Added a fix in upload.tcl so that extra post data is cleaned up
correctly - fixes bugs that occur when GET and POST uploads are mixed.
Minor cleanup to the sample htdocs tree.

Version 3.4.1 fixes CGI POST forms on Windows, a typo in upload.tcl
and the lib/pkgIndex.tcl.  It also disallows the ability to retrieve
.tml, .tclaccess, and .htaccess files.  These simple new APIs crept in:
  Url_AccessInstallPrepend, Url_AccessUnInstall
  Mtype_Add, Mtype_Reset
  Direct_UrlRemove

Version 3.4 has several updates to the Doc, Upload, and Thread modules
done by Melissa Chawla of Panasas. Please see the ChangeLog for details.
There is also a small modification to support If-Modified-Since optimization
in Httpd_ReturnFile contributed by Brian Meagher.  Don Porter contributed
virtual host support, so you can support several sites with one server.
Please see README.virthost for details

Version 3.3.1 was just a cleanup of the installation files and
configure scripts. (acruz)

Version 3.3 fixes more bugs in CGI handling and
adds a simple file upload domain handler.

Version 3.2.1 fixes bugs in CGI handling related to the changes
in 3.2 in the way POST data is handled.  

Version 3.2 changes the way you customize a TclHttpd installation with
the goal of not having to modify the bin/httpd.tcl and bin/httpdthread.tcl
scripts, although in some cases this will still be necessary.  A new
"custom code" directory is supported and the server will load all the
code from that directory during startup.  Specify this with the -library
command line option or the "library" Config specification in your .rc file.

Version 3.1.0 renames all the packages to be httpd::foo instead of just
foo, so that the package namespace is a bit more organized when TclHttpd
is installed along with the rest of Tcl and Tk.  Other that that,
it is essentially identical with 3.0.4.

Version 3.0.4 fixes yet-another bug with Doc_AddRoot.

Version 3.0.3 fixes another bug with Doc_AddRoot, and fixes the
bundled distribution so you can use the Thread extension again.

Version 3.0.2 fixes a serious SECURITY BUG that let 3.0.0 and 3.0.1 
serve up any old file on your system.  That bug was not present in earlier
versions of the server.

Version 3.0.1 has minor bug fixes and (hopefully) some improvements
in the bundled distribution.

Version 3.0.0 has three major changes:
* Use of Standard Tcl Library modules.  The server looks around for the
tcllib distribution and automatically uses it.  One goal of this conversion
is to eliminate the use of the page global array and replace that with
calls to the ncgi module.
* Support for threads.  If you configure and build Tclsh with --enable-threads
and you have the Thread extension available, the the server can 
use threads to service requests.
* Support for SSL.  If you have the "tls" extension installed, then you can
start an SSL server by giving the -https_port command line argument.

Version 2.3.6 is the last in the 2.3 series.  It has a few minor
bug fixes.  The next release, 3.0, will support threading using
the Thread extension and SSL using the TLS extension.

Version 2.3 changes the way post data is  handled.
The various point releases (e.g., 2.3.4) fix important
bugs in cookie handling and the new post data handler.

Version 2.1.6 introduces a configuration file, tclhttpd.rc
You can edit this to tune the set of modules used by the server,
or to hardwire the port, etc.

If you have Scotty installed, then you can try out the SNMP demo.
You'll need to arrange to have the Tnm*.so library on the
auto_path for your shell.  I have found that 2.1.5 works
with 8.0a2, but not with 8.0b1 because Tcl_GetFile has gone.

MAILING LISTS

There is a mailing list for users of the Tcl web server at
SourceForge as part of the tclhttpd project.  Please sign
up via the web site at www.sourceforge.net/projects/tclhttpd.
If that is dead, send email to
[email protected]
to find out the current location of the mailing list

Send messages for the list to
[email protected]

Bugs and comments to the mailing list, or to <[email protected]>
Put "httpd" in the subject of the mail so I can sort it automatically.

WWW

The current URL for the distribution can be found in
ftp://www.tcl.tk/pub/tcl/httpd/

There is documentation at
http://www.beedub.com/tclhttpd/
http://www.tcl.tk/software/tclhttpd/

SourceForge

http://www.sourceforge.net/projects/tclhttpd
http://tclhttpd.sourceforge.net/
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































































































Added README.md.























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
This HTTPD is written in Tcl and Tk.
Originally written by Stephen Uhler and Brent Welch of Sun Microsystems Laboratory.
Brent is now at Panasas, Inc.

Version 4 is maintained by Sean Woods of Test & Evaluation Solutions.

See the file "license.terms" for information on usage and redistribution
of this file, and for a DISCLAIMER OF ALL WARRANTIES.

Version: 4.0.0
Sat Mar 28 04:44:11 EDT 2015

STARKIT QUICK START

tclkit tclhttpd4.0.0.kit -port 80 -docRoot htmldir -library tcldir

The server loads all the tcl sources in the library.  Try also
tclkit tclhttpd4.0.0.kit -help

STANDARD QUICK START

It requires Tcl 8.6 (or higher) and the Standard Tcl Library.
This uses the cmdline, base64, ncgi, html, sha1, and counter
modules of the Standard Tcl Library. If you must, you
can probably get by with Tcl 8.5 or later if you install
the Standard Tcl Library and the TclOO extension.

The Web server runs under either tclsh or wish.
With wish you get a simple GUI that shows some counters.

For a quick test that runs a server on port 8015, do
UNIX:

1) Test preconditions
	Tcl interpreter: tclsh8.5, tclsh8.6, tclkit (or wish)
        tcllib 1.6 or higher
Try
        tclsh (whatever version)
	package require counter

2) If you can do the above, then you should be able to run the
server directly from this distribution directory without bothering
to configure, make, and install it. e.g., 

	tclsh8.6 bin/httpd.tcl -debug 1
Windows and Macintosh:
	Run wish or tclsh and source bin/httpd.tcl

3) For more detailed installation instructions, see the INSTALL file.

For a complete set of command line options, do
httpd.tcl -help
This lets you set basic parameters like port number and server name.

VERSION SUMMARY

Version 4.0 adds support for Tcl 8.6, and integrates TclOO. The
/lib directory has been moved to /modules, and the layout of modules
now mirrors that of Tcllib. DirectOO adds the ability to implement
dynamic content with TclOO objects. This version adds bootstrap
and markdown support.

Version 3.5 has various bug fixes, improvements to the docs, and
some sample applications.  3.5.1 adds a mail client module.

Version 3.4.3  fixes loading code from the custom code directory,
which broke in 3.4.2

Version 3.4.2 has bug fixes in the directory listing code (dirlist.tcl).
Prevent listing of directory trees outside the URL tree, and get them to work
at all.  Added a fix in upload.tcl so that extra post data is cleaned up
correctly - fixes bugs that occur when GET and POST uploads are mixed.
Minor cleanup to the sample htdocs tree.

Version 3.4.1 fixes CGI POST forms on Windows, a typo in upload.tcl
and the lib/pkgIndex.tcl.  It also disallows the ability to retrieve
.tml, .tclaccess, and .htaccess files.  These simple new APIs crept in:
  Url_AccessInstallPrepend, Url_AccessUnInstall
  Mtype_Add, Mtype_Reset
  Direct_UrlRemove

Version 3.4 has several updates to the Doc, Upload, and Thread modules
done by Melissa Chawla of Panasas. Please see the ChangeLog for details.
There is also a small modification to support If-Modified-Since optimization
in Httpd_ReturnFile contributed by Brian Meagher.  Don Porter contributed
virtual host support, so you can support several sites with one server.
Please see README.virthost for details

Version 3.3.1 was just a cleanup of the installation files and
configure scripts. (acruz)

Version 3.3 fixes more bugs in CGI handling and
adds a simple file upload domain handler.

Version 3.2.1 fixes bugs in CGI handling related to the changes
in 3.2 in the way POST data is handled.  

Version 3.2 changes the way you customize a TclHttpd installation with
the goal of not having to modify the bin/httpd.tcl and bin/httpdthread.tcl
scripts, although in some cases this will still be necessary.  A new
"custom code" directory is supported and the server will load all the
code from that directory during startup.  Specify this with the -library
command line option or the "library" Config specification in your .rc file.

Version 3.1.0 renames all the packages to be httpd::foo instead of just
foo, so that the package namespace is a bit more organized when TclHttpd
is installed along with the rest of Tcl and Tk.  Other that that,
it is essentially identical with 3.0.4.

Version 3.0.4 fixes yet-another bug with Doc_AddRoot.

Version 3.0.3 fixes another bug with Doc_AddRoot, and fixes the
bundled distribution so you can use the Thread extension again.

Version 3.0.2 fixes a serious SECURITY BUG that let 3.0.0 and 3.0.1 
serve up any old file on your system.  That bug was not present in earlier
versions of the server.

Version 3.0.1 has minor bug fixes and (hopefully) some improvements
in the bundled distribution.

Version 3.0.0 has three major changes:
* Use of Standard Tcl Library modules.  The server looks around for the
tcllib distribution and automatically uses it.  One goal of this conversion
is to eliminate the use of the page global array and replace that with
calls to the ncgi module.
* Support for threads.  If you configure and build Tclsh with --enable-threads
and you have the Thread extension available, the the server can 
use threads to service requests.
* Support for SSL.  If you have the "tls" extension installed, then you can
start an SSL server by giving the -https_port command line argument.

Version 2.3.6 is the last in the 2.3 series.  It has a few minor
bug fixes.  The next release, 3.0, will support threading using
the Thread extension and SSL using the TLS extension.

Version 2.3 changes the way post data is  handled.
The various point releases (e.g., 2.3.4) fix important
bugs in cookie handling and the new post data handler.

Version 2.1.6 introduces a configuration file, tclhttpd.rc
You can edit this to tune the set of modules used by the server,
or to hardwire the port, etc.

If you have Scotty installed, then you can try out the SNMP demo.
You'll need to arrange to have the Tnm*.so library on the
auto_path for your shell.  I have found that 2.1.5 works
with 8.0a2, but not with 8.0b1 because Tcl_GetFile has gone.

MAILING LISTS

There is a mailing list for users of the Tcl web server at
SourceForge as part of the tclhttpd project.  Please sign
up via the web site at www.sourceforge.net/projects/tclhttpd.
If that is dead, send email to
[email protected]
to find out the current location of the mailing list

Send messages for the list to
[email protected]

Bugs and comments to the mailing list, or to <[email protected]>
Put "httpd" in the subject of the mail so I can sort it automatically.

WWW

The current URL for the distribution can be found in
http://core.tcl.tk/tclhttpd

This site contains the fossil source repository, as well as the
most up to date documentation.

Changes to VERSION.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Current version is 3.5.1
This is reflected in the following files (sigh)

README
        For informational purposes
configure.in
        The patchlevel is either "" or ".1" etc.
        *re-run* autoconf to update configure
bin/httpd.tcl
        set v 3.5.1
        So it can look for the right tclhttpd library
lib/version.tcl
        To set the right version string.  This does
        package provide major.minor only, but the string
        has the date and patchlevel.  The actual value
        of the httpd::version package number isn't used.
lib/pkgIndex.tcl
|








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Current version is 4.0.0
This is reflected in the following files (sigh)

README
        For informational purposes
configure.in
        The patchlevel is either "" or ".1" etc.
        *re-run* autoconf to update configure
bin/httpd.tcl
        set v 4.0.0
        So it can look for the right tclhttpd library
lib/version.tcl
        To set the right version string.  This does
        package provide major.minor only, but the string
        has the date and patchlevel.  The actual value
        of the httpd::version package number isn't used.
lib/pkgIndex.tcl

Changes to WHATSNEW.

1
2




3
4
5
6
7
8
9
What's new in TclHttpd





3.5

Mostly this is a cleanup of the code and web pages to cleanly
separate out the core server from various sample applications and
demo code.  The default web site is defined by the htdocs and custom
subdirectories, and all the other stuff is organized under sampleapp.
There are some new security controls over the debug URL so you can


>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
What's new in TclHttpd

4.0
This version targets the new TclOO features backed into 8.6, as
well as utilizing sqlite as a database backend.

3.5

Mostly this is a cleanup of the code and web pages to cleanly
separate out the core server from various sample applications and
demo code.  The default web site is defined by the htdocs and custom
subdirectories, and all the other stuff is organized under sampleapp.
There are some new security controls over the debug URL so you can

Added auto.def.

















































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# Created by migrate-autoconf - fix items marked XXX

use cc cc-shared odie

options {
	with-serverroot:DIR  =>  {}
}
array set ::project {
  name tclhttpd
  major_version 4
  minor_version 0
  patchlevel .alpha
  fedora_release 0.fdr.1
}

foreach {field value} [array get ::project] {
  define PKG_[string toupper $field] $value
}

#--------------------------------------------------------------------
# __CHANGE__
# Set your package name and version numbers here.  The NODOT_VERSION is
# required for constructing the library name on systems that don't like
# dots in library names (Windows).  The VERSION variable is used on the
# other systems.
#--------------------------------------------------------------------

# XXX PACKAGE=tclhttpd

# XXX MAJOR_VERSION=4
# XXX MINOR_VERSION=0
# XXX PATCHLEVEL=".0"
# XXX RELEASE=`grep Release: ${srcdir}/${PACKAGE}.spec | sed -e 's/Release: *//'`

# XXX VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
# XXX NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
# XXX WIN_VERSION=`echo ${VERSION} | sed -e 's/\.//g'`

# XXX TCL_VERSION=8.6.4
# XXX TCLLIB_VERSION=1.6
# XXX THREAD_VERSION=2.6

# We build two minor packages for the crypt and limit C extensions

# XXX CRYPT_PACKAGE=crypt
# XXX CRYPT_VERSION="1.0"
# XXX WIN_CRYPT_VERSION=`echo ${CRYPT_VERSION} | sed -e 's/\.//g'`
# XXX LIMIT_PACKAGE=limit
# XXX LIMIT_VERSION="1.0"
# XXX WIN_LIMIT_VERSION=`echo ${LIMIT_VERSION} | sed -e 's/\.//g'`

if {[opt-val with-serverroot] ne {}} {
	set withval [opt-val with-serverroot]
	# XXX SERVER_ROOT=${withval}
} else {
	# XXX SERVER_ROOT='$(prefix)/$(PACKAGE)'
}

# XXX AC_SUBST PACKAGE
# XXX AC_SUBST SERVER_ROOT
# XXX AC_SUBST VERSION
# XXX AC_SUBST RELEASE
# XXX AC_SUBST WIN_VERSION

# XXX AC_SUBST CRYPT_PACKAGE
# XXX AC_SUBST CRYPT_VERSION
# XXX AC_SUBST WIN_CRYPT_VERSION

# XXX AC_SUBST LIMIT_PACKAGE
# XXX AC_SUBST LIMIT_VERSION
# XXX AC_SUBST WIN_LIMIT_VERSION

# XXX AC_SUBST TCL_VERSION
# XXX AC_SUBST TCLLIB_VERSION

# XXX AC_SUBST THREAD_VERSION

#--------------------------------------------------------------------
# We put this here so that you can compile with -DVERSION="1.2" to
# encode the package version directly into the source files.
#--------------------------------------------------------------------

# XXX eval AC_DEFINE_UNQUOTED(VERSION, "${VERSION}")

#--------------------------------------------------------------------
# Check whether --enable-gcc or --disable-gcc was given.  Do this
# before AC_CYGWIN is called so the compiler can
# be fully tested by built-in autoconf tools.
# This macro also calls AC_PROG_CC to set the compiler if --enable-gcc
# was not used.
#--------------------------------------------------------------------

# XXX SC_ENABLE_GCC
cc-check-progs install

#--------------------------------------------------------------------
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------


#--------------------------------------------------------------------
# Find ranlib
#--------------------------------------------------------------------

cc-check-tools ranlib

#--------------------------------------------------------------------
# This macro performs additional compiler tests.
#--------------------------------------------------------------------

# XXX AC_CYGWIN

#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------

# XXX AC_OBJEXT

#--------------------------------------------------------------------
# "cygpath" is used on windows to generate native path names for include
# files.
# These variables should only be used with the compiler and linker since
# they generate native path names.
#
# Unix tclConfig.sh points SRC_DIR at the top-level directory of
# the Tcl sources, while the Windows tclConfig.sh points SRC_DIR at
# the win subdirectory.  Hence the different usages of SRC_DIR below.
#
# This must be done before calling SC_PUBLIC_TCL_HEADERS
#--------------------------------------------------------------------

# XXX case "`uname -s`" in
# XXX *win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)
# XXX CYGPATH="cygpath -w"
# XXX RELPATH=".. .. bin"
# XXX ;;
# XXX *)
# XXX CYGPATH=echo
# XXX RELPATH=..
# XXX ;;
# XXX esac

# XXX AC_SUBST CYGPATH
# XXX AC_SUBST RELPATH

#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------

# XXX SC_PATH_TCLCONFIG
# XXX SC_LOAD_TCLCONFIG

#--------------------------------------------------------------------
# __CHANGE__
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after SC_PATH_TCLCONFIG/SC_LOAD_TCLCONFIG
#--------------------------------------------------------------------

# XXX SC_PUBLIC_TCL_HEADERS
#SC_PRIVATE_TCL_HEADERS

#--------------------------------------------------------------------
# __CHANGE__
# A few miscellaneous platform-specific items:
#
# Define a special symbol for Windows (BUILD_exampleA in this case) so
# that we create the export library with the dll.  See sha1.h on how
# to use this.
#
# Windows creates a few extra files that need to be cleaned up.
# You can add more files to clean if your extension creates any extra
# files.
#
# Define any extra compiler flags in the PACKAGE_CFLAGS variable.
# These will be appended to the current set of compiler flags for
# your system.
#--------------------------------------------------------------------

# XXX case "`uname -s`" in
# XXX *win32* | *WIN32* | *CYGWIN_NT*|*CYGWIN_98*|*CYGWIN_95*)
# XXX AC_DEFINE_UNQUOTED BUILD_${PACKAGE}
# XXX CLEANFILES="*.lib *.dll *.exp *.ilk *.pdb vc50.pch"
# XXX AC_SUBST CLEANFILES
# XXX ;;
# XXX *)
# XXX CLEANFILES=
# XXX ;;
# XXX esac

#--------------------------------------------------------------------
# Check whether --enable-threads or --disable-threads was given.
# So far only Tcl responds to this one.
#--------------------------------------------------------------------

# XXX SC_ENABLE_THREADS

#--------------------------------------------------------------------
# The statement below defines a collection of symbols related to
# building as a shared library instead of a static library.
#--------------------------------------------------------------------

# XXX SC_ENABLE_SHARED

#--------------------------------------------------------------------
# This macro figures out what flags to use with the compiler/linker
# when building shared/static debug/optimized objects.  This information
# is all taken from the tclConfig.sh file.
#--------------------------------------------------------------------

# XXX CFLAGS_DEBUG=${TCL_CFLAGS_DEBUG}
# XXX CFLAGS_OPTIMIZE=${TCL_CFLAGS_OPTIMIZE}
# XXX LDFLAGS_DEBUG=${TCL_LDFLAGS_DEBUG}
# XXX LDFLAGS_OPTIMIZE=${TCL_LDFLAGS_OPTIMIZE}
# XXX SHLIB_LD=${TCL_SHLIB_LD}
# XXX STLIB_LD=${TCL_STLIB_LD}
# XXX SHLIB_CFLAGS=${TCL_SHLIB_CFLAGS}

# XXX AC_SUBST CFLAGS_DEBUG
# XXX AC_SUBST CFLAGS_OPTIMIZE
# XXX AC_SUBST STLIB_LD
# XXX AC_SUBST SHLIB_LD
# XXX AC_SUBST SHLIB_CFLAGS
# XXX AC_SUBST SHLIB_LDFLAGS

#--------------------------------------------------------------------
# Find out where we should get the crypt() function
#--------------------------------------------------------------------

if {![cc-check-functions crypt]} {
}

# XXX AC_SUBST CRYPT_OBJS

#--------------------------------------------------------------------
# Find out if we have the sys/resource.h header file for building
# the limit extension
#--------------------------------------------------------------------

if {[cc-check-includes sys/resource.h]} {
	# XXX BUILD_LIMIT=1
} else {
	# XXX BUILD_LIMIT=0
}

# XXX if test "${BUILD_LIMIT}" = 1 ; then
# XXX LIMIT_EXTENSION='$(limit_LIB_FILE)'
# XXX else
# XXX LIMIT_EXTENSION=''
# XXX fi

# XXX AC_SUBST LIMIT_EXTENSION
# XXX AC_SUBST BUILD_LIMIT

#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols
# option.
#--------------------------------------------------------------------

# XXX SC_ENABLE_SYMBOLS

# XXX if test "${SHARED_BUILD}" = "1" ; then
# XXX CFLAGS='${CFLAGS_DEFAULT} ${CFLAGS_WARNING} ${SHLIB_CFLAGS}'
# XXX else
# XXX CFLAGS='${CFLAGS_DEFAULT} ${CFLAGS_WARNING}'
# XXX fi

#--------------------------------------------------------------------
# Everyone should be linking against the Tcl stub library.  If you
# can't for some reason, remove this definition.  If you aren't using
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.
#--------------------------------------------------------------------

define USE_TCL_STUBS

#--------------------------------------------------------------------
# This macro generates a line to use when building a library.  It
# depends on values set by the SC_ENABLE_SHARED, SC_ENABLE_SYMBOLS,
# and SC_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------

# XXX SC_MAKE_LIB

#--------------------------------------------------------------------
# eval these two values to dereference the ${DBGX} variable.
#--------------------------------------------------------------------

# XXX eval "SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}"
# XXX eval "UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}"

#--------------------------------------------------------------------
# Shared libraries and static libraries have different names.
#--------------------------------------------------------------------

# XXX case "`uname -s`" in
# XXX *win32* | *WIN32* | *CYGWIN_NT*|*CYGWIN_98*|*CYGWIN_95*)
# XXX if test "${SHARED_BUILD}" = "1" ; then
# XXX SHLIB_LD_LIBS="\"`cygpath -w ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\" ${TCL_SHLIB_LD_LIBS}"
# XXX eval "${PACKAGE}_LIB_FILE=${PACKAGE}${SHARED_LIB_SUFFIX}"
# XXX eval "${CRYPT_PACKAGE}_LIB_FILE=${CRYPT_PACKAGE}${SHARED_LIB_SUFFIX}"
# XXX eval "${LIMIT_PACKAGE}_LIB_FILE=${LIMIT_PACKAGE}${SHARED_LIB_SUFFIX}"
# XXX RANLIB=:
# XXX else
# XXX eval "${PACKAGE}_LIB_FILE=${PACKAGE}${UNSHARED_LIB_SUFFIX}"
# XXX eval "${CRYPT_PACKAGE}_LIB_FILE=${CRYPT_PACKAGE}${UNSHARED_LIB_SUFFIX}"
# XXX eval "${LIMIT_PACKAGE}_LIB_FILE=${LIMIT_PACKAGE}${UNSHARED_LIB_SUFFIX}"
# XXX fi
# XXX ;;
# XXX *)
# XXX if test "${SHARED_BUILD}" = "1" ; then
# XXX SHLIB_LD_LIBS="${TCL_STUB_LIB_SPEC} ${CRYPT_LIB}"
# XXX eval "${PACKAGE}_LIB_FILE=lib${PACKAGE}${SHARED_LIB_SUFFIX}"
# XXX eval "${CRYPT_PACKAGE}_LIB_FILE=lib${CRYPT_PACKAGE}${SHARED_LIB_SUFFIX}"
# XXX eval "${LIMIT_PACKAGE}_LIB_FILE=lib${LIMIT_PACKAGE}${SHARED_LIB_SUFFIX}"
# XXX RANLIB=:
# XXX else
# XXX eval "${PACKAGE}_LIB_FILE=lib${PACKAGE}${UNSHARED_LIB_SUFFIX}"
# XXX eval "${CRYPT_PACKAGE}_LIB_FILE=lib${CRYPT_PACKAGE}${UNSHARED_LIB_SUFFIX}"
# XXX eval "${LIMIT_PACKAGE}_LIB_FILE=lib${LIMIT_PACKAGE}${UNSHARED_LIB_SUFFIX}"
# XXX fi
# XXX ;;
# XXX esac

# XXX AC_SUBST SHARED_BUILD

#--------------------------------------------------------------------
# __CHANGE__
# Change the name from exampeA_LIB_FILE to match your package name.
#--------------------------------------------------------------------

# Hack to map from the TclHttpd version number that got automatically
# sucked up by the SHARED_LIB_SUFFIX macro
# XXX crypt_LIB_FILE=`echo $crypt_LIB_FILE | sed -e "s/$VERSION/$CRYPT_VERSION/" | sed -e "s/$NODOT_VERSION/$WIN_CRYPT_VERSION/"`
# XXX limit_LIB_FILE=`echo $limit_LIB_FILE | sed -e "s/$VERSION/$LIMIT_VERSION/" | sed -e "s/$NODOT_VERSION/$WIN_LIMIT_VERSION/"`
# XXX AC_SUBST limit_LIB_FILE
# XXX AC_SUBST crypt_LIB_FILE
# XXX AC_SUBST SHLIB_LD_LIBS

#--------------------------------------------------------------------
# Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl
# file during the install process.  Don't run the TCLSH_PROG through
# ${CYGPATH} because it's being used directly by make.
# Require that we use a tclsh shell version 8.2 or later since earlier
# versions have bugs in the pkg_mkIndex routine.
#--------------------------------------------------------------------

# XXX SC_PROG_TCLSH

#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
#--------------------------------------------------------------------

make-template Makefile.in
make-template  crypt_pkgIndex.tcl.in
make-template  limit_pkgIndex.tcl.in
make-template  $::project(name).spec.in

Added autosetup/LICENSE.







































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Unless explicitly stated, all files which form part of autosetup
are released under the following license:

---------------------------------------------------------------------
autosetup - A build environment "autoconfigurator"

Copyright (c) 2010-2011, WorkWare Systems <http://workware.net.au/>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials
   provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of WorkWare Systems.

Added autosetup/README.autosetup.



>
1
This is autosetup v0.6.6. See http://msteveb.github.com/autosetup/

Added autosetup/autosetup.



















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
#!/bin/sh
# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# vim:se syntax=tcl:
# \
dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"

set autosetup(version) 0.6.6

# Can be set to 1 to debug early-init problems
set autosetup(debug) 0

##################################################################
#
# Main flow of control, option handling
#
proc main {argv} {
	global autosetup define

	# There are 3 potential directories involved:
	# 1. The directory containing autosetup (this script)
	# 2. The directory containing auto.def
	# 3. The current directory

	# From this we need to determine:
	# a. The path to this script (and related support files)
	# b. The path to auto.def
	# c. The build directory, where output files are created

	# This is also complicated by the fact that autosetup may
	# have been run via the configure wrapper ([getenv WRAPPER] is set)

	# Here are the rules.
	# a. This script is $::argv0
	#    => dir, prog, exe, libdir
	# b. auto.def is in the directory containing the configure wrapper,
	#    otherwise it is in the current directory.
	#    => srcdir, autodef
	# c. The build directory is the current directory
	#    => builddir, [pwd]

	# 'misc' is needed before we can do anything, so set a temporary libdir
	# in case this is the development version
	set autosetup(libdir) [file dirname $::argv0]/lib
	use misc

	# (a)
	set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
	set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
	set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
	if {$autosetup(installed)} {
		set autosetup(libdir) $autosetup(dir)
	} else {
		set autosetup(libdir) [file join $autosetup(dir) lib]
	}
	autosetup_add_dep $autosetup(prog)

	# (b)
	if {[getenv WRAPPER ""] eq ""} {
		# Invoked directly
		set autosetup(srcdir) [pwd]
	} else {
		# Invoked via the configure wrapper
		set autosetup(srcdir) [file dirname $autosetup(exe)]
	}
	set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]

	# (c)
	set autosetup(builddir) [pwd]

	set autosetup(argv) $argv
	set autosetup(cmdline) {}
	set autosetup(options) {}
	set autosetup(optionhelp) {}
	set autosetup(showhelp) 0

	# Parse options
	use getopt

	array set ::useropts [getopt argv]

	#"=Core Options:"
	options-add {
		help:=local  => "display help and options. Optionally specify a module name, such as --help=system"
		version      => "display the version of autosetup"
		ref:=text manual:=text
		reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
		debug        => "display debugging output as autosetup runs"
		install:=.   => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
		force init:=help   => "create initial auto.def, etc.  Use --init=help for known types"
		# Undocumented options
		option-checking=1
		nopager
		quiet
		timing
		conf:
	}

	#parray ::useropts
	if {[opt-bool version]} {
		puts $autosetup(version)
		exit 0
	}

	# autosetup --conf=alternate-auto.def
	if {[opt-val conf] ne ""} {
		set autosetup(autodef) [opt-val conf]
	}

	# Debugging output (set this early)
	incr autosetup(debug) [opt-bool debug]
	incr autosetup(force) [opt-bool force]
	incr autosetup(msg-quiet) [opt-bool quiet]
	incr autosetup(msg-timing) [opt-bool timing]

	# If the local module exists, source it now to allow for
	# project-local customisations
	if {[file exists $autosetup(libdir)/local.tcl]} {
		use local
	}

	# Now any auto-load modules
	foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
		automf_load source $file
	}

	if {[opt-val help] ne ""} {
		incr autosetup(showhelp)
		use help
		autosetup_help [opt-val help]
	}

	if {[opt-val {manual ref reference}] ne ""} {
		use help
		autosetup_reference [opt-val {manual ref reference}]
	}

	if {[opt-val init] ne ""} {
		use init
		autosetup_init [opt-val init]
	}

	if {[opt-val install] ne ""} {
		use install
		autosetup_install [opt-val install]
	}

	if {![file exists $autosetup(autodef)]} {
		# Check for invalid option first
		options {}
		user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
	}

	# Parse extra arguments into autosetup(cmdline)
	foreach arg $argv {
		if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
			dict set autosetup(cmdline) $n $v
			define $n $v
		} else {
			user-error "Unexpected parameter: $arg"
		}
	}

	autosetup_add_dep $autosetup(autodef)

	set cmd [file-normalize $autosetup(exe)]
	foreach arg $autosetup(argv) {
		append cmd " [quote-if-needed $arg]"
	}
	define AUTOREMAKE $cmd

	# Log how we were invoked
	configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"

	# Note that auto.def is *not* loaded in the global scope
	source $autosetup(autodef)

	# Could warn here if options {} was not specified

	show-notices

	if {$autosetup(debug)} {
		msg-result "Writing all defines to config.log"
		configlog "================ defines ======================"
		foreach n [lsort [array names define]] {
			configlog "define $n $define($n)"
		}
	}

	exit 0
}

# Initial settings
set autosetup(exe) $::argv0
set autosetup(istcl) 1
set autosetup(start) [clock millis]
set autosetup(installed) 0
set autosetup(msg-checking) 0
set autosetup(msg-quiet) 0

# Embedded modules are inserted below here
set autosetup(installed) 1

# @opt-bool option ...
#
# Check each of the named, boolean options and return 1 if any of them have
# been set by the user.
#
proc opt-bool {args} {
	option-check-names {*}$args
	opt_bool ::useropts {*}$args
}

# @opt-val option-list ?default=""?
#
# Returns a list containing all the values given for the non-boolean options in 'option-list'.
# There will be one entry in the list for each option given by the user, including if the
# same option was used multiple times.
# If only a single value is required, use something like:
#
## lindex [opt-val $names] end
#
# If no options were set, $default is returned (exactly, not as a list).
#
proc opt-val {names {default ""}} {
	option-check-names {*}$names
	join [opt_val ::useropts $names $default]
}

proc option-check-names {args} {
	foreach o $args {
		if {$o ni $::autosetup(options)} {
			autosetup-error "Request for undeclared option --$o"
		}
	}
}

# Parse the option definition in $opts and update
# ::useropts() and ::autosetup(optionhelp) appropriately
#
proc options-add {opts {header ""}} {
	global useropts autosetup

	# First weed out comment lines
	set realopts {}
	foreach line [split $opts \n] {
		if {![string match "#*" [string trimleft $line]]} {
			append realopts $line \n
		}
	}
	set opts $realopts

	for {set i 0} {$i < [llength $opts]} {incr i} {
		set opt [lindex $opts $i]
		if {[string match =* $opt]} {
			# This is a special heading
			lappend autosetup(optionhelp) $opt ""
			set header {}
			continue
		}

		#puts "i=$i, opt=$opt"
		regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
		if {$name in $autosetup(options)} {
			autosetup-error "Option $name already specified"
		}

		#puts "$opt => $name $colon $equal $value"

		# Find the corresponding value in the user options
		# and set the default if necessary
		if {[string match "-*" $opt]} {
			# This is a documentation-only option, like "-C <dir>"
			set opthelp $opt
		} elseif {$colon eq ""} {
			# Boolean option
			lappend autosetup(options) $name

			if {![info exists useropts($name)]} {
				set useropts($name) $value
			}
			if {$value eq "1"} {
				set opthelp "--disable-$name"
			} else {
				set opthelp "--$name"
			}
		} else {
			# String option.
			lappend autosetup(options) $name

			if {$equal eq "="} {
				if {[info exists useropts($name)]} {
					# If the user specified the option with no value, the value will be "1"
					# Replace with the default
					if {$useropts($name) eq "1"} {
						set useropts($name) $value
					}
				}
				set opthelp "--$name?=$value?"
			} else {
				set opthelp "--$name=$value"
			}
		}

		# Now create the help for this option if appropriate
		if {[lindex $opts $i+1] eq "=>"} {
			set desc [lindex $opts $i+2]
			#string match \n* $desc
			if {$header ne ""} {
				lappend autosetup(optionhelp) $header ""
				set header ""
			}
			# A multi-line description
			lappend autosetup(optionhelp) $opthelp $desc
			incr i 2
		}
	}
}

# @module-options optionlist
#
# Like 'options', but used within a module.
proc module-options {opts} {
	set header ""
	if {$::autosetup(showhelp) > 1 && [llength $opts]} {
		set header "Module Options:"
	}
	options-add $opts $header

	if {$::autosetup(showhelp)} {
		# Ensure that the module isn't executed on --help
		# We are running under eval or source, so use break
		# to prevent further execution
		#return -code break -level 2
		return -code break
	}
}

proc max {a b} {
	expr {$a > $b ? $a : $b}
}

proc options-wrap-desc {text length firstprefix nextprefix initial} {
	set len $initial
	set space $firstprefix
	foreach word [split $text] {
		set word [string trim $word]
		if {$word == ""} {
			continue
		}
		if {$len && [string length $space$word] + $len >= $length} {
			puts ""
			set len 0
			set space $nextprefix
		}
		incr len [string length $space$word]
		puts -nonewline $space$word
		set space " "
	}
	if {$len} {
		puts ""
	}
}

proc options-show {} {
	# Determine the max option width
	set max 0
	foreach {opt desc} $::autosetup(optionhelp) {
		if {[string match =* $opt] || [string match \n* $desc]} {
			continue
		}
		set max [max $max [string length $opt]]
	}
	set indent [string repeat " " [expr $max+4]]
	set cols [getenv COLUMNS 80]
	catch {
		lassign [exec stty size] rows cols
	}
	incr cols -1
	# Now output
	foreach {opt desc} $::autosetup(optionhelp) {
		if {[string match =* $opt]} {
			puts [string range $opt 1 end]
			continue
		}
		puts -nonewline "  [format %-${max}s $opt]"
		if {[string match \n* $desc]} {
			puts $desc
		} else {
			options-wrap-desc [string trim $desc] $cols "  " $indent [expr $max + 2]
		}
	}
}

# @options options-spec
#
# Specifies configuration-time options which may be selected by the user
# and checked with opt-val and opt-bool. The format of options-spec follows.
#
# A boolean option is of the form:
#
## name[=0|1]  => "Description of this boolean option"
#
# The default is name=0, meaning that the option is disabled by default.
# If name=1 is used to make the option enabled by default, the description should reflect
# that with text like "Disable support for ...".
#
# An argument option (one which takes a parameter) is of the form:
#
## name:[=]value  => "Description of this option"
#
# If the name:value form is used, the value must be provided with the option (as --name=myvalue).
# If the name:=value form is used, the value is optional and the given value is used as the default
# if is not provided.
#
# Undocumented options are also supported by omitting the "=> description.
# These options are not displayed with --help and can be useful for internal options or as aliases.
#
# For example, --disable-lfs is an alias for --disable=largefile:
#
## lfs=1 largefile=1 => "Disable large file support"
#
proc options {optlist} {
	# Allow options as a list or args
	options-add $optlist "Local Options:"

	if {$::autosetup(showhelp)} {
		options-show
		exit 0
	}

	# Check for invalid options
	if {[opt-bool option-checking]} {
		foreach o [array names ::useropts] {
			if {$o ni $::autosetup(options)} {
				user-error "Unknown option --$o"
			}
		}
	}
}

proc config_guess {} {
	if {[file-isexec $::autosetup(dir)/config.guess]} {
		exec-with-stderr sh $::autosetup(dir)/config.guess
		if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} {
			user-error $alias
		}
		return $alias
	} else {
		configlog "No config.guess, so using uname"
		string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
	}
}

proc config_sub {alias} {
	if {[file-isexec $::autosetup(dir)/config.sub]} {
		if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} {
			user-error $alias
		}
	}
	return $alias
}

# @define name ?value=1?
#
# Defines the named variable to the given value.
# These (name, value) pairs represent the results of the configuration check
# and are available to be checked, modified and substituted.
#
proc define {name {value 1}} {
	set ::define($name) $value
	#dputs "$name <= $value"
}

# @define-append name value ...
#
# Appends the given value(s) to the given 'defined' variable.
# If the variable is not defined or empty, it is set to $value.
# Otherwise the value is appended, separated by a space.
# Any extra values are similarly appended.
# If any value is already contained in the variable (as a substring) it is omitted.
#
proc define-append {name args} {
	if {[get-define $name ""] ne ""} {
		# Make a token attempt to avoid duplicates
		foreach arg $args {
			if {[string first $arg $::define($name)] == -1} {
				append ::define($name) " " $arg
			}
		}
	} else {
		set ::define($name) [join $args]
	}
	#dputs "$name += [join $args] => $::define($name)"
}

# @get-define name ?default=0?
#
# Returns the current value of the 'defined' variable, or $default
# if not set.
#
proc get-define {name {default 0}} {
	if {[info exists ::define($name)]} {
		#dputs "$name => $::define($name)"
		return $::define($name)
	}
	#dputs "$name => $default"
	return $default
}

# @is-defined name
#
# Returns 1 if the given variable is defined.
#
proc is-defined {name} {
	info exists ::define($name)
}

# @all-defines
#
# Returns a dictionary (name value list) of all defined variables.
#
# This is suitable for use with 'dict', 'array set' or 'foreach'
# and allows for arbitrary processing of the defined variables.
#
proc all-defines {} {
	array get ::define
}


# @get-env name default
#
# If $name was specified on the command line, return it.
# If $name was set in the environment, return it.
# Otherwise return $default.
#
proc get-env {name default} {
	if {[dict exists $::autosetup(cmdline) $name]} {
		return [dict get $::autosetup(cmdline) $name]
	}
	getenv $name $default
}

# @env-is-set name
#
# Returns 1 if the $name was specified on the command line or in the environment.
# Note that an empty environment variable is not considered to be set.
#
proc env-is-set {name} {
	if {[dict exists $::autosetup(cmdline) $name]} {
		return 1
	}
	if {[getenv $name ""] ne ""} {
		return 1
	}
	return 0
}

# @readfile filename ?default=""?
#
# Return the contents of the file, without the trailing newline.
# If the doesn't exist or can't be read, returns $default.
#
proc readfile {filename {default_value ""}} {
	set result $default_value
	catch {
		set f [open $filename]
		set result [read -nonewline $f]
		close $f
	}
	return $result
}

# @writefile filename value
#
# Creates the given file containing $value.
# Does not add an extra newline.
#
proc writefile {filename value} {
	set f [open $filename w]
	puts -nonewline $f $value
	close $f
}

proc quote-if-needed {str} {
	if {[string match {*[\" ]*} $str]} {
		return \"[string map [list \" \\" \\ \\\\] $str]\"
	}
	return $str
}

proc quote-argv {argv} {
	set args {}
	foreach arg $argv {
		lappend args [quote-if-needed $arg]
	}
	join $args
}

# @suffix suf list
#
# Takes a list and returns a new list with $suf appended
# to each element
#
## suffix .c {a b c} => {a.c b.c c.c}
#
proc suffix {suf list} {
	set result {}
	foreach p $list {
		lappend result $p$suf
	}
	return $result
}

# @prefix pre list
#
# Takes a list and returns a new list with $pre prepended
# to each element
#
## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
#
proc prefix {pre list} {
	set result {}
	foreach p $list {
		lappend result $pre$p
	}
	return $result
}

# @find-executable name
#
# Searches the path for an executable with the given name.
# Note that the name may include some parameters, e.g. "cc -mbig-endian",
# in which case the parameters are ignored.
# Returns 1 if found, or 0 if not.
#
proc find-executable {name} {
	# Ignore any parameters
	set name [lindex $name 0]
	if {$name eq ""} {
		# The empty string is never a valid executable
		return 0
	}
	foreach p [split-path] {
		dputs "Looking for $name in $p"
		set exec [file join $p $name]
		if {[file-isexec $exec]} {
			dputs "Found $name -> $exec"
			return 1
		}
	}
	return 0
}

# @find-an-executable ?-required? name ...
#
# Given a list of possible executable names,
# searches for one of these on the path.
#
# Returns the name found, or "" if none found.
# If the first parameter is '-required', an error is generated
# if no executable is found.
#
proc find-an-executable {args} {
	set required 0
	if {[lindex $args 0] eq "-required"} {
		set args [lrange $args 1 end]
		incr required
	}
	foreach name $args {
		if {[find-executable $name]} {
			return $name
		}
	}
	if {$required} {
		if {[llength $args] == 1} {
			user-error "failed to find: [join $args]"
		} else {
			user-error "failed to find one of: [join $args]"
		}
	}
	return ""
}

# @configlog msg
#
# Writes the given message to the configuration log, config.log
#
proc configlog {msg} {
	if {![info exists ::autosetup(logfh)]} {
		set ::autosetup(logfh) [open config.log w]
	}
	puts $::autosetup(logfh) $msg
}

# @msg-checking msg
#
# Writes the message with no newline to stdout.
#
proc msg-checking {msg} {
	if {$::autosetup(msg-quiet) == 0} {
		maybe-show-timestamp
		puts -nonewline $msg
		set ::autosetup(msg-checking) 1
	}
}

# @msg-result msg
#
# Writes the message to stdout.
#
proc msg-result {msg} {
	if {$::autosetup(msg-quiet) == 0} {
		maybe-show-timestamp
		puts $msg
		set ::autosetup(msg-checking) 0
		show-notices
	}
}

# @msg-quiet command ...
#
# msg-quiet evaluates it's arguments as a command with output
# from msg-checking and msg-result suppressed.
#
# This is useful if a check needs to run a subcheck which isn't
# of interest to the user.
proc msg-quiet {args} {
	incr ::autosetup(msg-quiet)
	set rc [uplevel 1 $args]
	incr ::autosetup(msg-quiet) -1
	return $rc
}

# Will be overridden by 'use misc'
proc error-stacktrace {msg} {
	return $msg
}

proc error-location {msg} {
	return $msg
}

##################################################################
#
# Debugging output
#
proc dputs {msg} {
	if {$::autosetup(debug)} {
		puts $msg
	}
}

##################################################################
#
# User and system warnings and errors
#
# Usage errors such as wrong command line options

# @user-error msg
#
# Indicate incorrect usage to the user, including if required components
# or features are not found.
# autosetup exits with a non-zero return code.
#
proc user-error {msg} {
	show-notices
	puts stderr "Error: $msg"
	puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
	exit 1
}

# @user-notice msg
#
# Output the given message to stderr.
#
proc user-notice {msg} {
	lappend ::autosetup(notices) $msg
}

# Incorrect usage in the auto.def file. Identify the location.
proc autosetup-error {msg} {
	autosetup-full-error [error-location $msg]
}

# Like autosetup-error, except $msg is the full error message.
proc autosetup-full-error {msg} {
	show-notices
	puts stderr $msg
	exit 1
}

proc show-notices {} {
	if {$::autosetup(msg-checking)} {
		puts ""
		set ::autosetup(msg-checking) 0
	}
	flush stdout
	if {[info exists ::autosetup(notices)]} {
		puts stderr [join $::autosetup(notices) \n]
		unset ::autosetup(notices)
	}
}

proc maybe-show-timestamp {} {
	if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
		puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
	}
}

proc autosetup_version {} {
	return "autosetup v$::autosetup(version)"
}

##################################################################
#
# Directory/path handling
#

proc realdir {dir} {
	set oldpwd [pwd]
	cd $dir
	set pwd [pwd]
	cd $oldpwd
	return $pwd
}

# Follow symlinks until we get to something which is not a symlink
proc realpath {path} {
	while {1} {
		if {[catch {
			set path [file readlink $path]
		}]} {
			# Not a link
			break
		}
	}
	return $path
}

# Convert absolute path, $path into a path relative
# to the given directory (or the current dir, if not given).
#
proc relative-path {path {pwd {}}} {
	set diff 0
	set same 0
	set newf {}
	set prefix {}
	set path [file-normalize $path]
	if {$pwd eq ""} {
		set pwd [pwd]
	} else {
		set pwd [file-normalize $pwd]
	}

	if {$path eq $pwd} {
		return .
	}

	# Try to make the filename relative to the current dir
	foreach p [split $pwd /] f [split $path /] {
		if {$p ne $f} {
			incr diff
		} elseif {!$diff} {
			incr same
		}
		if {$diff} {
			if {$p ne ""} {
				# Add .. for sibling or parent dir
				lappend prefix ..
			}
			if {$f ne ""} {
				lappend newf $f
			}
		}
	}
	if {$same == 1 || [llength $prefix] > 3} {
		return $path
	}

	file join [join $prefix /] [join $newf /]
}

# Add filename as a dependency to rerun autosetup
# The name will be normalised (converted to a full path)
#
proc autosetup_add_dep {filename} {
	lappend ::autosetup(deps) [file-normalize $filename]
}

##################################################################
#
# Library module support
#

# @use module ...
#
# Load the given library modules.
# e.g. 'use cc cc-shared'
#
# Note that module 'X' is implemented in either 'autosetup/X.tcl'
# or 'autosetup/X/init.tcl'
#
# The latter form is useful for a complex module which requires additional
# support file. In this form, '$::usedir' is set to the module directory
# when it is loaded.
#
proc use {args} {
	foreach m $args {
		if {[info exists ::libmodule($m)]} {
			continue
		}
		set ::libmodule($m) 1
		if {[info exists ::modsource($m)]} {
			automf_load eval $::modsource($m)
		} else {
			set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl]
			set found 0
			foreach source $sources {
				if {[file exists $source]} {
					incr found
					break
				}
			}
			if {$found} {
				# For the convenience of the "use" source, point to the directory
				# it is being loaded from
				set ::usedir [file dirname $source]
				automf_load source $source
				autosetup_add_dep $source
			} else {
				autosetup-error "use: No such module: $m"
			}
		}
	}
}

# Load module source in the global scope by executing the given command
proc automf_load {args} {
	if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
		autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
	}
}
# ----- module core -----

set modsource(core) {
}

# ----- module asciidoc-formatting -----

set modsource(asciidoc-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting
# asciidoc format

use formatting

proc para {text} {
    regsub -all "\[ \t\n\]+" [string trim $text] " "
}
proc title {text} {
    underline [para $text] =
    nl
}
proc p {text} {
    puts [para $text]
    nl
}
proc code {text} {
    foreach line [parse_code_block $text] {
        puts "    $line"
    }
    nl
}
proc codelines {lines} {
    foreach line $lines {
        puts "    $line"
    }
    nl
}
proc nl {} {
    puts ""
}
proc underline {text char} {
    regexp "^(\[ \t\]*)(.*)" $text -> indent words
    puts $text
    puts $indent[string repeat $char [string length $words]]
}
proc section {text} {
    underline "[para $text]" -
    nl
}
proc subsection {text} {
    underline "$text" ~
    nl
}
proc bullet {text} {
    puts "* [para $text]"
}
proc indent {text} {
    puts " :: "
    puts [para $text]
}
proc defn {first args} {
    set sep ""
    if {$first ne ""} {
        puts "${first}::"
    } else {
        puts " :: "
    }
    set defn [string trim [join $args \n]]
    regsub -all "\n\n" $defn "\n ::\n" defn
    puts $defn
}
}

# ----- module formatting -----

set modsource(formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides common text formatting

# This is designed for documenation which looks like:
# code {...}
# or
# code {
#    ...
#    ...
# }
# In the second case, we need to work out the indenting
# and strip it from all lines but preserve the remaining indenting.
# Note that all lines need to be indented with the same initial
# spaces/tabs.
#
# Returns a list of lines with the indenting removed.
#
proc parse_code_block {text} {
    # If the text begins with newline, take the following text,
    # otherwise just return the original
    if {![regexp "^\n(.*)" $text -> text]} {
        return [list [string trim $text]]
    }

    # And trip spaces off the end
    set text [string trimright $text]

    set min 100
    # Examine each line to determine the minimum indent
    foreach line [split $text \n] {
        if {$line eq ""} {
            # Ignore empty lines for the indent calculation
            continue
        }
        regexp "^(\[ \t\]*)" $line -> indent
        set len [string length $indent]
        if {$len < $min} {
            set min $len
        }
    }

    # Now make a list of lines with this indent removed
    set lines {}
    foreach line [split $text \n] {
        lappend lines [string range $line $min end]
    }

    # Return the result
    return $lines
}
}

# ----- module getopt -----

set modsource(getopt) {
# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Simple getopt module

# Parse everything out of the argv list which looks like an option
# Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1
# Everything which doesn't look like an option, or is after --, is left unchanged
proc getopt {argvname} {
	upvar $argvname argv
	set nargv {}

	for {set i 0} {$i < [llength $argv]} {incr i} {
		set arg [lindex $argv $i]

		#dputs arg=$arg

		if {$arg eq "--"} {
			# End of options
			incr i
			lappend nargv {*}[lrange $argv $i end]
			break
		}

		if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
			lappend opts($name) $value
		} elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
			if {$prefix eq "disable-"} {
				set value 0
			} else {
				set value 1
			}
			lappend opts($name) $value
		} else {
			lappend nargv $arg
		}
	}

	#puts "getopt: argv=[join $argv] => [join $nargv]"
	#parray opts

	set argv $nargv

	return [array get opts]
}

proc opt_val {optarrayname options {default {}}} {
	upvar $optarrayname opts

	set result {}

	foreach o $options {
		if {[info exists opts($o)]} {
			lappend result {*}$opts($o)
		}
	}
	if {[llength $result] == 0} {
		return $default
	}
	return $result
}

proc opt_bool {optarrayname args} {
	upvar $optarrayname opts

	# Support the args being passed as a list
	if {[llength $args] == 1} {
		set args [lindex $args 0]
	}

	foreach o $args {
		if {[info exists opts($o)]} {
			if {"1" in $opts($o) || "yes" in $opts($o)} {
				return 1
			}
		}
	}
	return 0
}
}

# ----- module help -----

set modsource(help) {
# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
# All rights reserved

# Module which provides usage, help and the command reference

proc autosetup_help {what} {
    use_pager

    puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
    puts "This is [autosetup_version], a build environment \"autoconfigurator\""
    puts "See the documentation online at http://msteveb.github.com/autosetup/\n"

    if {$what eq "local"} {
        if {[file exists $::autosetup(autodef)]} {
            # This relies on auto.def having a call to 'options'
            # which will display options and quit
            source $::autosetup(autodef)
        } else {
            options-show
        }
    } else {
        incr ::autosetup(showhelp)
        if {[catch {use $what}]} {
            user-error "Unknown module: $what"
        } else {
            options-show
        }
    }
    exit 0
}

# If not already paged and stdout is a tty, pipe the output through the pager
# This is done by reinvoking autosetup with --nopager added
proc use_pager {} {
    if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
        if {[catch {
            exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
        } msg opts] == 1} {
            if {[dict get $opts -errorcode] eq "NONE"} {
                # an internal/exec error
                puts stderr $msg
                exit 1
            }
        }
        exit 0
    }
}

# Outputs the autosetup references in one of several formats
proc autosetup_reference {{type text}} {

    use_pager

    switch -glob -- $type {
        wiki {use wiki-formatting}
        ascii* {use asciidoc-formatting}
        md - markdown {use markdown-formatting}
        default {use text-formatting}
    }

    title "[autosetup_version] -- Command Reference"

    section {Introduction}

    p {
        See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
    }

    p {
        'autosetup' provides a number of built-in commands which
        are documented below. These may be used from 'auto.def' to test
        for features, define variables, create files from templates and
        other similar actions.
    }

    automf_command_reference

    exit 0
}

proc autosetup_output_block {type lines} {
    if {[llength $lines]} {
        switch $type {
            code {
                codelines $lines
            }
            p {
                p [join $lines]
            }
            list {
                foreach line $lines {
                    bullet $line
                }
                nl
            }
        }
    }
}

# Generate a command reference from inline documentation
proc automf_command_reference {} {
    lappend files $::autosetup(prog)
    lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]

    section "Core Commands"
    set type p
    set lines {}
    set cmd {}

    foreach file $files {
        set f [open $file]
        while {![eof $f]} {
            set line [gets $f]

            # Find lines starting with "# @*" and continuing through the remaining comment lines
            if {![regexp {^# @(.*)} $line -> cmd]} {
                continue
            }

            # Synopsis or command?
            if {$cmd eq "synopsis:"} {
                section "Module: [file rootname [file tail $file]]"
            } else {
                subsection $cmd
            }

            set lines {}
            set type p

            # Now the description
            while {![eof $f]} {
                set line [gets $f]

                if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
                    break
                }
                if {$hash eq "#"} {
                    set t code
                } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
                    set t list
                } else {
                    set t p
                }

                #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"

                if {$t ne $type || $cmd eq ""} {
                    # Finish the current block
                    autosetup_output_block $type $lines
                    set lines {}
                    set type $t
                }
                if {$cmd ne ""} {
                    lappend lines $cmd
                }
            }

            autosetup_output_block $type $lines
        }
        close $f
    }
}
}

# ----- module init -----

set modsource(init) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module to help create auto.def and configure

proc autosetup_init {type} {
	set help 0
	if {$type in {? help}} {
		incr help
	} elseif {![dict exists $::autosetup(inittypes) $type]} {
		puts "Unknown type, --init=$type"
		incr help
	}
	if {$help} {
		puts "Use one of the following types (e.g. --init=make)\n"
		foreach type [lsort [dict keys $::autosetup(inittypes)]] {
			lassign [dict get $::autosetup(inittypes) $type] desc
			# XXX: Use the options-show code to wrap the description
			puts [format "%-10s %s" $type $desc]
		}
		exit 0
	}
	lassign [dict get $::autosetup(inittypes) $type] desc script

	puts "Initialising $type: $desc\n"

	# All initialisations happens in the top level srcdir
	cd $::autosetup(srcdir)

	uplevel #0 $script

	exit 0
}

proc autosetup_add_init_type {type desc script} {
	dict set ::autosetup(inittypes) $type [list $desc $script]
}

# This is for in creating build-system init scripts
#
# If the file doesn't exist, create it containing $contents
# If the file does exist, only overwrite if --force is specified.
#
proc autosetup_check_create {filename contents} {
	if {[file exists $filename]} {
		if {!$::autosetup(force)} {
			puts "I see $filename already exists."
			return
		} else {
			puts "I will overwrite the existing $filename because you used --force."
		}
	} else {
		puts "I don't see $filename, so I will create it."
	}
	writefile $filename $contents
}
}

# ----- module install -----

set modsource(install) {
# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which can install autosetup

proc autosetup_install {dir} {
	if {[catch {
		cd $dir
		file mkdir autosetup

		set f [open autosetup/autosetup w]

		set publicmodules $::autosetup(libdir)/default.auto
                

		# First the main script, but only up until "CUT HERE"
		set in [open $::autosetup(dir)/autosetup]
		while {[gets $in buf] >= 0} {
			if {$buf ne "##-- CUT HERE --##"} {
				puts $f $buf
				continue
			}
                        
			# Insert the static modules here
			# i.e. those which don't contain @synopsis:
			puts $f "set autosetup(installed) 1"
                        set buf [readfile $::autosetup(libdir)/core.tcl]
                        set modname core
                        puts $f $buf
                        puts $f "# ----- module $modname -----"
                        puts $f "\nset modsource($modname) \{"
                        puts $f "\}\n"
                        
			foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
                          if {[file tail $file] eq "core.tcl"} continue
                          set buf [readfile $file]
                          if {[string match "*\n# @synopsis:*" $buf]} {
                                  lappend publicmodules $file
                                  continue
                          }
                          set modname [file rootname [file tail $file]]
                          puts $f "# ----- module $modname -----"
                          puts $f "\nset modsource($modname) \{"
                          puts $f $buf
                          puts $f "\}\n"
			}
		}
		close $in
		close $f
		exec chmod 755 autosetup/autosetup

		# Install public modules
		foreach file $publicmodules {
			autosetup_install_file $file autosetup
		}

		# Install support files
		foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
			autosetup_install_file $::autosetup(dir)/$file autosetup
		}
                foreach file [glob -nocomplain $::autosetup(dir)/scripts/*] {
			autosetup_install_file $::autosetup(dir)/scripts/[file tail $file] autosetup
                }
		exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh

		writefile autosetup/README.autosetup \
			"This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"

	} error]} {
		user-error "Failed to install autosetup: $error"
	}
	puts "Installed [autosetup_version] to autosetup/"

	# Now create 'configure' if necessary
	autosetup_create_configure

	exit 0
}

proc autosetup_create_configure {} {
	if {[file exists configure]} {
		if {!$::autosetup(force)} {
			# Could this be an autosetup configure?
			if {![string match "*\nWRAPPER=*" [readfile configure]]} {
				puts "I see configure, but not created by autosetup, so I won't overwrite it."
				puts "Remove it or use --force to overwrite."
				return
			}
		} else {
			puts "I will overwrite the existing configure because you used --force."
		}
	} else {
		puts "I don't see configure, so I will create it."
	}
	writefile configure \
{#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
}
	catch {exec chmod 755 configure}
}

# Append the contents of $file to filehandle $f
proc autosetup_install_append {f file} {
	set in [open $file]
	puts $f [read $in]
	close $in
}

proc autosetup_install_file {file dir} {
	if {![file exists $file]} {
		error "Missing installation file '$file'"
	}
	writefile [file join $dir [file tail $file]] [readfile $file]\n
}

if {$::autosetup(installed)} {
	user-error "autosetup can only be installed from development source, not from installed copy"
}
}

# ----- module markdown-formatting -----

set modsource(markdown-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting
# markdown format (kramdown syntax)

use formatting

proc para {text} {
    regsub -all "\[ \t\n\]+" [string trim $text] " " text
    regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
    regsub -all {^'([^']*)'} $text {**`\1`**} text
    regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
    return $text
}
proc title {text} {
    underline [para $text] =
    nl
}
proc p {text} {
    puts [para $text]
    nl
}
proc codelines {lines} {
    puts "~~~~~~~~~~~~"
    foreach line $lines {
        puts $line
    }
    puts "~~~~~~~~~~~~"
    nl
}
proc code {text} {
    puts "~~~~~~~~~~~~"
    foreach line [parse_code_block $text] {
        puts $line
    }
    puts "~~~~~~~~~~~~"
    nl
}
proc nl {} {
    puts ""
}
proc underline {text char} {
    regexp "^(\[ \t\]*)(.*)" $text -> indent words
    puts $text
    puts $indent[string repeat $char [string length $words]]
}
proc section {text} {
    underline "[para $text]" -
    nl
}
proc subsection {text} {
    puts "### `$text`"
    nl
}
proc bullet {text} {
    puts "* [para $text]"
}
proc defn {first args} {
    puts "^"
    set defn [string trim [join $args \n]]
    if {$first ne ""} {
        puts "**${first}**"
        puts -nonewline ": "
        regsub -all "\n\n" $defn "\n: " defn
    }
    puts "$defn"
}
}

# ----- module misc -----

set modsource(misc) {
# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module containing misc procs useful to modules
# Largely for platform compatibility

set autosetup(istcl) [info exists ::tcl_library]
set autosetup(iswin) [string equal windows $tcl_platform(platform)]

if {$autosetup(iswin)} {
	# mingw/windows separates $PATH with semicolons
	# and doesn't have an executable bit
	proc split-path {} {
		split [getenv PATH .] {;}
	}
	proc file-isexec {exec} {
		# Basic test for windows. We ignore .bat
		if {[file isfile $exec] || [file isfile $exec.exe]} {
			return 1
		}
		return 0
	}
} else {
	# unix separates $PATH with colons and has and executable bit
	proc split-path {} {
		split [getenv PATH .] :
	}
	proc file-isexec {exec} {
		file executable $exec
	}
}

# Assume that exec can return stdout and stderr
proc exec-with-stderr {args} {
	exec {*}$args 2>@1
}

if {$autosetup(istcl)} {
	# Tcl doesn't have the env command
	proc getenv {name args} {
		if {[info exists ::env($name)]} {
			return $::env($name)
		}
		if {[llength $args]} {
			return [lindex $args 0]
		}
		return -code error "environment variable \"$name\" does not exist"
	}
	proc isatty? {channel} {
		dict exists [fconfigure $channel] -xchar
	}
} else {
	if {$autosetup(iswin)} {
		# On Windows, backslash convert all environment variables
		# (Assume that Tcl does this for us)
		proc getenv {name args} {
			string map {\\ /} [env $name {*}$args]
		}
	} else {
		# Jim on unix is simple
		alias getenv env
	}
	proc isatty? {channel} {
		set tty 0
		catch {
			# isatty is a recent addition to Jim Tcl
			set tty [$channel isatty]
		}
		return $tty
	}
}

# In case 'file normalize' doesn't exist
#
proc file-normalize {path} {
	if {[catch {file normalize $path} result]} {
		if {$path eq ""} {
			return ""
		}
		set oldpwd [pwd]
		if {[file isdir $path]} {
			cd $path
			set result [pwd]
		} else {
			cd [file dirname $path]
			set result [file join [pwd] [file tail $path]]
		}
		cd $oldpwd
	}
	return $result
}

# If everything is working properly, the only errors which occur
# should be generated in user code (e.g. auto.def).
# By default, we only want to show the error location in user code.
# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
#
# This is designed to be called for incorrect usage in auto.def, via autosetup-error
#
proc error-location {msg} {
	if {$::autosetup(debug)} {
		return -code error $msg
	}
	# Search back through the stack trace for the first error in a .def file
	for {set i 1} {$i < [info level]} {incr i} {
		if {$::autosetup(istcl)} {
			array set info [info frame -$i]
		} else {
			lassign [info frame -$i] info(caller) info(file) info(line)
		}
		if {[string match *.def $info(file)]} {
			return "[relative-path $info(file)]:$info(line): Error: $msg"
		}
		#puts "Skipping $info(file):$info(line)"
	}
	return $msg
}

# If everything is working properly, the only errors which occur
# should be generated in user code (e.g. auto.def).
# By default, we only want to show the error location in user code.
# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
#
# This is designed to be called for incorrect usage in auto.def, via autosetup-error
#
proc error-stacktrace {msg} {
	if {$::autosetup(debug)} {
		return -code error $msg
	}
	# Search back through the stack trace for the first error in a .def file
	for {set i 1} {$i < [info level]} {incr i} {
		if {$::autosetup(istcl)} {
			array set info [info frame -$i]
		} else {
			lassign [info frame -$i] info(caller) info(file) info(line)
		}
		if {[string match *.def $info(file)]} {
			return "[relative-path $info(file)]:$info(line): Error: $msg"
		}
		#puts "Skipping $info(file):$info(line)"
	}
	return $msg
}

# Given the return from [catch {...} msg opts], returns an appropriate
# error message. A nice one for Jim and a less-nice one for Tcl.
# If 'fulltrace' is set, a full stack trace is provided.
# Otherwise a simple message is provided.
#
# This is designed for developer errors, e.g. in module code or auto.def code
#
#
proc error-dump {msg opts fulltrace} {
	if {$::autosetup(istcl)} {
		if {$fulltrace} {
			return "Error: [dict get $opts -errorinfo]"
		} else {
			return "Error: $msg"
		}
	} else {
		lassign $opts(-errorinfo) p f l
		if {$f ne ""} {
			set result "$f:$l: Error: "
		}
		append result "$msg\n"
		if {$fulltrace} {
			append result [stackdump $opts(-errorinfo)]
		}

		# Remove the trailing newline
		string trim $result
	}
}
}

# ----- module odie -----

set modsource(odie) {
# @synopsis:
#
# ODIE modules adds teacup platform data and integration with
# sherpa
#
use system codebale
# Build procs for this modules

options {
nodots => "Suppress dots in version numbers in lib names"
pkgdir: => "Where to install the package (default $prefix/lib)"
shlibver:=0.0 => "Shared lib version"
debugbld => "Debug build: symbols, asserts, etc."
nothreads => "Turn off threads"
static => "Build a static library (default off)"
}

proc odie_tea_init conflist {
  array set project $conflist
  
  set nodots [lindex [opt-val nodots] end]
  if {$nodots eq {}} {
    if {$::odie(windows)} {
      set nodots 1
    }
  } elseif {[string is true -strict $nodots]} {
    set nodots 1
  } else {
    set nodots 0
  }
  
  set libver $::project(pkgvers)
  lassign [regsub {^(\d)\.(\d)\.\d+$} [package provide Tcl] {\1.\2}] tclver
  if {[string is true -strict $nodots]} {
    set libver [string map {. ""} $libver]
    set tclver [string map {. ""} $tclver]
  }
  set prefix [get-define prefix]
  set pkgdir [lindex [opt-val pkgdir] end]
  if { $pkgdir eq {}} {
    set pkgdir [file join $prefix lib]
  }
  define pkgdir $pkgdir  
  define docdir [file join $prefix share doc]
  define exadir [file join $prefix share examples]
  define datarootdir [file join $prefix share]

  
  if {[file exists [file join $project(srcdir) .. odie odieConfig.tcl]]} {
    source [file join $project(srcdir) .. odie odieConfig.tcl]
  } else {
    set prefix [get-define prefix]
    if {$prefix eq {}} {
      foreach path {
        /odie
        ~/odie
        c:/odie
        /opt/local
        /opt/odie
        /opt/local/odie
        /usr/local/odie
      } {
        set cffile [file join $path sandbox odie odieConfig.tcl]
        if {[file exists $cffile]} {
  	set prefix [file normalize $path]
  	source $cffile
  	break
        }
      }
    }
    if {$prefix eq {} } { 
       error "No Odie detected"
    }
    if {![file exists [file join $prefix sandbox odie odieConfig.tcl]]} { 
       error "odieConfig.tcl not found"
    }
  }

  foreach {field} [lsort -dictionary [array names package]] {
    define PACKAGE_[string toupper $field] $package($field)
    define PKG_[string toupper $field] $package($field)
  }
  
  define PKG_NAME $::project(name)
  define PKG_VER $::project(pkgvers)
  
  set shlibver [lindex [opt-val shlibver 0.0] end]
  define SHLIB_VER $shlibver
  if {$shlibver ni {0.0 {}}} {
    append shlibspec [format [get-define SH_SOEXTVER] $shlibver]
  } else {
    set shlibspec [get-define SH_SOEXT]
  }
  define SHLIB_SPEC $shlibspec
  
  define EXT_INC_SPEC ""
  define EXT_LIB_DIR_SPEC ""
  define EXT_LIB_SPEC ""

  define TCL_INC_SPEC $::odie_tcl(include_spec)
  if {"tk" in $project(libs)} {
    define TCL_LIB_SPEC "$::odie_tcl(build_stub_lib_spec) $::odie_tk(build_stub_lib_spec)"
  } else {
    define TCL_LIB_SPEC $::odie_tcl(build_stub_lib_spec)
  }
  
  set ::odie_package(name) $::project(pkgname)
  set ::odie_package(version) $::project(pkgvers)
  set ::odie_package(ver) $::project(pkgvers)
  set ::odie_package(libfile) lib${::project(name)}$libver[get-define SHLIB_SPEC]
  set ::odie_package(lib_file) $::odie_package(libfile)
  if {"tk" in $project(libs)} {
    set ::odie_package(libs) $::odie_tk(libs)
  } else {
    set ::odie_package(libs) $::odie_tcl(libs)    
  }
  foreach lib $project(libs) {
    if { $lib in {tcl tk} } continue
    if { "-l$lib" ni $::odie_package(libs) } {
      lappend ::odie_package(libs) "-l$lib"
    }
  }
  set idx 0
  set start 0
  set end 0
  if {"tk" in $project(libs)} {
    set str $::odie_tk(defs)
  } else {
    set str $::odie_tcl(defs)
  }
  set len [string length $str]
  set token {}
  set next {}
  set item {}
  set opts {}
  while {$idx < $len} {
  ###
  # Seek start of opt
  ###
  if {[string range [string trim $item] end-1 end] != "-D"} {
    append item [string index $str $idx]
    incr idx
  } else {
    set end [expr {$idx-3}]
    set token [string trim [string range $str $start $end]]
    lappend opts $token
    set item {}
    set start $idx
    incr idx
  }
  }
  set token [string trim [string range $str $start end]]
  lappend opts $token
  
  set defs "-DPACKAGE_NAME=\"$::project(pkgname)\" -DPACKAGE_TARNAME=\"$::project(name)\" -DPACKAGE_VERSION=\"$::project(pkgvers)\" -DPACKAGE_STRING=\"$::project(pkgname) $::project(pkgvers)\""
  foreach opt [lrange $opts 4 end] {
  append defs " -D$opt"
  }
  set ::odie_package(defs) $defs
  set ::odie_package(cflags)  {}
  define DEFS $::odie_package(defs)
  set cflags { -pipe }
  if {[opt-bool debugbld]} {
  append cflags {${CFLAGS_DEBUG} ${CFLAGS_WARNING}}
  } else {
  append cflags {${CFLAGS_DEFAULT} ${CFLAGS_WARNING}}
  }
  if {[opt-bool static]} {
  } else {
  append cflags { ${SHLIB_CFLAGS}}
  }
  define CCFLAGS $cflags
  
  if {[lindex [opt-val nothreads] end] eq "1"} {
	define TH_CFLAGS ""
	define TH_LIBS ""
	define TH_DEFS ""
  } else {
	define TH_CFLAGS -pthread
	define TH_LIBS ""
	define TH_DEFS "-DTCL_THREADS=1 -DUSE_THREAD_ALLOC=1"
  }
  
  set tdefs {}
  lappend tdefs -DUSE_TCL_STUBS=1
  if {"tk" in $project(libs)} {
    lappend tdefs -DUSE_TK_STUBS=1
  }
  if {[lindex [opt-val debugbld] end] eq "1"} {
	define DEBUG ""
	define NDEBUG "#"
	lappend tdefs -DTCL_MEM_DEBUG=1
  } else {
	define DEBUG "#"
	define NDEBUG ""
  }
  define TDEFS [join $tdefs]
  
  set opt_defs {}
  define OPT_DEFS [join $opt_defs]
  
  define CCFLAGS $::odie_tcl(extra_cflags)
  define CFLAGS_WARN $::odie_tcl(cflags_warning)
  define CFLAGS_OPT $::odie_tcl(cflags_optimize)
  define CFLAGS_DEBUG $::odie_tcl(cflags_debug)
  
  foreach path $::project(include_paths) {
  append ::odie_package(includes) " " -I$path
  }
  
  set ::odie_package(headers) $::project(h_file)
  
  foreach {var val} [array get ::odie_package] {
  define PACKAGE_[string toupper $var] $val
  define PKG_[string toupper $var] $val
  }
  
  
  define LIB lib${::project(name)}$libver[get-define SHLIB_SPEC]
  define PKG_LIB lib${::project(name)}$libver[get-define SHLIB_SPEC]
  
  define PKG_TCL_MODULES_ROOT [file join $::project(srcdir) modules]
  define PKG_TCL_SOURCES ""
  set modules {}
  foreach path [glob -nocomplain [file join $::project(srcdir) modules *]] {
  if {[file isdirectory $path]} {
    lappend modules [file tail $path]
  }
  }
  define PKG_TCL_MODULES $modules
  define PKG_LIB_INIT $::project(name)
}


proc odie_mkhdr {} {
  ###
  # Build mkhdr if we don't have it
  ###
  if {![file exists [::realpath $::odie(mkhdr)]]} {
      cd [::realpath $::odie(src_dir)]
      doexec $::odie(cc) -o mkhdr.o -c scripts/mkhdr.c
      doexec $::odie(cc) mkhdr.o -o mkhdr$::odie(exe_suffix)
      file copy -force mkhdr$::odie(exe_suffix) [::realpath $::odie(mkhdr)]
  }
}

###
# Initialize our picture of the world
###
array set odie_tcl {
  config_flags {}
  version 8.6
  major_version 8
  minor_version 6
  patch_level .4
  fossil_branch release
}
array set odie_tk {
  config_flags {}
  version 8.6
  major_version 8
  minor_version 6
  patch_level .4
  fossil_branch release
}
array set odie {
  exe_suffix {}
  platform unix
  tea_platform_dir unix
  tcl_platform_dir unix
  tcl_config_flags {}
  tk_config_flags {}
  64bit {}
  windows 0
  system generic
  target generic
  os generic
  os_version {}
  teacup_os generic
  cpu {}
  window_system {}
  fossil_checkout .fslckout
  teacup_profile {}
  tk_binary_platform {}
  mirror_url http://fossil.etoyoc.com/fossil
}

# Make sure srcdir is fully qualified!
set ::odie(cpu) [exec uname -m]
set ::odie(os)  [exec uname -s]
set ::odie(system) ${::odie(os)}-${::odie(cpu)}

set vfscp {cp -a}
set ::odie(windows) 0
set ::odie(64bit) [expr {$::odie(cpu) in {amd64 x64 x86_64}}]

###
# Sort out some slight differences between Visual studio
# based builds and mingw/cygwin
###
switch -glob -- [get-define build] {
  *-*-ming* - *-*-cygwin - *-*-msys {
    ###
    # Under mingw, 64 bit is not possible
    ###
    set odie(windows) 1
    set odie(os) cygwin
    set ::odie(64bit) 0
  }
  *win32* - *WIN32* {
    ###
    # With visual studio, 64 bit should be assumed
    # but is otherwise to taste
    ###
    set odie(windows) 1
    set ::odie(os) windows

  } 
}

###
# Build information about the local tools
###
switch -glob -- [string tolower [get-define build]] {
  *-*-darwin* {
    # Use a native tool
    set verdat [exec sw_vers]
    foreach line [split $verdat \n] {
      if {[lindex $line 0] eq "ProductVersion:"} {
	set ::odie(os_version) [lindex $line 1]
      }
    }
    set ::odie(os) macosx
    set ::odie(teacup_os) macosx

    ###
    # Detect universal or x86_64
    ###
    set major [lindex [split $::odie(os_version) .] 1]
    if { $major < 4 || $::odie(cpu) != "x86_64"} {
      set ::odie(teacup_os) macosx
      set ::odie(teacup_profile) macosx-universal
      set ::odie(cpu) universal
    } else {
      set ::odie(teacup_os) macosx10.5
      set ::odie(teacup_profile) macosx10.5-i386-x86_64
      set ::odie(cpu) x86_64
    }
    set ::odie(tea_platform_dir) macosx
  }
  *-*-ming* - *-*-cygwin - *-*-msys - *win32*  {
    ###
    # With visual studio, 64 bit should be assumed
    # but is otherwise to taste
    ###
    set ::odie(platform) windows
    set ::odie(system) windows
    set ::odie(teacup_os) win32
    set vfscp {cp -a --no-preserve=links}
    set ::odie(windows) 1
    set ::odie(fossil_checkout)  _FOSSIL_
    set ::odie(tclsrc_dir) win
    set ::odie(platform_dir) win
    set ::odie(tea_platform_dir) win
    set ::odie(tcl_platform_dir) win
    if {$::odie(64bit)} {
      set ::odie(teacup_profile) win32-ix86
      set ::odie(cpu) ix86
    } else {
      set ::odie(teacup_profile) win32-x86_64
      set ::odie(cpu) x86_64
    }
    set ::odie(exe_suffix) .exe
  }
  *-*-linux* {
    set glibcver [exec ldd --version]
    set major [lindex [split $glibcver .] 0]
    set minor [lindex [split $glibcver .] 1]
    set ::odie(teacup_os) linux-glibc$major.$minor
    set ::odie(system) linux-$::odie(cpu)
    set ::odie(os) linux 
  }
}

if {[get-define build] ne [get-define host]} {
  set ::odie(windows) 0
  ###
  # Build information about the target
  ###
  switch [get-define host] {
    darwin - macosx - macosx10.5-i386-x86_64 {
      set ::odie(os) macosx
      set ::odie(teacup_os) macosx10.5
      set ::odie(teacup_profile) macosx10.5-i386-x86_64
      set ::odie(cpu) x86_64
      set ::odie(tea_platform_dir) macosx
      set ::odie(64bit) 1
    }
    macosx-universal {
      set ::odie(os) macosx
      set ::odie(teacup_os) macosx
      set ::odie(teacup_profile) macosx-universal
      set ::odie(cpu) universal
      set ::odie(tea_platform_dir) macosx
    }
    windows - windows-x86_64 - win32-x86_64 {
      set ::odie(platform) windows
      set ::odie(system) windows
      set ::odie(teacup_os) win32
      set ::odie(windows) 1
      set ::odie(tclsrc_dir) win
      set ::odie(platform_dir) win
      set ::odie(64bit) 1
      set ::odie(teacup_profile) win32-x86_64
      set ::odie(cpu) x86_64
      set ::odie(exe_suffix) .exe 
    }
    windows-ix86 - win32-ix86 {
      set ::odie(platform) windows
      set ::odie(system) windows
      set ::odie(teacup_os) win32
      set ::odie(windows) 1
      set ::odie(tclsrc_dir) win
      set ::odie(platform_dir) win
      set ::odie(64bit) 0
      set ::odie(teacup_profile) win32-ix86
      set ::odie(cpu) ix86
      set ::odie(exe_suffix) .exe
    }
    default {
      switch -glob -nocase -- [get-define target] {
        *macosx* - *-*-darwin* {
          # We don't know the version, so punt to
          # modern 64bit ix86
          set ::odie(os) macosx
          set ::odie(teacup_os) macosx10.5
          set ::odie(teacup_profile) macosx10.5-i386-x86_64
          set ::odie(cpu) x86_64
    
          set ::odie(tea_platform_dir) macosx
        }
        *-*-ming* - *-*-cygwin - *-*-msys - *win32*  {
          set ::odie(platform) windows
          set ::odie(system) windows
          set ::odie(teacup_os) win32
          set ::odie(windows) 1
          set ::odie(tclsrc_dir) win
          set ::odie(platform_dir) win
          if {$::odie(64bit)} {
            set ::odie(teacup_profile) win32-x86_64
            set ::odie(cpu) x86_64
          } else {
            set ::odie(teacup_profile) win32-ix86
            set ::odie(cpu) ix86
          }
          set ::odie(exe_suffix) .exe
        }
        *-*-linux* {
          # Assume a modern linux found in teacup profiles
          set ::odie(teacup_os) linux-glibc2.3
          set ::odie(system) linux-$::odie(cpu)
          set ::odie(os) linux 
        }
      }
    }
  }
}

if {$::odie(teacup_profile) eq {}} {
  set ::odie(teacup_profile) $::odie(teacup_os)-$::odie(cpu)
}
define VFS_CP $vfscp

if {[opt-val prefix] ne {} || ![info exists ::odie(prefix)]} {
  #------------------------------------------------------------------------
  # Handle the --prefix=... option
  #------------------------------------------------------------------------
  set prefix [opt-val prefix]
  if { $prefix eq {} } {
  
  
    if { $::odie(windows) } {
      set prefix c:/odie
    } else {
      set prefix $::env(HOME)/odie
    }
  }
  set ::odie_config(prefix) $prefix
  
  set exec_prefix $prefix
}
set ::odie(prefix) $prefix
define prefix $prefix
define exec_prefix $prefix

###
# Read in tclConfig.sh
###


set pathlist [list ../tcl/$::odie(tcl_platform_dir) ../tk/$::odie(tcl_platform_dir) [file join $prefix lib] /usr/local/lib /opt/local/lib c:/tcl c:/tcl/lib]
foreach {file pre array} {
  tclConfig.sh tcl ::odie_tcl
  tkConfig.sh  tk ::odie_tk
} {
  set ${array}(config_found) 0
  set l [expr {[string length $pre]+1}]
  foreach path $pathlist {
    set ffile [file join $path $file]
    if {[file exists $ffile]} break
  }
  if {![file exists $ffile]} continue
  set ${array}(config_found) 1
  foreach {field dat} [read_Config.sh $ffile] {
    set field [string tolower $field]
    if {[string match ${pre}_* $field]} {
      set field [string range $field $l end]
    }
    set ${array}($field) $dat
  }
}

###
# Figure out Tcl
###
if {$::odie(windows)} {
  set ::odie(tcl_shell) [file join $prefix bin tclsh${::odie_tcl(major_version)}${::odie_tcl(minor_version)}.exe]
  set ::odie(wish_shell) [file join $prefix bin wish${::odie_tk(major_version)}${::odie_tk(minor_version)}.exe]
  set ::odie(tclkit)  [file join $prefix bin tclkit${::odie_tcl(major_version)}${::odie_tcl(minor_version)}.exe]
  set ::odie(wishkit)  [file join $prefix bin tclkit${::odie_tcl(major_version)}${::odie_tcl(minor_version)}.exe]
  set ::odie(toadkit)  [file join $prefix bin toadkit${::odie_tcl(major_version)}${::odie_tcl(minor_version)}.exe]

} else {
  set ::odie(tcl_shell) [file join $prefix bin tclsh${::odie_tcl(major_version)}.${::odie_tcl(minor_version)}]
  set ::odie(wish_shell) [file join $prefix bin wish${::odie_tk(major_version)}.${::odie_tk(minor_version)}]
  set ::odie(tclkit)  [file join $prefix bin tclkit${::odie_tcl(major_version)}.${::odie_tcl(minor_version)}]
  set ::odie(wishkit)  [file join $prefix bin wishkit${::odie_tcl(major_version)}.${::odie_tcl(minor_version)}]
  set ::odie(toadkit)  [file join $prefix bin toadkit${::odie_tcl(major_version)}.${::odie_tcl(minor_version)}]
}

define TCL_SHELL   $::odie(tcl_shell)
define WISH_SHELL  $::odie(wish_shell)
define TCLSH_PROG  [info nameofexecutable]
define BUILD_TCLSH [info nameofexecutable]

set ::force_check 0
###
# Under MSYS/Cygwin transform the Cygwinized paths
# pack into proper names for Windows
###
foreach path {
  sandbox download src_dir tcl_shell wish_shell build_tclsh
  fossil git zip unzip sherpa lib local_repo
} {
  if {[info exists ::odie($path)]} {
    set ::odie_build($path) [::realpath $::odie($path)]
  }
}
}

# ----- module text-formatting -----

set modsource(text-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting

use formatting

proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
    set len 0
    set space $firstprefix
    foreach word [split $text] {
        set word [string trim $word]
        if {$word == ""} {
            continue
        }
        if {$len && [string length $space$word] + $len >= $length} {
            puts ""
            set len 0
            set space $nextprefix
        }
        incr len [string length $space$word]

        # Use man-page conventions for highlighting 'quoted' and *quoted*
        # single words.
        # Use x^Hx for *bold* and _^Hx for 'underline'.
        #
        # less and more will both understand this.
        # Pipe through 'col -b' to remove them.
        if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
            regsub -all . $bareword "_\b&" word
            append word $dot
        } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
            regsub -all . $bareword "&\b&" word
            append word $dot
        }
        puts -nonewline $space$word
        set space " "
    }
    if {$len} {
        puts ""
    }
}
proc title {text} {
    underline [string trim $text] =
    nl
}
proc p {text} {
    wordwrap $text 80
    nl
}
proc codelines {lines} {
    foreach line $lines {
        puts "    $line"
    }
    nl
}
proc nl {} {
    puts ""
}
proc underline {text char} {
    regexp "^(\[ \t\]*)(.*)" $text -> indent words
    puts $text
    puts $indent[string repeat $char [string length $words]]
}
proc section {text} {
    underline "[string trim $text]" -
    nl
}
proc subsection {text} {
    underline "$text" ~
    nl
}
proc bullet {text} {
    wordwrap $text 76 "  * " "    "
}
proc indent {text} {
    wordwrap $text 76 "    " "    "
}
proc defn {first args} {
    if {$first ne ""} {
        underline "    $first" ~
    }
    foreach p $args {
        if {$p ne ""} {
            indent $p
        }
    }
}
}

# ----- module wiki-formatting -----

set modsource(wiki-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting
# wiki.tcl.tk format output

use formatting

proc joinlines {text} {
    set lines {}
    foreach l [split [string trim $text] \n] {
        lappend lines [string trim $l]
    }
    join $lines
}
proc p {text} {
    puts [joinlines $text]
    puts ""
}
proc title {text} {
    puts "*** [joinlines $text] ***"
    puts ""
}
proc codelines {lines} {
    puts "======"
    foreach line $lines {
        puts "    $line"
    }
    puts "======"
}
proc code {text} {
    puts "======"
    foreach line [parse_code_block $text] {
        puts "    $line"
    }
    puts "======"
}
proc nl {} {
}
proc section {text} {
    puts "'''$text'''"
    puts ""
}
proc subsection {text} {
    puts "''$text''"
    puts ""
}
proc bullet {text} {
    puts "   * [joinlines $text]"
}
proc indent {text} {
    puts "    :    [joinlines $text]"
}
proc defn {first args} {
    if {$first ne ""} {
        indent '''$first'''
    }

    foreach p $args {
        p $p
    }
}
}

set corefile [file join [file dirname $::argv0] lib core.tcl]
if {[file exist $corefile]} {
  source $corefile
}

##################################################################
#
# Entry/Exit
#
if {$autosetup(debug)} {
	main $argv
}
if {[catch {main $argv} msg opts] == 1} {
	show-notices
	autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
	if {!$autosetup(debug)} {
		puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
	}
	exit 1
}

Added autosetup/cc-db.tcl.































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc-db' module provides a knowledge based of system idiosyncracies
# In general, this module can always be included

use cc

module-options {}

# openbsd needs sys/types.h to detect some system headers
cc-include-needs sys/socket.h sys/types.h
cc-include-needs netinet/in.h sys/types.h

Added autosetup/cc-lib.tcl.



































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# Provides a library of common tests on top of the 'cc' module.

use cc

module-options {}

# @cc-check-lfs
#
# The equivalent of the AC_SYS_LARGEFILE macro
# 
# defines 'HAVE_LFS' if LFS is available,
# and defines '_FILE_OFFSET_BITS=64' if necessary
#
# Returns 1 if 'LFS' is available or 0 otherwise
#
proc cc-check-lfs {} {
	cc-check-includes sys/types.h
	msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
	set lfs 1
	if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
		msg-result no
	} elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
		define _FILE_OFFSET_BITS 64
		msg-result yes
	} else {
		set lfs 0
		msg-result none
	}
	define-feature lfs $lfs
	return $lfs
}

# @cc-check-endian
#
# The equivalent of the AC_C_BIGENDIAN macro
# 
# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
#
# Returns 1 if determined, or 0 if not.
#
proc cc-check-endian {} {
	cc-check-includes sys/types.h sys/param.h
	set rc 0
	msg-checking "Checking endian..."
	cc-with {-includes {sys/types.h sys/param.h}} {
		if {[cctest -code {
			#if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
				#error unknown
			#elif BYTE_ORDER != BIG_ENDIAN
				#error little
			#endif
		}]} {
			define-feature big-endian
			msg-result "big"
			set rc 1
		} elseif {[cctest -code {
			#if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
				#error unknown
			#elif BYTE_ORDER != LITTLE_ENDIAN
				#error big
			#endif
		}]} {
			define-feature little-endian
			msg-result "little"
			set rc 1
		} else {
			msg-result "unknown"
		}
	}
	return $rc
}

# @cc-check-flags flag ?...?
#
# Checks whether the given C/C++ compiler flags can be used. Defines feature
# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
# appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
proc cc-check-flags {args} {
    set result 1
    array set opts [cc-get-settings]
    switch -exact -- $opts(-lang) {
        c++ {
            set lang C++
            set prefix CXXFLAG
        }
        c {
            set lang C
            set prefix CFLAG
        }
        default {
            autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
        }
    }
    foreach flag $args {
        msg-checking "Checking whether the $lang compiler accepts $flag..."
        if {[cctest -cflags $flag]} {
            msg-result yes
            define-feature $prefix$flag
            cc-with [list -cflags [list $flag]]
            define-append ${prefix}S $flag
        } else {
            msg-result no
            set result 0
        }
    }
    return $result
}

# @cc-check-standards ver ?...?
#
# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
# options, and appends the first working one to '-cflags' and 'CFLAGS' or
# 'CXXFLAGS'.
proc cc-check-standards {args} {
    array set opts [cc-get-settings]
    foreach std $args {
        if {[cc-check-flags -std=$std]} {
            return $std
        }
    }
    return ""
}

# Checks whether $keyword is usable as alignof
proc cctest_alignof {keyword} {
    msg-checking "Checking for $keyword..."
    if {[cctest -code [subst -nobackslashes {
        printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x'));
    }]]} then {
        msg-result ok
        define-feature $keyword
    } else {
        msg-result "not found"
    }
}

# @cc-check-c11
#
# Checks for several C11/C++11 extensions and their alternatives. Currently
# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
proc cc-check-c11 {} {
    msg-checking "Checking for _Static_assert..."
    if {[cctest -code {
        _Static_assert(1, "static assertions are available");
    }]} then {
        msg-result ok
        define-feature _Static_assert
    } else {
        msg-result "not found"
    }

    cctest_alignof _Alignof
    cctest_alignof __alignof__
    cctest_alignof __alignof
}

Added autosetup/cc-shared.tcl.

































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc-shared' module provides support for shared libraries and shared objects.
# It defines the following variables:
#
## SH_CFLAGS         Flags to use compiling sources destined for a shared library
## SH_LDFLAGS        Flags to use linking (creating) a shared library
## SH_SOPREFIX       Prefix to use to set the soname when creating a shared library
## SH_SOEXT          Extension for shared libs
## SH_SOEXTVER       Format for versioned shared libs - %s = version
## SHOBJ_CFLAGS      Flags to use compiling sources destined for a shared object
## SHOBJ_LDFLAGS     Flags to use linking a shared object, undefined symbols allowed
## SHOBJ_LDFLAGS_R   - as above, but all symbols must be resolved
## SH_LINKFLAGS      Flags to use linking an executable which will load shared objects
## LD_LIBRARY_PATH   Environment variable which specifies path to shared libraries
## STRIPLIBFLAGS     Arguments to strip to strip a dynamic library

module-options {}

# Defaults: gcc on unix
define SHOBJ_CFLAGS -fpic
define SHOBJ_LDFLAGS -shared
define SH_CFLAGS -fpic
define SH_LDFLAGS -shared
define SH_LINKFLAGS -rdynamic
define SH_SOEXT .so
define SH_SOEXTVER .so.%s
define SH_SOPREFIX -Wl,-soname,
define LD_LIBRARY_PATH LD_LIBRARY_PATH
define STRIPLIBFLAGS --strip-unneeded

# Note: This is a helpful reference for identifying the toolchain
#       http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers

switch -glob -- [get-define host] {
	*-*-darwin* {
		define SHOBJ_CFLAGS "-dynamic -fno-common"
		define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
		define SHOBJ_LDFLAGS_R -bundle
		define SH_CFLAGS -dynamic
		define SH_LDFLAGS -dynamiclib
		define SH_LINKFLAGS ""
		define SH_SOEXT .dylib
		define SH_SOEXTVER .%s.dylib
		define SH_SOPREFIX -Wl,-install_name,
		define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
		define STRIPLIBFLAGS -x
	}
	*-*-ming* - *-*-cygwin - *-*-msys {
		define SHOBJ_CFLAGS ""
		define SHOBJ_LDFLAGS -shared
		define SH_CFLAGS ""
		define SH_LDFLAGS -shared
		define SH_LINKFLAGS ""
		define SH_SOEXT .dll
		define SH_SOEXTVER .dll
		define SH_SOPREFIX ""
		define LD_LIBRARY_PATH PATH
	}
	sparc* {
		if {[msg-quiet cc-check-decls __SUNPRO_C]} {
			msg-result "Found sun stdio compiler"
			# sun stdio compiler
			# XXX: These haven't been fully tested. 
			define SHOBJ_CFLAGS -KPIC
			define SHOBJ_LDFLAGS "-G"
			define SH_CFLAGS -KPIC
			define SH_LINKFLAGS -Wl,-export-dynamic
			define SH_SOPREFIX -Wl,-h,
		} else {
			# sparc has a very small GOT table limit, so use -fPIC
			define SH_CFLAGS -fPIC
			define SHOBJ_CFLAGS -fPIC
		}
	}
	*-*-solaris* {
		if {[msg-quiet cc-check-decls __SUNPRO_C]} {
			msg-result "Found sun stdio compiler"
			# sun stdio compiler
			# XXX: These haven't been fully tested. 
			define SHOBJ_CFLAGS -KPIC
			define SHOBJ_LDFLAGS "-G"
			define SH_CFLAGS -KPIC
			define SH_LINKFLAGS -Wl,-export-dynamic
			define SH_SOPREFIX -Wl,-h,
		}
	}
	*-*-hpux {
		# XXX: These haven't been tested
		define SHOBJ_CFLAGS "+O3 +z"
		define SHOBJ_LDFLAGS -b
		define SH_CFLAGS +z
		define SH_LINKFLAGS -Wl,+s
		define LD_LIBRARY_PATH SHLIB_PATH
	}
	*-*-haiku {
		define SHOBJ_CFLAGS ""
		define SHOBJ_LDFLAGS -shared
		define SH_CFLAGS ""
		define SH_LDFLAGS -shared
		define SH_LINKFLAGS ""
		define SH_SOPREFIX ""
		define LD_LIBRARY_PATH LIBRARY_PATH
	}
}

if {![is-defined SHOBJ_LDFLAGS_R]} {
	define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
}

Added autosetup/cc.tcl.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc' module supports checking various 'features' of the C or C++
# compiler/linker environment. Common commands are cc-check-includes,
# cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
#
# The following environment variables are used if set:
#
## CC       - C compiler
## CXX      - C++ compiler
## CCACHE   - Set to "none" to disable automatic use of ccache
## CFLAGS   - Additional C compiler flags
## CXXFLAGS - Additional C++ compiler flags
## LDFLAGS  - Additional compiler flags during linking
## LIBS     - Additional libraries to use (for all tests)
## CROSS    - Tool prefix for cross compilation
#
# The following variables are defined from the corresponding
# environment variables if set.
#
## CPPFLAGS
## LINKFLAGS
## CC_FOR_BUILD
## LD

use system

module-options {}

# Note that the return code is not meaningful
proc cc-check-something {name code} {
	uplevel 1 $code
}

# Checks for the existence of the given function by linking
#
proc cctest_function {function} {
	cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
}

# Checks for the existence of the given type by compiling
proc cctest_type {type} {
	cctest -code "$type _x;"
}

# Checks for the existence of the given type/structure member.
# e.g. "struct stat.st_mtime"
proc cctest_member {struct_member} {
	lassign [split $struct_member .] struct member
	cctest -code "static $struct _s; return sizeof(_s.$member);"
}

# Checks for the existence of the given define by compiling
#
proc cctest_define {name} {
	cctest -code "#ifndef $name\n#error not defined\n#endif"
}

# Checks for the existence of the given name either as
# a macro (#define) or an rvalue (such as an enum)
#
proc cctest_decl {name} {
	cctest -code "#ifndef $name\n(void)$name;\n#endif"
}

# @cc-check-sizeof type ...
#
# Checks the size of the given types (between 1 and 32, inclusive).
# Defines a variable with the size determined, or "unknown" otherwise.
# e.g. for type 'long long', defines SIZEOF_LONG_LONG.
# Returns the size of the last type.
#
proc cc-check-sizeof {args} {
	foreach type $args {
		msg-checking "Checking for sizeof $type..."
		set size unknown
		# Try the most common sizes first
		foreach i {4 8 1 2 16 32} {
			if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
				set size $i
				break
			}
		}
		msg-result $size
		set define [feature-define-name $type SIZEOF_]
		define $define $size
	}
	# Return the last result
	get-define $define
}

# Checks for each feature in $list by using the given script.
#
# When the script is evaluated, $each is set to the feature
# being checked, and $extra is set to any additional cctest args.
#
# Returns 1 if all features were found, or 0 otherwise.
proc cc-check-some-feature {list script} {
	set ret 1
	foreach each $list {
		if {![check-feature $each $script]} {
			set ret 0
		}
	}
	return $ret
}

# @cc-check-includes includes ...
#
# Checks that the given include files can be used
proc cc-check-includes {args} {
	cc-check-some-feature $args {
		set with {}
		if {[dict exists $::autosetup(cc-include-deps) $each]} {
			set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
			msg-quiet cc-check-includes {*}$deps
			foreach i $deps {
				if {[have-feature $i]} {
					lappend with $i
				}
			}
		}
		if {[llength $with]} {
			cc-with [list -includes $with] {
				cctest -includes $each
			}
		} else {
			cctest -includes $each
		}
	}
}

# @cc-include-needs include required ...
#
# Ensures that when checking for 'include', a check is first
# made for each 'required' file, and if found, it is #included
proc cc-include-needs {file args} {
	foreach depfile $args {
		dict set ::autosetup(cc-include-deps) $file $depfile 1
	}
}

# @cc-check-types type ...
#
# Checks that the types exist.
proc cc-check-types {args} {
	cc-check-some-feature $args {
		cctest_type $each
	}
}

# @cc-check-defines define ...
#
# Checks that the given preprocessor symbol is defined
proc cc-check-defines {args} {
	cc-check-some-feature $args {
		cctest_define $each
	}
}

# @cc-check-decls name ...
#
# Checks that each given name is either a preprocessor symbol or rvalue
# such as an enum. Note that the define used for a decl is HAVE_DECL_xxx
# rather than HAVE_xxx
proc cc-check-decls {args} {
	set ret 1
	foreach name $args {
		msg-checking "Checking for $name..."
		set r [cctest_decl $name]
		define-feature "decl $name" $r
		if {$r} {
			msg-result "ok"
		} else {
			msg-result "not found"
			set ret 0
		}
	}
	return $ret
}

# @cc-check-functions function ...
#
# Checks that the given functions exist (can be linked)
proc cc-check-functions {args} {
	cc-check-some-feature $args {
		cctest_function $each
	}
}

# @cc-check-members type.member ...
#
# Checks that the given type/structure members exist.
# A structure member is of the form "struct stat.st_mtime"
proc cc-check-members {args} {
	cc-check-some-feature $args {
		cctest_member $each
	}
}

# @cc-check-function-in-lib function libs ?otherlibs?
#
# Checks that the given given function can be found in one of the libs.
#
# First checks for no library required, then checks each of the libraries
# in turn.
#
# If the function is found, the feature is defined and lib_$function is defined
# to -l$lib where the function was found, or "" if no library required.
# In addition, -l$lib is added to the LIBS define.
#
# If additional libraries may be needed for linking, they should be specified
# as $extralibs as "-lotherlib1 -lotherlib2".
# These libraries are not automatically added to LIBS.
#
# Returns 1 if found or 0 if not.
# 
proc cc-check-function-in-lib {function libs {otherlibs {}}} {
	msg-checking "Checking libs for $function..."
	set found 0
	cc-with [list -libs $otherlibs] {
		if {[cctest_function $function]} {
			msg-result "none needed"
			define lib_$function ""
			incr found
		} else {
			foreach lib $libs {
				cc-with [list -libs -l$lib] {
					if {[cctest_function $function]} {
						msg-result -l$lib
						define lib_$function -l$lib
						define-append LIBS -l$lib
						incr found
						break
					}
				}
			}
		}
	}
	if {$found} {
		define [feature-define-name $function]
	} else {
		msg-result "no"
	}
	return $found
}

# @cc-check-tools tool ...
#
# Checks for existence of the given compiler tools, taking
# into account any cross compilation prefix.
#
# For example, when checking for "ar", first AR is checked on the command
# line and then in the environment. If not found, "${host}-ar" or
# simply "ar" is assumed depending upon whether cross compiling.
# The path is searched for this executable, and if found AR is defined
# to the executable name.
# Note that even when cross compiling, the simple "ar" is used as a fallback,
# but a warning is generated. This is necessary for some toolchains.
#
# It is an error if the executable is not found.
#
proc cc-check-tools {args} {
	foreach tool $args {
		set TOOL [string toupper $tool]
		set exe [get-env $TOOL [get-define cross]$tool]
		if {[find-executable {*}$exe]} {
			define $TOOL $exe
			continue
		}
		if {[find-executable {*}$tool]} {
			msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
			define $TOOL $tool
			continue
		}
		user-error "Failed to find $exe"
	}
}

# @cc-check-progs prog ...
#
# Checks for existence of the given executables on the path.
#
# For example, when checking for "grep", the path is searched for
# the executable, 'grep', and if found GREP is defined as "grep".
#
# It the executable is not found, the variable is defined as false.
# Returns 1 if all programs were found, or 0 otherwise.
#
proc cc-check-progs {args} {
	set failed 0
	foreach prog $args {
		set PROG [string toupper $prog]
		msg-checking "Checking for $prog..."
		if {![find-executable $prog]} {
			msg-result no
			define $PROG false
			incr failed
		} else {
			msg-result ok
			define $PROG $prog
		}
	}
	expr {!$failed}
}

# Adds the given settings to $::autosetup(ccsettings) and
# returns the old settings.
#
proc cc-add-settings {settings} {
	if {[llength $settings] % 2} {
		autosetup-error "settings list is missing a value: $settings"
	}

	set prev [cc-get-settings]
	# workaround a bug in some versions of jimsh by forcing
	# conversion of $prev to a list
	llength $prev

	array set new $prev

	foreach {name value} $settings {
		switch -exact -- $name {
			-cflags - -includes {
				# These are given as lists
				lappend new($name) {*}$value
			}
			-declare {
				lappend new($name) $value
			}
			-libs {
				# Note that new libraries are added before previous libraries
				set new($name) [list {*}$value {*}$new($name)]
			}
			-link - -lang - -nooutput {
				set new($name) $value
			}
			-source - -sourcefile - -code {
				# XXX: These probably are only valid directly from cctest
				set new($name) $value
			}
			default {
				autosetup-error "unknown cctest setting: $name"
			}
		}
	}

	cc-store-settings [array get new]

	return $prev
}

proc cc-store-settings {new} {
	set ::autosetup(ccsettings) $new
}

proc cc-get-settings {} {
	return $::autosetup(ccsettings)
}

# Similar to cc-add-settings, but each given setting
# simply replaces the existing value.
#
# Returns the previous settings
proc cc-update-settings {args} {
	set prev [cc-get-settings]
	cc-store-settings [dict merge $prev $args]
	return $prev
}

# @cc-with settings ?{ script }?
#
# Sets the given 'cctest' settings and then runs the tests in 'script'.
# Note that settings such as -lang replace the current setting, while
# those such as -includes are appended to the existing setting.
#
# If no script is given, the settings become the default for the remainder
# of the auto.def file.
#
## cc-with {-lang c++} {
##   # This will check with the C++ compiler
##   cc-check-types bool
##   cc-with {-includes signal.h} {
##     # This will check with the C++ compiler, signal.h and any existing includes.
##     ...
##   }
##   # back to just the C++ compiler
## }
#
# The -libs setting is special in that newer values are added *before* earlier ones.
#
## cc-with {-libs {-lc -lm}} {
##   cc-with {-libs -ldl} {
##     cctest -libs -lsocket ...
##     # libs will be in this order: -lsocket -ldl -lc -lm
##   }
## }
proc cc-with {settings args} {
	if {[llength $args] == 0} {
		cc-add-settings $settings
	} elseif {[llength $args] > 1} {
		autosetup-error "usage: cc-with settings ?script?"
	} else {
		set save [cc-add-settings $settings]
		set rc [catch {uplevel 1 [lindex $args 0]} result info]
		cc-store-settings $save
		if {$rc != 0} {
			return -code [dict get $info -code] $result
		}
		return $result
	}
}

# @cctest ?settings?
# 
# Low level C compiler checker. Compiles and or links a small C program
# according to the arguments and returns 1 if OK, or 0 if not.
#
# Supported settings are:
#
## -cflags cflags      A list of flags to pass to the compiler
## -includes list      A list of includes, e.g. {stdlib.h stdio.h}
## -declare code       Code to declare before main()
## -link 1             Don't just compile, link too
## -lang c|c++         Use the C (default) or C++ compiler
## -libs liblist       List of libraries to link, e.g. {-ldl -lm}
## -code code          Code to compile in the body of main()
## -source code        Compile a complete program. Ignore -includes, -declare and -code
## -sourcefile file    Shorthand for -source [readfile [get-define srcdir]/$file]
## -nooutput 1         Treat any compiler output (e.g. a warning) as an error
#
# Unless -source or -sourcefile is specified, the C program looks like:
#
## #include <firstinclude>   /* same for remaining includes in the list */
##
## declare-code              /* any code in -declare, verbatim */
##
## int main(void) {
##   code                    /* any code in -code, verbatim */
##   return 0;
## }
#
# Any failures are recorded in 'config.log'
#
proc cctest {args} {
	set src conftest__.c
	set tmp conftest__

	# Easiest way to merge in the settings
	cc-with $args {
		array set opts [cc-get-settings]
	}

	if {[info exists opts(-sourcefile)]} {
		set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
	}
	if {[info exists opts(-source)]} {
		set lines $opts(-source)
	} else {
		foreach i $opts(-includes) {
			if {$opts(-code) ne "" && ![feature-checked $i]} {
				# Compiling real code with an unchecked header file
				# Quickly (and silently) check for it now

				# Remove all -includes from settings before checking
				set saveopts [cc-update-settings -includes {}]
				msg-quiet cc-check-includes $i
				cc-store-settings $saveopts
			}
			if {$opts(-code) eq "" || [have-feature $i]} {
				lappend source "#include <$i>"
			}
		}
		lappend source {*}$opts(-declare)
		lappend source "int main(void) {"
		lappend source $opts(-code)
		lappend source "return 0;"
		lappend source "}"

		set lines [join $source \n]
	}

	# Build the command line
	set cmdline {}
	lappend cmdline {*}[get-define CCACHE]
	switch -exact -- $opts(-lang) {
		c++ {
			lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
		}
		c {
			lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
		}
		default {
			autosetup-error "cctest called with unknown language: $opts(-lang)"
		}
	}

	if {!$opts(-link)} {
		set tmp conftest__.o
		lappend cmdline -c
	}
	lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""]

	lappend cmdline $src -o $tmp {*}$opts(-libs)

	# At this point we have the complete command line and the
	# complete source to be compiled. Get the result from cache if
	# we can
	if {[info exists ::cc_cache($cmdline,$lines)]} {
		msg-checking "(cached) "
		set ok $::cc_cache($cmdline,$lines)
		if {$::autosetup(debug)} {
			configlog "From cache (ok=$ok): [join $cmdline]"
			configlog "============"
			configlog $lines
			configlog "============"
		}
		return $ok
	}

	writefile $src $lines\n

	set ok 1
	set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
	if {$err || ($opts(-nooutput) && [string length $result])} {
		configlog "Failed: [join $cmdline]"
		configlog $result
		configlog "============"
		configlog "The failed code was:"
		configlog $lines
		configlog "============"
		set ok 0
	} elseif {$::autosetup(debug)} {
		configlog "Compiled OK: [join $cmdline]"
		configlog "============"
		configlog $lines
		configlog "============"
	}
	file delete $src
	file delete $tmp

	# cache it
	set ::cc_cache($cmdline,$lines) $ok

	return $ok
}

# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
#
# Deprecated - see make-config-header
proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
	user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
	make-config-header $file -auto $autopatterns -bare $barepatterns
}

# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
#
# Examines all defined variables which match the given patterns
# and writes an include file, $file, which defines each of these.
# Variables which match '-auto' are output as follows:
# - defines which have the value "0" are ignored.
# - defines which have integer values are defined as the integer value.
# - any other value is defined as a string, e.g. "value"
# Variables which match '-bare' are defined as-is.
# Variables which match '-str' are defined as a string, e.g. "value"
# Variables which match '-none' are omitted.
#
# Note that order is important. The first pattern which matches is selected
# Default behaviour is:
#
#  -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
#
# If the file would be unchanged, it is not written.
proc make-config-header {file args} {
	set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
	file mkdir [file dirname $file]
	set lines {}
	lappend lines "#ifndef $guard"
	lappend lines "#define $guard"

	# Add some defaults
	lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*

	foreach n [lsort [dict keys [all-defines]]] {
		set value [get-define $n]
		set type [calc-define-output-type $n $args]
		switch -exact -- $type {
			-bare {
				# Just output the value unchanged
			}
			-none {
				continue
			}
			-str {
				set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
			}
			-auto {
				# Automatically determine the type
				if {$value eq "0"} {
					lappend lines "/* #undef $n */"
					continue
				}
				if {![string is integer -strict $value]} {
					set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
				}
			}
			"" {
				continue
			}
			default {
				autosetup-error "Unknown type in make-config-header: $type"
			}
		}
		lappend lines "#define $n $value"
	}
	lappend lines "#endif"
	set buf [join $lines \n]
	write-if-changed $file $buf {
		msg-result "Created $file"
	}
}

proc calc-define-output-type {name spec} {
	foreach {type patterns} $spec {
		foreach pattern $patterns {
			if {[string match $pattern $name]} {
				return $type
			}
		}
	}
	return ""
}

# Initialise some values from the environment or commandline or default settings
foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
	lassign $i var default
	define $var [get-env $var $default]
}

if {[env-is-set CC]} {
	# Set by the user, so don't try anything else
	set try [list [get-env CC ""]]
} else {
	# Try some reasonable options
	set try [list [get-define cross]cc [get-define cross]gcc]
}
define CC [find-an-executable {*}$try]
if {[get-define CC] eq ""} {
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

define CPP [get-env CPP "[get-define CC] -E"]

# XXX: Could avoid looking for a C++ compiler until requested
# Note that if CXX isn't found, we just set it to "false". It might not be needed.
if {[env-is-set CXX]} {
	define CXX [find-an-executable -required [get-env CXX ""]]
} else {
	define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
}

# CXXFLAGS default to CFLAGS if not specified
define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]

# May need a CC_FOR_BUILD, so look for one
define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]

if {[get-define CC] eq ""} {
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

define CCACHE [find-an-executable [get-env CCACHE ccache]]

# Initial cctest settings
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
set autosetup(cc-include-deps) {}

msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
if {[get-define CXX] ne "false"} {
	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"

# On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
# but some compilers may not support it, so test here.
switch -glob -- [get-define host] {
	*-*-darwin* {
		if {[cctest -cflags {-g0}]} {
			define cc-default-debug -g0
		}
	}
}

if {![cc-check-includes stdlib.h]} {
	user-error "Compiler does not work. See config.log"
}

Added autosetup/codebale.tcl.































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
###
# codebale.tcl
#
# This file defines routines used to bundle and manage Tcl and C
# code repositories
#
# Copyright (c) 2014 Sean Woods
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
###
#::namespace eval ::codebale {}

# @synopsis:
#
# CODEBALE modules adds autobuild utilities
#

set col 0
use fileutil

###
# topic: e1d75c45e58cc525a0a70ce6f767717c
###
proc codebale_isdirectory name {
  return [file isdirectory $name]
}

###
# topic: d0663852b31759ce78f33cbc63379d84
###
proc codebale_istcl name {
  return [string match *.tcl $name]
}

###
# topic: ea4ac0a84ae990dafee965b995f48e63
###
proc codebale_istm name {
  return [string match *.tm $name]
}

###
# topic: ec0fd469c986351ea0d5a287d6f040d8
###
proc codebale_cases_finalize f {
  global col
  if {$col>0} {puts $f {}}
  set col 0
}

###
# topic: 78728b1f05577d4bc1276e7294ff2cc7
###
proc codebale_cases_generate {prefix cases} {
  global col
  set col 0
  set f [open [file join $::project(path) build [string tolower ${prefix}_cases].h] w]
  fconfigure $f -translation crlf
  puts $f $::project(standard_header)
  puts $f "  const static char *${prefix}_strs\[\] = \173"
  set lx [lsort  $cases]
  foreach item $lx {
    cases_put $f \"[string tolower $item]\",
  }
  cases_put $f 0
  cases_finalize $f
  puts $f "  \175;"
  puts $f "  enum ${prefix}_enum \173"
  foreach name $lx {
    regsub -all {@} $name {} name
    cases_put $f ${prefix}_[string toupper $name],
  }
  cases_finalize $f
  puts $f "  \175;"
  puts $f "\
  int index;
  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, \"METHOD ?ARG ...?\");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv\[1\], ${prefix}_strs,\
            \"option\", 0, &index)){
    return TCL_ERROR;
  }
  switch( (enum ${prefix}_enum)index )"
  close $f
}

###
# topic: 545596e62faedfeda638c8bb703882b1
###
proc codebale_cases_put {f x} {
  global col
  if {$col==0} {puts -nonewline $f "   "}
  if {$col<2} {
    puts -nonewline $f [format " %-21s" $x]
    incr col
  } else {
    puts $f $x
    set col 0
  }
}

###
# topic: 9dd91e4b98b001260e30671883da494b
# description: Generate function declarations
###
proc codebale_headers_csourcefile file {  
  ###
  # Skip huge files
  ###
  if {[file size $file] > 500000} {return {}}
  set fin [open $file r]
  set dat [read $fin]
  close $fin
  set result [digest_csource $dat]
  set functions {}
  if [catch {
  foreach {funcname info} [lsort  -stride 2 [dictGetnull $result function]] {
    dict with info {
      if { "static" in $keywords } continue
      append functions "$keywords $funcname\([join $arglist ", "]\)\x3b" \n
    }
  }
  } err] {
    puts "ERROR Parsing $file: $err"
    return "/*
** $file
** Process cancelled because of errors
** $err
** Line number: $::readinglinenumber
** Line: $::readingline
*/
"
  }
  return $functions
}

###
# topic: c0304a049be6f31206a02d15813720ce
###
proc codebale_meta_output outfile {
  set fout [open $outfile w]
  puts "SAVING TO $outfile"
  
  #puts $fout "array set filemd5 \x7b"
  #array set temp [array get ::filemd5]
  #foreach {file md5} [lsort  [array names temp]] {
  #  set md5 $temp($file)
  #  puts $fout "    [list $file $md5]"
  #}
  #array unset temp
  #puts $fout "\x7d"
  puts $fout "helpdoc eval {begin transaction}"
  helpdoc eval {
    select handle,localpath from repository
  } {
    puts $fout [list ::helpdoc repository_restore $handle [list localpath $localpath]]
  }
  helpdoc eval {
    select hash,fileid from file
  } {
    puts $fout [helpdoc file_serialize $fileid]
  }
  puts $fout [helpdoc node_serialize 0]
  helpdoc eval {
    select entryid from entry
    where class='section'
    order by name
  } {
    puts $fout [helpdoc node_serialize $entryid]
  }
  helpdoc eval {
    select entryid from entry
    where class!='section'
    order by parent,class,name
  } {
    puts $fout [helpdoc node_serialize $entryid]
  }
  puts $fout "helpdoc eval {commit}"
  close $fout
}

###
# topic: cd6e815c2e68b751656a4c9bbe8918dd
# description: Filters extranous fields from meta data
###
proc codebale_meta_scrub {aliases info} {
  foreach {c alist} $aliases {
    foreach a $alist {
      set canonical($a) $c
    }
  }

  set outfo {}
  foreach {field val} $info {
    if {[info exists canonical($field)]} {
      set cname $canonical($field)
    } else {
      set cname $field
    }
    if {$cname eq {}} continue
    if {[string length [string trim $val]]} {
      dict set outfo $cname $val
    }
  }
  return $outfo
}

###
# topic: 51380132b6f872ed01830e34431931d4
###
proc codebale_pkg_mkIndex base {
  set stack {}
  if {[file exists [file join $base pkgIndex.tcl]]} {
    return
    #file delete [file join $base pkgIndex.tcl]
  }
  set fout [open [file join $base pkgIndex.tcl.new] w]
  fconfigure $fout -translation crlf

  set result [::codebale_sniffPath $base stack]
  
  puts $fout {# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
  }
  
  while {[llength $stack]} {
    set stackpath [lindex $stack 0]
    set stack [lrange $stack 1 end]
    foreach {type file} [::codebale_sniffPath $stackpath stack] { 
      lappend result $type $file
    }
  }
  set i [string length $base]
  foreach {type file} $result {
      switch $type {
          module {
              set fname [file rootname [file tail $file]]
              set package [lindex [split $fname -] 0]
              set version [lindex [split $fname -] 1]
              set dir [string trimleft [string range [file dirname $file] $i end] /]
              puts $fout "package ifneeded $package $version \[list source \[file join \$dir $dir [file tail $file]\]\]"
              #::codebale_read_tclsourcefile $file
          }
          source {
              if { $file == "$base/pkgIndex.tcl" } continue
              if { $file == "$base/packages.tcl" } continue
              if { $file == "$base/main.tcl" } continue
              if { [file tail $file] == "version_info.tcl" } continue
              set fin [open $file r]
              set dat [read $fin]
              close $fin
              if {[regexp "package provide" $dat]} {
                 set fname [file rootname [file tail $file]]
  
                 set dir [string trimleft [string range [file dirname $file] $i end] /]
              
                 foreach line [split $dat \n] {
                    set line [string trim $line]
                    
                    if { [string range $line 0 14] != "package provide" } continue
                    set package [lindex $line 2]
                    set version [lindex $line 3]
                    if { $dir eq {} } {
                      puts $fout "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]"                      
                    } else {
                      puts $fout "package ifneeded $package $version \[list source \[file join \$dir $dir [file tail $file]\]\]"
                    }
                    break
                 }
              }
              #::codebale_read_tclsourcefile $file
          }
      }
  }
  close $fout
  file rename -force [file join $base pkgIndex.tcl.new] [file join $base pkgIndex.tcl]
}

###
# topic: 924caf1f68529d8dbc329b85e391a1c1
###
proc codebale_pkgindex_manifest base {
  set stack {}
  set output {}
  set base [file-normalize $base]
  set i    [string length  $base]

  foreach {file} [fileutil_find $base codebale_istm] {
    set file [file-normalize $file]
    set fname [file rootname [file tail $file]]
    ###
    # Assume the package is correct in the filename
    ###
    set package [lindex [split $fname -] 0]
    set version [lindex [split $fname -] 1]
    set path [string trimleft [string range [file dirname $file] $i end] /]
    ###
    # Read the file, and override assumptions as needed
    ###
    set fin [open $file r]
    set dat [read $fin]
    close $fin
    foreach line [split $dat \n] {
      set line [string trim $line]
      if { [string range $line 0 9] != "# Package " } continue
      set package [lindex $line 2]
      set version [lindex $line 3]
      break
    }
    lappend output $package $version
  }
  foreach {file} [fileutil_find $base codebale_istcl] {
    set file [file-normalize $file]
    set fin [open $file r]
    set dat [read $fin]
    close $fin
    if {![regexp "package provide" $dat]} continue
    set fname [file rootname [file tail $file]]
    set dir [string trimleft [string range [file dirname $file] $i end] /]
    
    foreach line [split $dat \n] {
      set line [string trim $line]              
      if { [string range $line 0 14] != "package provide" } continue
      set package [lindex $line 2]
      set version [lindex $line 3]
      lappend output $package $version
      break
    }
  }
  return $output
}

###
# topic: 929629f0ebaa554710f66410dfa51f8a
###
proc codebale_pkgindex_path base {
  set stack {}
  set buffer {
lappend ::PATHSTACK $dir
  }
  set base [file-normalize $base]
  set i    [string length  $base]
  # Build a list of all of the paths
  set paths [fileutil_find $base codebale_isdirectory]
  
  foreach path $paths {
    if {$path eq $base} continue
    set path_indexed($path) 0
    foreach idxname {pkgIndex.tcl} {
      if {[file exists [file join $path $idxname]]} {
        incr path_indexed($path)
        set dir [string trimleft [string range $path $i end] /]
        append buffer "
set dir \[file join \[lindex \$::PATHSTACK end\] $dir\] \; source \[file join \[lindex \$::PATHSTACK end\] $dir $idxname\]
"
        append buffer \n
      }
    }
  }

  foreach path $paths {
    if {$path_indexed($path)} continue
    foreach file [glob -nocomplain $path/*.tm] {
      set file [file-normalize $file]
      set fname [file rootname [file tail $file]]
      ###
      # Assume the package is correct in the filename
      ###
      set package [lindex [split $fname -] 0]
      set version [lindex [split $fname -] 1]
      set path [string trimleft [string range [file dirname $file] $i end] /]
      ###
      # Read the file, and override assumptions as needed
      ###
      set fin [open $file r]
      set dat [read $fin]
      close $fin
      foreach line [split $dat \n] {
        set line [string trim $line]
        if { [string range $line 0 9] != "# Package " } continue
        set package [lindex $line 2]
        set version [lindex $line 3]
        break
      }
      append buffer "package ifneeded $package $version \[list source \[file join \[lindex \$::PATHSTACK end\] $path [file tail $file]\]\]"
      append buffer \n
    }
    foreach file [glob -nocomplain $path/*.tcl] {
      set file [file-normalize $file]
      if { $file == [file join $base tcl8.6 package.tcl] } continue
      if { $file == [file join $base packages.tcl] } continue
      if { $file == [file join $base main.tcl] } continue
      if { [file tail $file] == "version_info.tcl" } continue
      set fin [open $file r]
      set dat [read $fin]
      close $fin
      if {![regexp "package provide" $dat]} continue
      set fname [file rootname [file tail $file]]
      set dir [string trimleft [string range [file dirname $file] $i end] /]
      
      foreach line [split $dat \n] {
        set line [string trim $line]              
        if { [string range $line 0 14] != "package provide" } continue
        set package [lindex $line 2]
        set version [lindex $line 3]
        append buffer "package ifneeded $package $version \[list source \[file join \[lindex \$::PATHSTACK end\] $dir [file tail $file]\]\]"
        append buffer \n
        break
      }
    }
  }
  append buffer {
set dir [lindex $::PATHSTACK end]  
set ::PATHSTACK [lrange $::PATHSTACK 0 end-1]
}
  return $buffer
}

###
# topic: 3a00781665184d1efb9e292dbdd1b35c
# title: Read the contents of an rc conf file
# description:
#    This style of conf file is assumed to contain lines formatted
#    set VARNAME VALUE
###
proc codebale_read_rc_file fname {
  if {![file exists $fname]} {
    return {}
  }
  if {![catch {source $fname} err]} {
    # Could read as a Tcl file
    # Fill the result with the contents of
    # all of the local variables defined by
    # that file
    set vars [info vars]
    ldelete vars fname
    foreach var $vars {
      dict set result $var [set $var]
    }
    return $result
  }
  # Parse the file the hard way...
  set fin [open $fname r]
  set thisline {}
  while {[gets $fin line] >= 0} {
    set line [string trim $line]
    if {[string index $line 0] eq "#"} continue
    append thisline \n $line
    if {![info complete $thisline]} continue
    # Remove leading \n
    set thisline [string trimleft $thisline]
    if {[string range $line 0 2] == "set"} {
      dict set result [lindex $line 1] [lindex $line 2]
    } else {
      if {[llength $line] eq 2} {
        dict set result [lindex $line 0] [lindex $line 1]
      }
    }
  }
  return $result
}

###
# topic: cbb00d37108708e5968c8a38f73ec38a
###
proc codebale_read_sh_file {filename {localdat {}}} {
  set fin [open $filename r]
  set result {}
  if {$localdat eq {}} {
    set top 1
    set local [array get ::env]
    dict set local EXE {}
  } else {
    set top 0
    set local $localdat
  }
  while {[gets $fin line] >= 0} {
    set line [string trim $line]
    if {[string index $line 0] eq "#"} continue
    if {$line eq {}} continue
    catch {
    if {[string range $line 0 6] eq "export "} {
      set eq [string first "=" $line]
      set field [string trim [string range $line 6 [expr {$eq - 1}]]]
      set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local]
      dict set result $field [read_sh_subst $value $local]
      dict set local $field $value
    } elseif {[string range $line 0 7] eq "include "} {
      set subfile [read_sh_subst [string range $line 7 end] $local]
      foreach {field value} [read_sh_file $subfile $local] {
        dict set result $field $value
      }
    } else {
      set eq [string first "=" $line]
      if {$eq > 0} {
        set field [read_sh_subst [string range $line 0 [expr {$eq - 1}]] $local]
        set value [string trim [string range $line [expr {$eq+1}] end] ']
        #set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local]
        dict set local $field $value
        dict set result $field $value
      }
    }
    } err opts
    if {[dict get $opts -code] != 0} {
      #puts $opts
      puts "Error reading line:\n$line\nerr: $err\n***"
      return $err {*}$opts
    }
  }
  return $result
}

###
# topic: 22c2e7ae33fbe0d87784ca9b16df0de4
# description: Converts a XXX.sh file into a series of Tcl variables
###
proc codebale_read_sh_subst {line info} {
  regsub -all {\x28} $line \x7B line
  regsub -all {\x29} $line \x7D line

  #set line [string map $key [string trim $line]]
  foreach {field value} $info {
    catch {set $field $value}
  }
  if [catch {subst $line} result] {
    return {}
  }
  set result [string trim $result]
  return [string trim $result ']
}

###
# topic: 45a5b1e3f8a8372363f1670642972c62
###
proc codebale_shlib_fname {os pkgname pkgvers} {
  if { $os eq "windows" } {
    return lib${pkgname}[string map {. {}} ${pkgvers}].dll
    
  } else {
    switch $os {
      macosx {
        set suffix .dylib
      }
      default {
        set suffix .so
      }
    }
    return lib${pkgname}${pkgvers}$suffix
  }
}

proc realpath path {
  if { !$::odie(windows) } {
    return $path
  }
  if {[string index $path 0] eq "/" && [string index $path 2] eq "/"} {
    return [string index $path 1]:[string range $path 2 end]
  }
  return $path
}

proc cygpath path {
  if { !$::odie(windows) } {
    return $path
  }
  if {[string index $path 1] != ":" } { 
    return $path
  }
  set path [file-normalize $path]
  return /[string tolower [string index $path 0]][string range $path 2 end]
}

proc cygrelative {base filename} {
  set base [::cygpath $base]
  set filename [::cygpath $filename]
  return [::fileutil_relative $base $filename]
}

###
# topic: a5992c7f8340ba02d40e386aac95b1b8
# description: Records an alias for a Tcl keyword
###
proc codebale_alias {alias cname} {
  global cnames
  set cnames($alias) $cname
}

###
# topic: 0e883f3583c0ccd3eddc6b297ac2ea77
###
proc codebale_buffer_append {varname args} {
  upvar 1 $varname result
  if {![info exists result]} {
    set result {}    
  }
  if {[string length $result]} {
    set result [string trimright $result \n]
    append result \n
  }
  set priorarg {}
  foreach arg $args {
    if {[string length [string trim $arg]]==0} continue
    #if {[string match $arg $priorarg]} continue
    set priorarg $arg
    append result \n [string trim $arg \n] \n
  }
  set result [string trim $result \n]
  append result \n
  return $result
}

###
# topic: 926c564aa67884986f7489f37da3fb32
###
proc codebale_buffer_merge args {
  set result {}
  set priorarg {}
  foreach arg $args {
    if {[string length [string trim $arg]]==0} continue
    if {[string match $arg $priorarg]} continue
    set priorarg $arg
    append result [string trim $arg \n] \n
  }
  set result [string trim $result \n]
  return $result
}

###
# topic: c1e66f4a20e397a5d2541714575c165f
###
proc codebale_buffer_puts {varname args} {
  upvar 1 $varname result
  if {![info exists result]} {
    set result {}    
  }
  set result [string trimright $result \n]
  #if {[string length $result]} {
  #  set result [string trimright $result \n]
  #}
  set priorarg {}
  foreach arg $args {
    #if {[string length [string trim $arg]]==0} continue
    #if {[string match $arg $priorarg]} continue
    #set priorarg $arg
    append result \n $arg
    #[string trim $arg \n]
  }
  #set result [string trim $result \n]
  #append result \n
  return $result
}

###
# topic: 951f31f2cb24992f34d97e3deb16b43f
# description: Reports back the canonical name of a tcl keyword
###
proc codebale_canonical alias {
  global cnames
  if {[info exists cnames($alias)]} {
    return $cnames($alias)
  }
  return $alias
}

proc codebale_detect_cases_put_item {f x} {
  upvar 1 col col
  if {$col==0} {puts -nonewline $f "   "}
  if {$col<2} {
    puts -nonewline $f [format " %-21s" $x]
    incr col
  } else {
    puts $f $x
    set col 0
  }
}

proc codebale_detect_cases_finalize {f} {
  upvar 1 col col
  if {$col>0} {puts $f {}}
  set col 0
}

###
# topic: aacfe07625f74f93dada2159f53fca32
###
proc codebale_detect_cases cfile {
  set dirname [file dirname $cfile]
  set fin [open $cfile r]
  while {[gets $fin line] >= 0} {
    if {[regexp {^ *case *([A-Z]+)_([A-Z0-9_]+):} $line all prefix label]} {
      lappend cases($prefix) $label
    }
  }
  close $fin

  set col 0
  
  foreach prefix [array names cases] {
    set hfile [file join $dirname [string tolower $prefix]_cases.h]
    if {[file exists $hfile] && [file mtime $hfile]>[file mtime $cfile]} continue
    set f [open $hfile w]
    fconfigure $f -translation crlf
    puts $f "/*** Automatically Generated Header File - Do Not Edit ***/"
    puts $f "  const static char *${prefix}_strs\[\] = \173"
    set lx [lsort  $cases($prefix)]
    foreach item $lx {
      codebale_detect_cases_put_item $f \"[string tolower $item]\",
    }
    codebale_detect_cases_put_item $f 0
    codebale_detect_cases_finalize $f
    puts $f "  \175;"
    puts $f "  enum ${prefix}_enum \173"
    foreach name $lx {
      regsub -all {@} $name {} name
      codebale_detect_cases_put_item $f ${prefix}_[string toupper $name],
    }
    codebale_detect_cases_finalize $f
    puts $f "  \175;"
    puts $f "\
  int index;
  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, \"METHOD ?ARG ...?\");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv\[1\], ${prefix}_strs,\
            \"option\", 0, &index)){
    return TCL_ERROR;
  }
  switch( (enum ${prefix}_enum)index )"
    close $f
  }
  set result {}
  foreach item [array names cases] {
    lappend result [string tolower ${item}_cases.h]
  }
  return $result
}

###
# topic: 003ce0c0d69b74076e8433492deac920
# description:
#    Descends into a directory structure, returning
#    a list of items found in the form of:
#    type object
#    where type is one of: csource source parent_name
#    and object is the full path to the file
###
proc codebale_sniffPath {spath stackvar} {
  upvar 1 $stackvar stack    
  set result {}
  if { ![file isdirectory $spath] } {
    switch [file extension $spath] {
      .tm {
        return [list parent_name $spath]
      }
      .tcl {
        return [list source $spath]
      }
      .h {
        return [list cheader $spath]
      }
      .c {
        return [list csource $spath]
      }
    }    
    return
  }
  foreach f [glob -nocomplain $spath/*] {
    if {[file isdirectory $f]} {
      if {[file tail $f] in {CVS build} } continue
      if {[file extension $f] eq ".vfs" } continue
      set stack [linsert $stack 0 $f]
    }
  }
  set idx 0
  foreach idxtype {
    pkgIndex.tcl tclIndex
  } {
    if {[file exists [file join $spath $idxtype]]} {
      lappend result index [file join $spath $idxtype]
    }
  }
  if {[llength $result]} {
    return $result
  }
  foreach f [glob -nocomplain $spath/*] {
    if {![file isdirectory $f]} {
      set stack [linsert $stack 0 $f]
    }
  }
  return {}
}


# [dictGetnull] is like [dict get] but returns empty string for missing keys.
proc dictGetnull {dictionary args} {
  if {[dict exists $dictionary {*}$args]} {
    dict get $dictionary {*}$args
  }
}

#namespace ensemble configure dict -map [dict replace\
#    [namespace ensemble configure dict -map] getnull ::tcl::dict::getnull]

if {[info command ::ldelete] eq {}} {
proc ldelete {varname args} {
  upvar 1 $varname var
  if ![info exists var] {
      return
  }
  foreach item [lsort -unique $args] {
    while {[set i [lsearch $var $item]]>=0} {
      set var [lreplace $var $i $i]
    }
  }
  return $var
}  
}


###
# topic: 5b6897b1d60450332ff9f389b5ca952d
###
proc doexec args {
  exec {*}$args >&@ stdout
}

# Simpler version without the substitution
proc read_Config.sh {filename} {
  set fin [open $filename r]
  set result {}
  while {[gets $fin line] >= 0} {
    set line [string trim $line]
    if {[string index $line 0] eq "#"} continue
    if {$line eq {}} continue
    catch {
      set eq [string first "=" $line]
      if {$eq > 0} {
        set field [string range $line 0 [expr {$eq - 1}]]
        set value [string trim [string range $line [expr {$eq+1}] end] ']
        #set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local]
        dict set result $field $value
      }
    } err opts
    if {[dict get $opts -code] != 0} {
      #puts $opts
      puts "Error reading line:\n$line\nerr: $err\n***"
      return $err {*}$opts
    }
  }
  return $result
}

Added autosetup/config.guess.















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
#! /bin/sh
# Attempt to guess a canonical system name.
#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
#   Free Software Foundation, Inc.

timestamp='2010-09-24'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.


# Originally written by Per Bothner.  Please send patches (context
# diff format) to <[email protected]> and include a ChangeLog
# entry.
#
# This script attempts to guess a canonical system name similar to
# config.sub.  If it succeeds, it prints the system name on stdout, and
# exits with 0.  Otherwise, it exits with 1.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION]

Output the configuration name of the system \`$me' is run on.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to <[email protected]>."

version="\
GNU config.guess ($timestamp)

Originally written by Per Bothner.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help" >&2
       exit 1 ;;
    * )
       break ;;
  esac
done

if test $# != 0; then
  echo "$me: too many arguments$help" >&2
  exit 1
fi

trap 'exit 1' HUP INT TERM

# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.

# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.

# Portable tmp directory creation inspired by the Autoconf team.

set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" HUP INT PIPE TERM ;
: ${TMPDIR=/tmp} ;
 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
 { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
case $CC_FOR_BUILD,$HOST_CC,$CC in
 ,,)    echo "int x;" > $dummy.c ;
	for c in cc gcc c89 c99 ; do
	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
	     CC_FOR_BUILD="$c"; break ;
	  fi ;
	done ;
	if test x"$CC_FOR_BUILD" = x ; then
	  CC_FOR_BUILD=no_compiler_found ;
	fi
	;;
 ,,*)   CC_FOR_BUILD=$CC ;;
 ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
esac ; set_cc_for_build= ;'

# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# ([email protected] 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
	PATH=$PATH:/.attbin ; export PATH
fi

UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown

# Note: order is significant - the case branches are not exclusive.

case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
    *:NetBSD:*:*)
	# NetBSD (nbsd) targets should (where applicable) match one or
	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
	# switched to ELF, *-*-netbsd* would select the old
	# object file format.  This provides both forward
	# compatibility and a consistent mechanism for selecting the
	# object file format.
	#
	# Note: NetBSD doesn't particularly care about the vendor
	# portion of the name.  We always set it to "unknown".
	sysctl="sysctl -n hw.machine_arch"
	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
	case "${UNAME_MACHINE_ARCH}" in
	    armeb) machine=armeb-unknown ;;
	    arm*) machine=arm-unknown ;;
	    sh3el) machine=shl-unknown ;;
	    sh3eb) machine=sh-unknown ;;
	    sh5el) machine=sh5le-unknown ;;
	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
	esac
	# The Operating System including object format, if it has switched
	# to ELF recently, or will in the future.
	case "${UNAME_MACHINE_ARCH}" in
	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
		eval $set_cc_for_build
		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
			| grep -q __ELF__
		then
		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
		    # Return netbsd for either.  FIX?
		    os=netbsd
		else
		    os=netbsdelf
		fi
		;;
	    *)
	        os=netbsd
		;;
	esac
	# The OS release
	# Debian GNU/NetBSD machines have a different userland, and
	# thus, need a distinct triplet. However, they do not need
	# kernel version information, so it can be replaced with a
	# suitable tag, in the style of linux-gnu.
	case "${UNAME_VERSION}" in
	    Debian*)
		release='-gnu'
		;;
	    *)
		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
		;;
	esac
	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
	# contains redundant information, the shorter form:
	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
	echo "${machine}-${os}${release}"
	exit ;;
    *:OpenBSD:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
	exit ;;
    *:ekkoBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
	exit ;;
    *:SolidBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
	exit ;;
    macppc:MirBSD:*:*)
	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    *:MirBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    alpha:OSF1:*:*)
	case $UNAME_RELEASE in
	*4.0)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
		;;
	*5.*)
	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
		;;
	esac
	# According to Compaq, /usr/sbin/psrinfo has been available on
	# OSF/1 and Tru64 systems produced since 1995.  I hope that
	# covers most systems running today.  This code pipes the CPU
	# types through head -n 1, so we only detect the type of CPU 0.
	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
	case "$ALPHA_CPU_TYPE" in
	    "EV4 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "EV4.5 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "LCA4 (21066/21068)")
		UNAME_MACHINE="alpha" ;;
	    "EV5 (21164)")
		UNAME_MACHINE="alphaev5" ;;
	    "EV5.6 (21164A)")
		UNAME_MACHINE="alphaev56" ;;
	    "EV5.6 (21164PC)")
		UNAME_MACHINE="alphapca56" ;;
	    "EV5.7 (21164PC)")
		UNAME_MACHINE="alphapca57" ;;
	    "EV6 (21264)")
		UNAME_MACHINE="alphaev6" ;;
	    "EV6.7 (21264A)")
		UNAME_MACHINE="alphaev67" ;;
	    "EV6.8CB (21264C)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8AL (21264B)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8CX (21264D)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.9A (21264/EV69A)")
		UNAME_MACHINE="alphaev69" ;;
	    "EV7 (21364)")
		UNAME_MACHINE="alphaev7" ;;
	    "EV7.9 (21364A)")
		UNAME_MACHINE="alphaev79" ;;
	esac
	# A Pn.n version is a patched version.
	# A Vn.n version is a released version.
	# A Tn.n version is a released field test version.
	# A Xn.n version is an unreleased experimental baselevel.
	# 1.2 uses "1.2" for uname -r.
	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
	exit ;;
    Alpha\ *:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# Should we change UNAME_MACHINE based on the output of uname instead
	# of the specific Alpha model?
	echo alpha-pc-interix
	exit ;;
    21064:Windows_NT:50:3)
	echo alpha-dec-winnt3.5
	exit ;;
    Amiga*:UNIX_System_V:4.0:*)
	echo m68k-unknown-sysv4
	exit ;;
    *:[Aa]miga[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-amigaos
	exit ;;
    *:[Mm]orph[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-morphos
	exit ;;
    *:OS/390:*:*)
	echo i370-ibm-openedition
	exit ;;
    *:z/VM:*:*)
	echo s390-ibm-zvmoe
	exit ;;
    *:OS400:*:*)
        echo powerpc-ibm-os400
	exit ;;
    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
	echo arm-acorn-riscix${UNAME_RELEASE}
	exit ;;
    arm:riscos:*:*|arm:RISCOS:*:*)
	echo arm-unknown-riscos
	exit ;;
    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
	echo hppa1.1-hitachi-hiuxmpp
	exit ;;
    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
	# [email protected] (Earle F. Ake) contributed MIS and NILE.
	if test "`(/bin/universe) 2>/dev/null`" = att ; then
		echo pyramid-pyramid-sysv3
	else
		echo pyramid-pyramid-bsd
	fi
	exit ;;
    NILE*:*:*:dcosx)
	echo pyramid-pyramid-svr4
	exit ;;
    DRS?6000:unix:4.0:6*)
	echo sparc-icl-nx6
	exit ;;
    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
	case `/usr/bin/uname -p` in
	    sparc) echo sparc-icl-nx7; exit ;;
	esac ;;
    s390x:SunOS:*:*)
	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4H:SunOS:5.*:*)
	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
	echo i386-pc-auroraux${UNAME_RELEASE}
	exit ;;
    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
	eval $set_cc_for_build
	SUN_ARCH="i386"
	# If there is a compiler, see if it is configured for 64-bit objects.
	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
	# This test works for both compilers.
	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
		grep IS_64BIT_ARCH >/dev/null
	    then
		SUN_ARCH="x86_64"
	    fi
	fi
	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:6*:*)
	# According to config.sub, this is the proper way to canonicalize
	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
	# it's likely to be more like Solaris than SunOS4.
	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:*:*)
	case "`/usr/bin/arch -k`" in
	    Series*|S4*)
		UNAME_RELEASE=`uname -v`
		;;
	esac
	# Japanese Language versions have a version number like `4.1.3-JL'.
	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
	exit ;;
    sun3*:SunOS:*:*)
	echo m68k-sun-sunos${UNAME_RELEASE}
	exit ;;
    sun*:*:4.2BSD:*)
	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
	case "`/bin/arch`" in
	    sun3)
		echo m68k-sun-sunos${UNAME_RELEASE}
		;;
	    sun4)
		echo sparc-sun-sunos${UNAME_RELEASE}
		;;
	esac
	exit ;;
    aushp:SunOS:*:*)
	echo sparc-auspex-sunos${UNAME_RELEASE}
	exit ;;
    # The situation for MiNT is a little confusing.  The machine name
    # can be virtually everything (everything which is not
    # "atarist" or "atariste" at least should have a processor
    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
    # to the lowercase version "mint" (or "freemint").  Finally
    # the system name "TOS" denotes a system which is actually not
    # MiNT.  But MiNT is downward compatible to TOS, so this should
    # be no problem.
    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
        echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
        exit ;;
    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
        echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
        echo m68k-milan-mint${UNAME_RELEASE}
        exit ;;
    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
        echo m68k-hades-mint${UNAME_RELEASE}
        exit ;;
    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
        echo m68k-unknown-mint${UNAME_RELEASE}
        exit ;;
    m68k:machten:*:*)
	echo m68k-apple-machten${UNAME_RELEASE}
	exit ;;
    powerpc:machten:*:*)
	echo powerpc-apple-machten${UNAME_RELEASE}
	exit ;;
    RISC*:Mach:*:*)
	echo mips-dec-mach_bsd4.3
	exit ;;
    RISC*:ULTRIX:*:*)
	echo mips-dec-ultrix${UNAME_RELEASE}
	exit ;;
    VAX*:ULTRIX*:*:*)
	echo vax-dec-ultrix${UNAME_RELEASE}
	exit ;;
    2020:CLIX:*:* | 2430:CLIX:*:*)
	echo clipper-intergraph-clix${UNAME_RELEASE}
	exit ;;
    mips:*:*:UMIPS | mips:*:*:RISCos)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
#ifdef __cplusplus
#include <stdio.h>  /* for printf() prototype */
	int main (int argc, char *argv[]) {
#else
	int main (argc, argv) int argc; char *argv[]; {
#endif
	#if defined (host_mips) && defined (MIPSEB)
	#if defined (SYSTYPE_SYSV)
	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_SVR4)
	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
	#endif
	#endif
	  exit (-1);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c &&
	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
	  SYSTEM_NAME=`$dummy $dummyarg` &&
	    { echo "$SYSTEM_NAME"; exit; }
	echo mips-mips-riscos${UNAME_RELEASE}
	exit ;;
    Motorola:PowerMAX_OS:*:*)
	echo powerpc-motorola-powermax
	exit ;;
    Motorola:*:4.3:PL8-*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:Power_UNIX:*:*)
	echo powerpc-harris-powerunix
	exit ;;
    m88k:CX/UX:7*:*)
	echo m88k-harris-cxux7
	exit ;;
    m88k:*:4*:R4*)
	echo m88k-motorola-sysv4
	exit ;;
    m88k:*:3*:R3*)
	echo m88k-motorola-sysv3
	exit ;;
    AViiON:dgux:*:*)
        # DG/UX returns AViiON for all architectures
        UNAME_PROCESSOR=`/usr/bin/uname -p`
	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
	then
	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
	       [ ${TARGET_BINARY_INTERFACE}x = x ]
	    then
		echo m88k-dg-dgux${UNAME_RELEASE}
	    else
		echo m88k-dg-dguxbcs${UNAME_RELEASE}
	    fi
	else
	    echo i586-dg-dgux${UNAME_RELEASE}
	fi
 	exit ;;
    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
	echo m88k-dolphin-sysv3
	exit ;;
    M88*:*:R3*:*)
	# Delta 88k system running SVR3
	echo m88k-motorola-sysv3
	exit ;;
    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
	echo m88k-tektronix-sysv3
	exit ;;
    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
	echo m68k-tektronix-bsd
	exit ;;
    *:IRIX*:*:*)
	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
	exit ;;
    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
    i*86:AIX:*:*)
	echo i386-ibm-aix
	exit ;;
    ia64:AIX:*:*)
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:2:3)
	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
		eval $set_cc_for_build
		sed 's/^		//' << EOF >$dummy.c
		#include <sys/systemcfg.h>

		main()
			{
			if (!__power_pc())
				exit(1);
			puts("powerpc-ibm-aix3.2.5");
			exit(0);
			}
EOF
		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
		then
			echo "$SYSTEM_NAME"
		else
			echo rs6000-ibm-aix3.2.5
		fi
	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
		echo rs6000-ibm-aix3.2.4
	else
		echo rs6000-ibm-aix3.2
	fi
	exit ;;
    *:AIX:*:[4567])
	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
		IBM_ARCH=rs6000
	else
		IBM_ARCH=powerpc
	fi
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:*:*)
	echo rs6000-ibm-aix
	exit ;;
    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
	echo romp-ibm-bsd4.4
	exit ;;
    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
	exit ;;                             # report: romp-ibm BSD 4.3
    *:BOSX:*:*)
	echo rs6000-bull-bosx
	exit ;;
    DPX/2?00:B.O.S.:*:*)
	echo m68k-bull-sysv3
	exit ;;
    9000/[34]??:4.3bsd:1.*:*)
	echo m68k-hp-bsd
	exit ;;
    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
	echo m68k-hp-bsd4.4
	exit ;;
    9000/[34678]??:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	case "${UNAME_MACHINE}" in
	    9000/31? )            HP_ARCH=m68000 ;;
	    9000/[34]?? )         HP_ARCH=m68k ;;
	    9000/[678][0-9][0-9])
		if [ -x /usr/bin/getconf ]; then
		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
                    case "${sc_cpu_version}" in
                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
                      532)                      # CPU_PA_RISC2_0
                        case "${sc_kernel_bits}" in
                          32) HP_ARCH="hppa2.0n" ;;
                          64) HP_ARCH="hppa2.0w" ;;
			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
                        esac ;;
                    esac
		fi
		if [ "${HP_ARCH}" = "" ]; then
		    eval $set_cc_for_build
		    sed 's/^              //' << EOF >$dummy.c

              #define _HPUX_SOURCE
              #include <stdlib.h>
              #include <unistd.h>

              int main ()
              {
              #if defined(_SC_KERNEL_BITS)
                  long bits = sysconf(_SC_KERNEL_BITS);
              #endif
                  long cpu  = sysconf (_SC_CPU_VERSION);

                  switch (cpu)
              	{
              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
              	case CPU_PA_RISC2_0:
              #if defined(_SC_KERNEL_BITS)
              	    switch (bits)
              		{
              		case 64: puts ("hppa2.0w"); break;
              		case 32: puts ("hppa2.0n"); break;
              		default: puts ("hppa2.0"); break;
              		} break;
              #else  /* !defined(_SC_KERNEL_BITS) */
              	    puts ("hppa2.0"); break;
              #endif
              	default: puts ("hppa1.0"); break;
              	}
                  exit (0);
              }
EOF
		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
		    test -z "$HP_ARCH" && HP_ARCH=hppa
		fi ;;
	esac
	if [ ${HP_ARCH} = "hppa2.0w" ]
	then
	    eval $set_cc_for_build

	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
	    # generating 64-bit code.  GNU and HP use different nomenclature:
	    #
	    # $ CC_FOR_BUILD=cc ./config.guess
	    # => hppa2.0w-hp-hpux11.23
	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
	    # => hppa64-hp-hpux11.23

	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
		grep -q __LP64__
	    then
		HP_ARCH="hppa2.0w"
	    else
		HP_ARCH="hppa64"
	    fi
	fi
	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
	exit ;;
    ia64:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	echo ia64-hp-hpux${HPUX_REV}
	exit ;;
    3050*:HI-UX:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#include <unistd.h>
	int
	main ()
	{
	  long cpu = sysconf (_SC_CPU_VERSION);
	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
	     results, however.  */
	  if (CPU_IS_PA_RISC (cpu))
	    {
	      switch (cpu)
		{
		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
		  default: puts ("hppa-hitachi-hiuxwe2"); break;
		}
	    }
	  else if (CPU_IS_HP_MC68K (cpu))
	    puts ("m68k-hitachi-hiuxwe2");
	  else puts ("unknown-hitachi-hiuxwe2");
	  exit (0);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
		{ echo "$SYSTEM_NAME"; exit; }
	echo unknown-hitachi-hiuxwe2
	exit ;;
    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
	echo hppa1.1-hp-bsd
	exit ;;
    9000/8??:4.3bsd:*:*)
	echo hppa1.0-hp-bsd
	exit ;;
    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
	echo hppa1.0-hp-mpeix
	exit ;;
    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
	echo hppa1.1-hp-osf
	exit ;;
    hp8??:OSF1:*:*)
	echo hppa1.0-hp-osf
	exit ;;
    i*86:OSF1:*:*)
	if [ -x /usr/sbin/sysversion ] ; then
	    echo ${UNAME_MACHINE}-unknown-osf1mk
	else
	    echo ${UNAME_MACHINE}-unknown-osf1
	fi
	exit ;;
    parisc*:Lites*:*:*)
	echo hppa1.1-hp-lites
	exit ;;
    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
	echo c1-convex-bsd
        exit ;;
    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
        exit ;;
    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
	echo c34-convex-bsd
        exit ;;
    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
	echo c38-convex-bsd
        exit ;;
    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
	echo c4-convex-bsd
        exit ;;
    CRAY*Y-MP:*:*:*)
	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*[A-Z]90:*:*:*)
	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
	      -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*TS:*:*:*)
	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*T3E:*:*:*)
	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*SV1:*:*:*)
	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    *:UNICOS/mp:*:*)
	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
        exit ;;
    5000:UNIX_System_V:4.*:*)
        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
	exit ;;
    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
	exit ;;
    sparc*:BSD/OS:*:*)
	echo sparc-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:BSD/OS:*:*)
	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:FreeBSD:*:*)
	case ${UNAME_MACHINE} in
	    pc98)
		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	    amd64)
		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	    *)
		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	esac
	exit ;;
    i*:CYGWIN*:*)
	echo ${UNAME_MACHINE}-pc-cygwin
	exit ;;
    *:MINGW*:*)
	echo ${UNAME_MACHINE}-pc-mingw32
	exit ;;
    i*:MSYS*:*) 
	echo ${UNAME_MACHINE}-pc-msys 
	exit ;; 
    i*:windows32*:*)
    	# uname -m includes "-pc" on this system.
    	echo ${UNAME_MACHINE}-mingw32
	exit ;;
    i*:PW*:*)
	echo ${UNAME_MACHINE}-pc-pw32
	exit ;;
    *:Interix*:*)
    	case ${UNAME_MACHINE} in
	    x86)
		echo i586-pc-interix${UNAME_RELEASE}
		exit ;;
	    authenticamd | genuineintel | EM64T)
		echo x86_64-unknown-interix${UNAME_RELEASE}
		exit ;;
	    IA64)
		echo ia64-unknown-interix${UNAME_RELEASE}
		exit ;;
	esac ;;
    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
	echo i${UNAME_MACHINE}-pc-mks
	exit ;;
    8664:Windows_NT:*)
	echo x86_64-pc-mks
	exit ;;
    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
	# UNAME_MACHINE based on the output of uname instead of i386?
	echo i586-pc-interix
	exit ;;
    i*:UWIN*:*)
	echo ${UNAME_MACHINE}-pc-uwin
	exit ;;
    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
	echo x86_64-unknown-cygwin
	exit ;;
    p*:CYGWIN*:*)
	echo powerpcle-unknown-cygwin
	exit ;;
    prep*:SunOS:5.*:*)
	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    *:GNU:*:*)
	# the GNU system
	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
	exit ;;
    *:GNU/*:*:*)
	# other systems with GNU libc and userland
	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
	exit ;;
    i*86:Minix:*:*)
	echo ${UNAME_MACHINE}-pc-minix
	exit ;;
    alpha:Linux:*:*)
	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
	  EV5)   UNAME_MACHINE=alphaev5 ;;
	  EV56)  UNAME_MACHINE=alphaev56 ;;
	  PCA56) UNAME_MACHINE=alphapca56 ;;
	  PCA57) UNAME_MACHINE=alphapca56 ;;
	  EV6)   UNAME_MACHINE=alphaev6 ;;
	  EV67)  UNAME_MACHINE=alphaev67 ;;
	  EV68*) UNAME_MACHINE=alphaev68 ;;
        esac
	objdump --private-headers /bin/sh | grep -q ld.so.1
	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
	exit ;;
    arm*:Linux:*:*)
	eval $set_cc_for_build
	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
	    | grep -q __ARM_EABI__
	then
	    echo ${UNAME_MACHINE}-unknown-linux-gnu
	else
	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
	fi
	exit ;;
    avr32*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    cris:Linux:*:*)
	echo cris-axis-linux-gnu
	exit ;;
    crisv32:Linux:*:*)
	echo crisv32-axis-linux-gnu
	exit ;;
    frv:Linux:*:*)
    	echo frv-unknown-linux-gnu
	exit ;;
    i*86:Linux:*:*)
	LIBC=gnu
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#ifdef __dietlibc__
	LIBC=dietlibc
	#endif
EOF
	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
	exit ;;
    ia64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    m32r*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    m68*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    mips:Linux:*:* | mips64:Linux:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#undef CPU
	#undef ${UNAME_MACHINE}
	#undef ${UNAME_MACHINE}el
	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
	CPU=${UNAME_MACHINE}el
	#else
	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
	CPU=${UNAME_MACHINE}
	#else
	CPU=
	#endif
	#endif
EOF
	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
	;;
    or32:Linux:*:*)
	echo or32-unknown-linux-gnu
	exit ;;
    padre:Linux:*:*)
	echo sparc-unknown-linux-gnu
	exit ;;
    parisc64:Linux:*:* | hppa64:Linux:*:*)
	echo hppa64-unknown-linux-gnu
	exit ;;
    parisc:Linux:*:* | hppa:Linux:*:*)
	# Look for CPU level
	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
	  *)    echo hppa-unknown-linux-gnu ;;
	esac
	exit ;;
    ppc64:Linux:*:*)
	echo powerpc64-unknown-linux-gnu
	exit ;;
    ppc:Linux:*:*)
	echo powerpc-unknown-linux-gnu
	exit ;;
    s390:Linux:*:* | s390x:Linux:*:*)
	echo ${UNAME_MACHINE}-ibm-linux
	exit ;;
    sh64*:Linux:*:*)
    	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    sh*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    sparc:Linux:*:* | sparc64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    tile*:Linux:*:*)
	echo ${UNAME_MACHINE}-tilera-linux-gnu
	exit ;;
    vax:Linux:*:*)
	echo ${UNAME_MACHINE}-dec-linux-gnu
	exit ;;
    x86_64:Linux:*:*)
	echo x86_64-unknown-linux-gnu
	exit ;;
    xtensa*:Linux:*:*)
    	echo ${UNAME_MACHINE}-unknown-linux-gnu
	exit ;;
    i*86:DYNIX/ptx:4*:*)
	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
	# earlier versions are messed up and put the nodename in both
	# sysname and nodename.
	echo i386-sequent-sysv4
	exit ;;
    i*86:UNIX_SV:4.2MP:2.*)
        # Unixware is an offshoot of SVR4, but it has its own version
        # number series starting with 2...
        # I am not positive that other SVR4 systems won't match this,
	# I just have to hope.  -- rms.
        # Use sysv4.2uw... so that sysv4* matches it.
	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
	exit ;;
    i*86:OS/2:*:*)
	# If we were able to find `uname', then EMX Unix compatibility
	# is probably installed.
	echo ${UNAME_MACHINE}-pc-os2-emx
	exit ;;
    i*86:XTS-300:*:STOP)
	echo ${UNAME_MACHINE}-unknown-stop
	exit ;;
    i*86:atheos:*:*)
	echo ${UNAME_MACHINE}-unknown-atheos
	exit ;;
    i*86:syllable:*:*)
	echo ${UNAME_MACHINE}-pc-syllable
	exit ;;
    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
	echo i386-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    i*86:*DOS:*:*)
	echo ${UNAME_MACHINE}-pc-msdosdjgpp
	exit ;;
    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
	else
		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
	fi
	exit ;;
    i*86:*:5:[678]*)
    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
	case `/bin/uname -X | grep "^Machine"` in
	    *486*)	     UNAME_MACHINE=i486 ;;
	    *Pentium)	     UNAME_MACHINE=i586 ;;
	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
	esac
	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
	exit ;;
    i*86:*:3.2:*)
	if test -f /usr/options/cb.name; then
		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
	elif /bin/uname -X 2>/dev/null >/dev/null ; then
		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
			&& UNAME_MACHINE=i586
		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
			&& UNAME_MACHINE=i686
		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
			&& UNAME_MACHINE=i686
		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
	else
		echo ${UNAME_MACHINE}-pc-sysv32
	fi
	exit ;;
    pc:*:*:*)
	# Left here for compatibility:
        # uname -m prints for DJGPP always 'pc', but it prints nothing about
        # the processor, so we play safe by assuming i586.
	# Note: whatever this is, it MUST be the same as what config.sub
	# prints for the "djgpp" host, or else GDB configury will decide that
	# this is a cross-build.
	echo i586-pc-msdosdjgpp
        exit ;;
    Intel:Mach:3*:*)
	echo i386-pc-mach3
	exit ;;
    paragon:*:*:*)
	echo i860-intel-osf1
	exit ;;
    i860:*:4.*:*) # i860-SVR4
	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
	else # Add other i860-SVR4 vendors below as they are discovered.
	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
	fi
	exit ;;
    mini*:CTIX:SYS*5:*)
	# "miniframe"
	echo m68010-convergent-sysv
	exit ;;
    mc68k:UNIX:SYSTEM5:3.51m)
	echo m68k-convergent-sysv
	exit ;;
    M680?0:D-NIX:5.3:*)
	echo m68k-diab-dnix
	exit ;;
    M68*:*:R3V[5678]*:*)
	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
	OS_REL=''
	test -r /etc/.relid \
	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
          && { echo i486-ncr-sysv4; exit; } ;;
    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
	OS_REL='.3'
	test -r /etc/.relid \
	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
	echo m68k-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    mc68030:UNIX_System_V:4.*:*)
	echo m68k-atari-sysv4
	exit ;;
    TSUNAMI:LynxOS:2.*:*)
	echo sparc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    rs6000:LynxOS:2.*:*)
	echo rs6000-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
	echo powerpc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    SM[BE]S:UNIX_SV:*:*)
	echo mips-dde-sysv${UNAME_RELEASE}
	exit ;;
    RM*:ReliantUNIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    RM*:SINIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    *:SINIX-*:*:*)
	if uname -p 2>/dev/null >/dev/null ; then
		UNAME_MACHINE=`(uname -p) 2>/dev/null`
		echo ${UNAME_MACHINE}-sni-sysv4
	else
		echo ns32k-sni-sysv
	fi
	exit ;;
    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
                      # says <[email protected]>
        echo i586-unisys-sysv4
        exit ;;
    *:UNIX_System_V:4*:FTX*)
	# From Gerald Hewes <[email protected]>.
	# How about differentiating between stratus architectures? -djm
	echo hppa1.1-stratus-sysv4
	exit ;;
    *:*:*:FTX*)
	# From [email protected].
	echo i860-stratus-sysv4
	exit ;;
    i*86:VOS:*:*)
	# From [email protected].
	echo ${UNAME_MACHINE}-stratus-vos
	exit ;;
    *:VOS:*:*)
	# From [email protected].
	echo hppa1.1-stratus-vos
	exit ;;
    mc68*:A/UX:*:*)
	echo m68k-apple-aux${UNAME_RELEASE}
	exit ;;
    news*:NEWS-OS:6*:*)
	echo mips-sony-newsos6
	exit ;;
    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
	if [ -d /usr/nec ]; then
	        echo mips-nec-sysv${UNAME_RELEASE}
	else
	        echo mips-unknown-sysv${UNAME_RELEASE}
	fi
        exit ;;
    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
	echo powerpc-be-beos
	exit ;;
    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
	echo powerpc-apple-beos
	exit ;;
    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
	echo i586-pc-beos
	exit ;;
    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
	echo i586-pc-haiku
	exit ;;
    SX-4:SUPER-UX:*:*)
	echo sx4-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-5:SUPER-UX:*:*)
	echo sx5-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-6:SUPER-UX:*:*)
	echo sx6-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-7:SUPER-UX:*:*)
	echo sx7-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8:SUPER-UX:*:*)
	echo sx8-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8R:SUPER-UX:*:*)
	echo sx8r-nec-superux${UNAME_RELEASE}
	exit ;;
    Power*:Rhapsody:*:*)
	echo powerpc-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Rhapsody:*:*)
	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Darwin:*:*)
	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
	case $UNAME_PROCESSOR in
	    i386)
		eval $set_cc_for_build
		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
		      grep IS_64BIT_ARCH >/dev/null
		  then
		      UNAME_PROCESSOR="x86_64"
		  fi
		fi ;;
	    unknown) UNAME_PROCESSOR=powerpc ;;
	esac
	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
	exit ;;
    *:procnto*:*:* | *:QNX:[0123456789]*:*)
	UNAME_PROCESSOR=`uname -p`
	if test "$UNAME_PROCESSOR" = "x86"; then
		UNAME_PROCESSOR=i386
		UNAME_MACHINE=pc
	fi
	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
	exit ;;
    *:QNX:*:4*)
	echo i386-pc-qnx
	exit ;;
    NEO-?:NONSTOP_KERNEL:*:*)
	echo neo-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSE-?:NONSTOP_KERNEL:*:*)
	echo nse-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSR-?:NONSTOP_KERNEL:*:*)
	echo nsr-tandem-nsk${UNAME_RELEASE}
	exit ;;
    *:NonStop-UX:*:*)
	echo mips-compaq-nonstopux
	exit ;;
    BS2000:POSIX*:*:*)
	echo bs2000-siemens-sysv
	exit ;;
    DS/*:UNIX_System_V:*:*)
	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
	exit ;;
    *:Plan9:*:*)
	# "uname -m" is not consistent, so use $cputype instead. 386
	# is converted to i386 for consistency with other x86
	# operating systems.
	if test "$cputype" = "386"; then
	    UNAME_MACHINE=i386
	else
	    UNAME_MACHINE="$cputype"
	fi
	echo ${UNAME_MACHINE}-unknown-plan9
	exit ;;
    *:TOPS-10:*:*)
	echo pdp10-unknown-tops10
	exit ;;
    *:TENEX:*:*)
	echo pdp10-unknown-tenex
	exit ;;
    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
	echo pdp10-dec-tops20
	exit ;;
    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
	echo pdp10-xkl-tops20
	exit ;;
    *:TOPS-20:*:*)
	echo pdp10-unknown-tops20
	exit ;;
    *:ITS:*:*)
	echo pdp10-unknown-its
	exit ;;
    SEI:*:*:SEIUX)
        echo mips-sei-seiux${UNAME_RELEASE}
	exit ;;
    *:DragonFly:*:*)
	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
	exit ;;
    *:*VMS:*:*)
    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
	case "${UNAME_MACHINE}" in
	    A*) echo alpha-dec-vms ; exit ;;
	    I*) echo ia64-dec-vms ; exit ;;
	    V*) echo vax-dec-vms ; exit ;;
	esac ;;
    *:XENIX:*:SysV)
	echo i386-pc-xenix
	exit ;;
    i*86:skyos:*:*)
	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
	exit ;;
    i*86:rdos:*:*)
	echo ${UNAME_MACHINE}-pc-rdos
	exit ;;
    i*86:AROS:*:*)
	echo ${UNAME_MACHINE}-pc-aros
	exit ;;
esac

#echo '(No uname command or uname output not recognized.)' 1>&2
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2

eval $set_cc_for_build
cat >$dummy.c <<EOF
#ifdef _SEQUENT_
# include <sys/types.h>
# include <sys/utsname.h>
#endif
main ()
{
#if defined (sony)
#if defined (MIPSEB)
  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
     I don't know....  */
  printf ("mips-sony-bsd\n"); exit (0);
#else
#include <sys/param.h>
  printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
          "4"
#else
	  ""
#endif
         ); exit (0);
#endif
#endif

#if defined (__arm) && defined (__acorn) && defined (__unix)
  printf ("arm-acorn-riscix\n"); exit (0);
#endif

#if defined (hp300) && !defined (hpux)
  printf ("m68k-hp-bsd\n"); exit (0);
#endif

#if defined (NeXT)
#if !defined (__ARCHITECTURE__)
#define __ARCHITECTURE__ "m68k"
#endif
  int version;
  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
  if (version < 4)
    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
  else
    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
  exit (0);
#endif

#if defined (MULTIMAX) || defined (n16)
#if defined (UMAXV)
  printf ("ns32k-encore-sysv\n"); exit (0);
#else
#if defined (CMU)
  printf ("ns32k-encore-mach\n"); exit (0);
#else
  printf ("ns32k-encore-bsd\n"); exit (0);
#endif
#endif
#endif

#if defined (__386BSD__)
  printf ("i386-pc-bsd\n"); exit (0);
#endif

#if defined (sequent)
#if defined (i386)
  printf ("i386-sequent-dynix\n"); exit (0);
#endif
#if defined (ns32000)
  printf ("ns32k-sequent-dynix\n"); exit (0);
#endif
#endif

#if defined (_SEQUENT_)
    struct utsname un;

    uname(&un);

    if (strncmp(un.version, "V2", 2) == 0) {
	printf ("i386-sequent-ptx2\n"); exit (0);
    }
    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
	printf ("i386-sequent-ptx1\n"); exit (0);
    }
    printf ("i386-sequent-ptx\n"); exit (0);

#endif

#if defined (vax)
# if !defined (ultrix)
#  include <sys/param.h>
#  if defined (BSD)
#   if BSD == 43
      printf ("vax-dec-bsd4.3\n"); exit (0);
#   else
#    if BSD == 199006
      printf ("vax-dec-bsd4.3reno\n"); exit (0);
#    else
      printf ("vax-dec-bsd\n"); exit (0);
#    endif
#   endif
#  else
    printf ("vax-dec-bsd\n"); exit (0);
#  endif
# else
    printf ("vax-dec-ultrix\n"); exit (0);
# endif
#endif

#if defined (alliant) && defined (i860)
  printf ("i860-alliant-bsd\n"); exit (0);
#endif

  exit (1);
}
EOF

$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
	{ echo "$SYSTEM_NAME"; exit; }

# Apollos put the system type in the environment.

test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }

# Convex versions that predate uname can use getsysinfo(1)

if [ -x /usr/convex/getsysinfo ]
then
    case `getsysinfo -f cpu_type` in
    c1*)
	echo c1-convex-bsd
	exit ;;
    c2*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
	exit ;;
    c34*)
	echo c34-convex-bsd
	exit ;;
    c38*)
	echo c38-convex-bsd
	exit ;;
    c4*)
	echo c4-convex-bsd
	exit ;;
    esac
fi

cat >&2 <<EOF
$0: unable to guess system type

This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from

  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD

If the version you run ($0) is already up to date, please
send the following data and any information you think might be
pertinent to <[email protected]> in order to provide the needed
information to handle your system.

config.guess timestamp = $timestamp

uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`

hostinfo               = `(hostinfo) 2>/dev/null`
/bin/universe          = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch              = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`

UNAME_MACHINE = ${UNAME_MACHINE}
UNAME_RELEASE = ${UNAME_RELEASE}
UNAME_SYSTEM  = ${UNAME_SYSTEM}
UNAME_VERSION = ${UNAME_VERSION}
EOF

exit 1

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:

Added autosetup/config.sub.































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
#! /bin/sh
# Configuration validation subroutine script.
#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
#   Free Software Foundation, Inc.

timestamp='2010-09-11'

# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
# can handle that machine.  It does not imply ALL GNU software can.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.


# Please send patches to <[email protected]>.  Submit a context
# diff and a properly formatted GNU ChangeLog entry.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.

# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD

# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
# Each package is responsible for reporting which valid configurations
# it does not support.  The user should be able to distinguish
# a failure to support a valid configuration from a meaningless
# configuration.

# The goal of this file is to map all the various variations of a given
# machine specification into a single specification in the form:
#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or in some cases, the newer four-part form:
#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
       $0 [OPTION] ALIAS

Canonicalize a configuration name.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to <[email protected]>."

version="\
GNU config.sub ($timestamp)

Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help"
       exit 1 ;;

    *local*)
       # First pass through any local machine types.
       echo $1
       exit ;;

    * )
       break ;;
  esac
done

case $# in
 0) echo "$me: missing argument$help" >&2
    exit 1;;
 1) ;;
 *) echo "$me: too many arguments$help" >&2
    exit 1;;
esac

# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
  knetbsd*-gnu* | netbsd*-gnu* | \
  kopensolaris*-gnu* | \
  storm-chaos* | os2-emx* | rtmk-nova*)
    os=-$maybe_os
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
    ;;
  *)
    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
    if [ $basic_machine != $1 ]
    then os=`echo $1 | sed 's/.*-/-/'`
    else os=; fi
    ;;
esac

### Let's recognize common machines as not being operating systems so
### that things like config.sub decstation-3100 work.  We also
### recognize some manufacturers as not being operating systems, so we
### can provide default operating systems below.
case $os in
	-sun*os*)
		# Prevent following clause from handling this invalid input.
		;;
	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
	-apple | -axis | -knuth | -cray | -microblaze)
		os=
		basic_machine=$1
		;;
        -bluegene*)
	        os=-cnk
		;;
	-sim | -cisco | -oki | -wec | -winbond)
		os=
		basic_machine=$1
		;;
	-scout)
		;;
	-wrs)
		os=-vxworks
		basic_machine=$1
		;;
	-chorusos*)
		os=-chorusos
		basic_machine=$1
		;;
 	-chorusrdb)
 		os=-chorusrdb
		basic_machine=$1
 		;;
	-hiux*)
		os=-hiuxwe2
		;;
	-sco6)
		os=-sco5v6
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5)
		os=-sco3.2v5
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco4)
		os=-sco3.2v4
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2.[4-9]*)
		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2v[4-9]*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5v6*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco*)
		os=-sco3.2v2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-udk*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-isc)
		os=-isc2.2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-clix*)
		basic_machine=clipper-intergraph
		;;
	-isc*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-lynx*)
		os=-lynxos
		;;
	-ptx*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
		;;
	-windowsnt*)
		os=`echo $os | sed -e 's/windowsnt/winnt/'`
		;;
	-psos*)
		os=-psos
		;;
	-mint | -mint[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
esac

# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
	# Recognize the basic CPU types without company name.
	# Some are omitted here because they have special meanings below.
	1750a | 580 \
	| a29k \
	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
	| am33_2.0 \
	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
	| bfin \
	| c4x | clipper \
	| d10v | d30v | dlx | dsp16xx \
	| fido | fr30 | frv \
	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
	| i370 | i860 | i960 | ia64 \
	| ip2k | iq2000 \
	| lm32 \
	| m32c | m32r | m32rle | m68000 | m68k | m88k \
	| maxq | mb | microblaze | mcore | mep | metag \
	| mips | mipsbe | mipseb | mipsel | mipsle \
	| mips16 \
	| mips64 | mips64el \
	| mips64octeon | mips64octeonel \
	| mips64orion | mips64orionel \
	| mips64r5900 | mips64r5900el \
	| mips64vr | mips64vrel \
	| mips64vr4100 | mips64vr4100el \
	| mips64vr4300 | mips64vr4300el \
	| mips64vr5000 | mips64vr5000el \
	| mips64vr5900 | mips64vr5900el \
	| mipsisa32 | mipsisa32el \
	| mipsisa32r2 | mipsisa32r2el \
	| mipsisa64 | mipsisa64el \
	| mipsisa64r2 | mipsisa64r2el \
	| mipsisa64sb1 | mipsisa64sb1el \
	| mipsisa64sr71k | mipsisa64sr71kel \
	| mipstx39 | mipstx39el \
	| mn10200 | mn10300 \
	| moxie \
	| mt \
	| msp430 \
	| nds32 | nds32le | nds32be \
	| nios | nios2 \
	| ns16k | ns32k \
	| or32 \
	| pdp10 | pdp11 | pj | pjl \
	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
	| pyramid \
	| rx \
	| score \
	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
	| sh64 | sh64le \
	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
	| spu | strongarm \
	| tahoe | thumb | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
	| ubicom32 \
	| v850 | v850e \
	| we32k \
	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
	| z8k | z80)
		basic_machine=$basic_machine-unknown
		;;
	c54x)
		basic_machine=tic54x-unknown
		;;
	c55x)
		basic_machine=tic55x-unknown
		;;
	c6x)
		basic_machine=tic6x-unknown
		;;
	m6811 | m68hc11 | m6812 | m68hc12 | picochip)
		# Motorola 68HC11/12.
		basic_machine=$basic_machine-unknown
		os=-none
		;;
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
		;;
	ms1)
		basic_machine=mt-unknown
		;;

	# We use `pc' rather than `unknown'
	# because (1) that's what they normally are, and
	# (2) the word "unknown" tends to confuse beginning users.
	i*86 | x86_64)
	  basic_machine=$basic_machine-pc
	  ;;
	# Object if more than one company name word.
	*-*-*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
	# Recognize the basic CPU types with company name.
	580-* \
	| a29k-* \
	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
	| avr-* | avr32-* \
	| bfin-* | bs2000-* \
	| c[123]* | c30-* | [cjt]90-* | c4x-* \
	| clipper-* | craynv-* | cydra-* \
	| d10v-* | d30v-* | dlx-* \
	| elxsi-* \
	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
	| h8300-* | h8500-* \
	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
	| i*86-* | i860-* | i960-* | ia64-* \
	| ip2k-* | iq2000-* \
	| lm32-* \
	| m32c-* | m32r-* | m32rle-* \
	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
	| mips16-* \
	| mips64-* | mips64el-* \
	| mips64octeon-* | mips64octeonel-* \
	| mips64orion-* | mips64orionel-* \
	| mips64r5900-* | mips64r5900el-* \
	| mips64vr-* | mips64vrel-* \
	| mips64vr4100-* | mips64vr4100el-* \
	| mips64vr4300-* | mips64vr4300el-* \
	| mips64vr5000-* | mips64vr5000el-* \
	| mips64vr5900-* | mips64vr5900el-* \
	| mipsisa32-* | mipsisa32el-* \
	| mipsisa32r2-* | mipsisa32r2el-* \
	| mipsisa64-* | mipsisa64el-* \
	| mipsisa64r2-* | mipsisa64r2el-* \
	| mipsisa64sb1-* | mipsisa64sb1el-* \
	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
	| mipstx39-* | mipstx39el-* \
	| mmix-* \
	| mt-* \
	| msp430-* \
	| nds32-* | nds32le-* | nds32be-* \
	| nios-* | nios2-* \
	| none-* | np1-* | ns16k-* | ns32k-* \
	| orion-* \
	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
	| pyramid-* \
	| romp-* | rs6000-* | rx-* \
	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
	| sparclite-* \
	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
	| tahoe-* | thumb-* \
	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
	| tile-* | tilegx-* \
	| tron-* \
	| ubicom32-* \
	| v850-* | v850e-* | vax-* \
	| we32k-* \
	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
	| xstormy16-* | xtensa*-* \
	| ymp-* \
	| z8k-* | z80-*)
		;;
	# Recognize the basic CPU types without company name, with glob match.
	xtensa*)
		basic_machine=$basic_machine-unknown
		;;
	# Recognize the various machine names and aliases which stand
	# for a CPU type and a company and sometimes even an OS.
	386bsd)
		basic_machine=i386-unknown
		os=-bsd
		;;
	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
		basic_machine=m68000-att
		;;
	3b*)
		basic_machine=we32k-att
		;;
	a29khif)
		basic_machine=a29k-amd
		os=-udi
		;;
    	abacus)
		basic_machine=abacus-unknown
		;;
	adobe68k)
		basic_machine=m68010-adobe
		os=-scout
		;;
	alliant | fx80)
		basic_machine=fx80-alliant
		;;
	altos | altos3068)
		basic_machine=m68k-altos
		;;
	am29k)
		basic_machine=a29k-none
		os=-bsd
		;;
	amd64)
		basic_machine=x86_64-pc
		;;
	amd64-*)
		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	amdahl)
		basic_machine=580-amdahl
		os=-sysv
		;;
	amiga | amiga-*)
		basic_machine=m68k-unknown
		;;
	amigaos | amigados)
		basic_machine=m68k-unknown
		os=-amigaos
		;;
	amigaunix | amix)
		basic_machine=m68k-unknown
		os=-sysv4
		;;
	apollo68)
		basic_machine=m68k-apollo
		os=-sysv
		;;
	apollo68bsd)
		basic_machine=m68k-apollo
		os=-bsd
		;;
	aros)
		basic_machine=i386-pc
		os=-aros
		;;
	aux)
		basic_machine=m68k-apple
		os=-aux
		;;
	balance)
		basic_machine=ns32k-sequent
		os=-dynix
		;;
	blackfin)
		basic_machine=bfin-unknown
		os=-linux
		;;
	blackfin-*)
		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	bluegene*)
		basic_machine=powerpc-ibm
		os=-cnk
		;;
	c54x-*)
		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c55x-*)
		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c6x-*)
		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c90)
		basic_machine=c90-cray
		os=-unicos
		;;
        cegcc)
		basic_machine=arm-unknown
		os=-cegcc
		;;
	convex-c1)
		basic_machine=c1-convex
		os=-bsd
		;;
	convex-c2)
		basic_machine=c2-convex
		os=-bsd
		;;
	convex-c32)
		basic_machine=c32-convex
		os=-bsd
		;;
	convex-c34)
		basic_machine=c34-convex
		os=-bsd
		;;
	convex-c38)
		basic_machine=c38-convex
		os=-bsd
		;;
	cray | j90)
		basic_machine=j90-cray
		os=-unicos
		;;
	craynv)
		basic_machine=craynv-cray
		os=-unicosmp
		;;
	cr16)
		basic_machine=cr16-unknown
		os=-elf
		;;
	crds | unos)
		basic_machine=m68k-crds
		;;
	crisv32 | crisv32-* | etraxfs*)
		basic_machine=crisv32-axis
		;;
	cris | cris-* | etrax*)
		basic_machine=cris-axis
		;;
	crx)
		basic_machine=crx-unknown
		os=-elf
		;;
	da30 | da30-*)
		basic_machine=m68k-da30
		;;
	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
		basic_machine=mips-dec
		;;
	decsystem10* | dec10*)
		basic_machine=pdp10-dec
		os=-tops10
		;;
	decsystem20* | dec20*)
		basic_machine=pdp10-dec
		os=-tops20
		;;
	delta | 3300 | motorola-3300 | motorola-delta \
	      | 3300-motorola | delta-motorola)
		basic_machine=m68k-motorola
		;;
	delta88)
		basic_machine=m88k-motorola
		os=-sysv3
		;;
	dicos)
		basic_machine=i686-pc
		os=-dicos
		;;
	djgpp)
		basic_machine=i586-pc
		os=-msdosdjgpp
		;;
	dpx20 | dpx20-*)
		basic_machine=rs6000-bull
		os=-bosx
		;;
	dpx2* | dpx2*-bull)
		basic_machine=m68k-bull
		os=-sysv3
		;;
	ebmon29k)
		basic_machine=a29k-amd
		os=-ebmon
		;;
	elxsi)
		basic_machine=elxsi-elxsi
		os=-bsd
		;;
	encore | umax | mmax)
		basic_machine=ns32k-encore
		;;
	es1800 | OSE68k | ose68k | ose | OSE)
		basic_machine=m68k-ericsson
		os=-ose
		;;
	fx2800)
		basic_machine=i860-alliant
		;;
	genix)
		basic_machine=ns32k-ns
		;;
	gmicro)
		basic_machine=tron-gmicro
		os=-sysv
		;;
	go32)
		basic_machine=i386-pc
		os=-go32
		;;
	h3050r* | hiux*)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	h8300hms)
		basic_machine=h8300-hitachi
		os=-hms
		;;
	h8300xray)
		basic_machine=h8300-hitachi
		os=-xray
		;;
	h8500hms)
		basic_machine=h8500-hitachi
		os=-hms
		;;
	harris)
		basic_machine=m88k-harris
		os=-sysv3
		;;
	hp300-*)
		basic_machine=m68k-hp
		;;
	hp300bsd)
		basic_machine=m68k-hp
		os=-bsd
		;;
	hp300hpux)
		basic_machine=m68k-hp
		os=-hpux
		;;
	hp3k9[0-9][0-9] | hp9[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k2[0-9][0-9] | hp9k31[0-9])
		basic_machine=m68000-hp
		;;
	hp9k3[2-9][0-9])
		basic_machine=m68k-hp
		;;
	hp9k6[0-9][0-9] | hp6[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k7[0-79][0-9] | hp7[0-79][0-9])
		basic_machine=hppa1.1-hp
		;;
	hp9k78[0-9] | hp78[0-9])
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][13679] | hp8[0-9][13679])
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][0-9] | hp8[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hppa-next)
		os=-nextstep3
		;;
	hppaosf)
		basic_machine=hppa1.1-hp
		os=-osf
		;;
	hppro)
		basic_machine=hppa1.1-hp
		os=-proelf
		;;
	i370-ibm* | ibm*)
		basic_machine=i370-ibm
		;;
# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
	i*86v32)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv32
		;;
	i*86v4*)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv4
		;;
	i*86v)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv
		;;
	i*86sol2)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-solaris2
		;;
	i386mach)
		basic_machine=i386-mach
		os=-mach
		;;
	i386-vsta | vsta)
		basic_machine=i386-unknown
		os=-vsta
		;;
	iris | iris4d)
		basic_machine=mips-sgi
		case $os in
		    -irix*)
			;;
		    *)
			os=-irix4
			;;
		esac
		;;
	isi68 | isi)
		basic_machine=m68k-isi
		os=-sysv
		;;
	m68knommu)
		basic_machine=m68k-unknown
		os=-linux
		;;
	m68knommu-*)
		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	m88k-omron*)
		basic_machine=m88k-omron
		;;
	magnum | m3230)
		basic_machine=mips-mips
		os=-sysv
		;;
	merlin)
		basic_machine=ns32k-utek
		os=-sysv
		;;
        microblaze)
		basic_machine=microblaze-xilinx
		;;
	mingw32)
		basic_machine=i386-pc
		os=-mingw32
		;;
	mingw32ce)
		basic_machine=arm-unknown
		os=-mingw32ce
		;;
	miniframe)
		basic_machine=m68000-convergent
		;;
	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
	mips3*-*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
		;;
	mips3*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
		;;
	monitor)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	morphos)
		basic_machine=powerpc-unknown
		os=-morphos
		;;
	msdos)
		basic_machine=i386-pc
		os=-msdos
		;;
	ms1-*)
		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
		;;
	mvs)
		basic_machine=i370-ibm
		os=-mvs
		;;
	msys) 
		basic_machine=i386-pc 
		os=-msys 
	 ;; 
	ncr3000)
		basic_machine=i486-ncr
		os=-sysv4
		;;
	netbsd386)
		basic_machine=i386-unknown
		os=-netbsd
		;;
	netwinder)
		basic_machine=armv4l-rebel
		os=-linux
		;;
	news | news700 | news800 | news900)
		basic_machine=m68k-sony
		os=-newsos
		;;
	news1000)
		basic_machine=m68030-sony
		os=-newsos
		;;
	news-3600 | risc-news)
		basic_machine=mips-sony
		os=-newsos
		;;
	necv70)
		basic_machine=v70-nec
		os=-sysv
		;;
	next | m*-next )
		basic_machine=m68k-next
		case $os in
		    -nextstep* )
			;;
		    -ns2*)
		      os=-nextstep2
			;;
		    *)
		      os=-nextstep3
			;;
		esac
		;;
	nh3000)
		basic_machine=m68k-harris
		os=-cxux
		;;
	nh[45]000)
		basic_machine=m88k-harris
		os=-cxux
		;;
	nindy960)
		basic_machine=i960-intel
		os=-nindy
		;;
	mon960)
		basic_machine=i960-intel
		os=-mon960
		;;
	nonstopux)
		basic_machine=mips-compaq
		os=-nonstopux
		;;
	np1)
		basic_machine=np1-gould
		;;
        neo-tandem)
		basic_machine=neo-tandem
		;;
        nse-tandem)
		basic_machine=nse-tandem
		;;
	nsr-tandem)
		basic_machine=nsr-tandem
		;;
	op50n-* | op60c-*)
		basic_machine=hppa1.1-oki
		os=-proelf
		;;
	openrisc | openrisc-*)
		basic_machine=or32-unknown
		;;
	os400)
		basic_machine=powerpc-ibm
		os=-os400
		;;
	OSE68000 | ose68000)
		basic_machine=m68000-ericsson
		os=-ose
		;;
	os68k)
		basic_machine=m68k-none
		os=-os68k
		;;
	pa-hitachi)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	paragon)
		basic_machine=i860-intel
		os=-osf
		;;
	parisc)
		basic_machine=hppa-unknown
		os=-linux
		;;
	parisc-*)
		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	pbd)
		basic_machine=sparc-tti
		;;
	pbb)
		basic_machine=m68k-tti
		;;
	pc532 | pc532-*)
		basic_machine=ns32k-pc532
		;;
	pc98)
		basic_machine=i386-pc
		;;
	pc98-*)
		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium | p5 | k5 | k6 | nexgen | viac3)
		basic_machine=i586-pc
		;;
	pentiumpro | p6 | 6x86 | athlon | athlon_*)
		basic_machine=i686-pc
		;;
	pentiumii | pentium2 | pentiumiii | pentium3)
		basic_machine=i686-pc
		;;
	pentium4)
		basic_machine=i786-pc
		;;
	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumpro-* | p6-* | 6x86-* | athlon-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium4-*)
		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pn)
		basic_machine=pn-gould
		;;
	power)	basic_machine=power-ibm
		;;
	ppc)	basic_machine=powerpc-unknown
		;;
	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppcle | powerpclittle | ppc-le | powerpc-little)
		basic_machine=powerpcle-unknown
		;;
	ppcle-* | powerpclittle-*)
		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64)	basic_machine=powerpc64-unknown
		;;
	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
		basic_machine=powerpc64le-unknown
		;;
	ppc64le-* | powerpc64little-*)
		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ps2)
		basic_machine=i386-ibm
		;;
	pw32)
		basic_machine=i586-unknown
		os=-pw32
		;;
	rdos)
		basic_machine=i386-pc
		os=-rdos
		;;
	rom68k)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	rm[46]00)
		basic_machine=mips-siemens
		;;
	rtpc | rtpc-*)
		basic_machine=romp-ibm
		;;
	s390 | s390-*)
		basic_machine=s390-ibm
		;;
	s390x | s390x-*)
		basic_machine=s390x-ibm
		;;
	sa29200)
		basic_machine=a29k-amd
		os=-udi
		;;
	sb1)
		basic_machine=mipsisa64sb1-unknown
		;;
	sb1el)
		basic_machine=mipsisa64sb1el-unknown
		;;
	sde)
		basic_machine=mipsisa32-sde
		os=-elf
		;;
	sei)
		basic_machine=mips-sei
		os=-seiux
		;;
	sequent)
		basic_machine=i386-sequent
		;;
	sh)
		basic_machine=sh-hitachi
		os=-hms
		;;
	sh5el)
		basic_machine=sh5le-unknown
		;;
	sh64)
		basic_machine=sh64-unknown
		;;
	sparclite-wrs | simso-wrs)
		basic_machine=sparclite-wrs
		os=-vxworks
		;;
	sps7)
		basic_machine=m68k-bull
		os=-sysv2
		;;
	spur)
		basic_machine=spur-unknown
		;;
	st2000)
		basic_machine=m68k-tandem
		;;
	stratus)
		basic_machine=i860-stratus
		os=-sysv4
		;;
	sun2)
		basic_machine=m68000-sun
		;;
	sun2os3)
		basic_machine=m68000-sun
		os=-sunos3
		;;
	sun2os4)
		basic_machine=m68000-sun
		os=-sunos4
		;;
	sun3os3)
		basic_machine=m68k-sun
		os=-sunos3
		;;
	sun3os4)
		basic_machine=m68k-sun
		os=-sunos4
		;;
	sun4os3)
		basic_machine=sparc-sun
		os=-sunos3
		;;
	sun4os4)
		basic_machine=sparc-sun
		os=-sunos4
		;;
	sun4sol2)
		basic_machine=sparc-sun
		os=-solaris2
		;;
	sun3 | sun3-*)
		basic_machine=m68k-sun
		;;
	sun4)
		basic_machine=sparc-sun
		;;
	sun386 | sun386i | roadrunner)
		basic_machine=i386-sun
		;;
	sv1)
		basic_machine=sv1-cray
		os=-unicos
		;;
	symmetry)
		basic_machine=i386-sequent
		os=-dynix
		;;
	t3e)
		basic_machine=alphaev5-cray
		os=-unicos
		;;
	t90)
		basic_machine=t90-cray
		os=-unicos
		;;
        # This must be matched before tile*.
        tilegx*)
		basic_machine=tilegx-unknown
		os=-linux-gnu
		;;
	tile*)
		basic_machine=tile-unknown
		os=-linux-gnu
		;;
	tx39)
		basic_machine=mipstx39-unknown
		;;
	tx39el)
		basic_machine=mipstx39el-unknown
		;;
	toad1)
		basic_machine=pdp10-xkl
		os=-tops20
		;;
	tower | tower-32)
		basic_machine=m68k-ncr
		;;
	tpf)
		basic_machine=s390x-ibm
		os=-tpf
		;;
	udi29k)
		basic_machine=a29k-amd
		os=-udi
		;;
	ultra3)
		basic_machine=a29k-nyu
		os=-sym1
		;;
	v810 | necv810)
		basic_machine=v810-nec
		os=-none
		;;
	vaxv)
		basic_machine=vax-dec
		os=-sysv
		;;
	vms)
		basic_machine=vax-dec
		os=-vms
		;;
	vpp*|vx|vx-*)
		basic_machine=f301-fujitsu
		;;
	vxworks960)
		basic_machine=i960-wrs
		os=-vxworks
		;;
	vxworks68)
		basic_machine=m68k-wrs
		os=-vxworks
		;;
	vxworks29k)
		basic_machine=a29k-wrs
		os=-vxworks
		;;
	w65*)
		basic_machine=w65-wdc
		os=-none
		;;
	w89k-*)
		basic_machine=hppa1.1-winbond
		os=-proelf
		;;
	xbox)
		basic_machine=i686-pc
		os=-mingw32
		;;
	xps | xps100)
		basic_machine=xps100-honeywell
		;;
	ymp)
		basic_machine=ymp-cray
		os=-unicos
		;;
	z8k-*-coff)
		basic_machine=z8k-unknown
		os=-sim
		;;
	z80-*-coff)
		basic_machine=z80-unknown
		os=-sim
		;;
	none)
		basic_machine=none-none
		os=-none
		;;

# Here we handle the default manufacturer of certain CPU types.  It is in
# some cases the only manufacturer, in others, it is the most popular.
	w89k)
		basic_machine=hppa1.1-winbond
		;;
	op50n)
		basic_machine=hppa1.1-oki
		;;
	op60c)
		basic_machine=hppa1.1-oki
		;;
	romp)
		basic_machine=romp-ibm
		;;
	mmix)
		basic_machine=mmix-knuth
		;;
	rs6000)
		basic_machine=rs6000-ibm
		;;
	vax)
		basic_machine=vax-dec
		;;
	pdp10)
		# there are many clones, so DEC is not a safe bet
		basic_machine=pdp10-unknown
		;;
	pdp11)
		basic_machine=pdp11-dec
		;;
	we32k)
		basic_machine=we32k-att
		;;
	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
		basic_machine=sh-unknown
		;;
	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
		basic_machine=sparc-sun
		;;
	cydra)
		basic_machine=cydra-cydrome
		;;
	orion)
		basic_machine=orion-highlevel
		;;
	orion105)
		basic_machine=clipper-highlevel
		;;
	mac | mpw | mac-mpw)
		basic_machine=m68k-apple
		;;
	pmac | pmac-mpw)
		basic_machine=powerpc-apple
		;;
	*-unknown)
		# Make sure to match an already-canonicalized machine name.
		;;
	*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
esac

# Here we canonicalize certain aliases for manufacturers.
case $basic_machine in
	*-digital*)
		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
		;;
	*-commodore*)
		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
		;;
	*)
		;;
esac

# Decode manufacturer-specific aliases for certain operating systems.

if [ x"$os" != x"" ]
then
case $os in
        # First match some system type aliases
        # that might get confused with valid system types.
	# -solaris* is a basic system type, with this one exception.
        -auroraux)
	        os=-auroraux
		;;
	-solaris1 | -solaris1.*)
		os=`echo $os | sed -e 's|solaris1|sunos4|'`
		;;
	-solaris)
		os=-solaris2
		;;
	-svr4*)
		os=-sysv4
		;;
	-unixware*)
		os=-sysv4.2uw
		;;
	-gnu/linux*)
		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
		;;
	# First accept the basic system types.
	# The portable systems comes first.
	# Each alternative MUST END IN A *, to match a version number.
	# -sysv* is not here because it comes later, after sysvr4.
	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
	      | -sym* | -kopensolaris* \
	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
	      | -aos* | -aros* \
	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
	      | -openbsd* | -solidbsd* \
	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
	      | -chorusos* | -chorusrdb* | -cegcc* \
	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
	      | -mingw32* | -linux-gnu* | -linux-android* \
	      | -linux-newlib* | -linux-uclibc* \
	      | -uxpv* | -beos* | -mpeix* | -udk* \
	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
	# Remember, each alternative MUST END IN *, to match a version number.
		;;
	-qnx*)
		case $basic_machine in
		    x86-* | i*86-*)
			;;
		    *)
			os=-nto$os
			;;
		esac
		;;
	-nto-qnx*)
		;;
	-nto*)
		os=`echo $os | sed -e 's|nto|nto-qnx|'`
		;;
	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
		;;
	-mac*)
		os=`echo $os | sed -e 's|mac|macos|'`
		;;
	-linux-dietlibc)
		os=-linux-dietlibc
		;;
	-linux*)
		os=`echo $os | sed -e 's|linux|linux-gnu|'`
		;;
	-sunos5*)
		os=`echo $os | sed -e 's|sunos5|solaris2|'`
		;;
	-sunos6*)
		os=`echo $os | sed -e 's|sunos6|solaris3|'`
		;;
	-opened*)
		os=-openedition
		;;
        -os400*)
		os=-os400
		;;
	-wince*)
		os=-wince
		;;
	-osfrose*)
		os=-osfrose
		;;
	-osf*)
		os=-osf
		;;
	-utek*)
		os=-bsd
		;;
	-dynix*)
		os=-bsd
		;;
	-acis*)
		os=-aos
		;;
	-atheos*)
		os=-atheos
		;;
	-syllable*)
		os=-syllable
		;;
	-386bsd)
		os=-bsd
		;;
	-ctix* | -uts*)
		os=-sysv
		;;
	-nova*)
		os=-rtmk-nova
		;;
	-ns2 )
		os=-nextstep2
		;;
	-nsk*)
		os=-nsk
		;;
	# Preserve the version number of sinix5.
	-sinix5.*)
		os=`echo $os | sed -e 's|sinix|sysv|'`
		;;
	-sinix*)
		os=-sysv4
		;;
        -tpf*)
		os=-tpf
		;;
	-triton*)
		os=-sysv3
		;;
	-oss*)
		os=-sysv3
		;;
	-svr4)
		os=-sysv4
		;;
	-svr3)
		os=-sysv3
		;;
	-sysvr4)
		os=-sysv4
		;;
	# This must come after -sysvr4.
	-sysv*)
		;;
	-ose*)
		os=-ose
		;;
	-es1800*)
		os=-ose
		;;
	-xenix)
		os=-xenix
		;;
	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
		os=-mint
		;;
	-aros*)
		os=-aros
		;;
	-kaos*)
		os=-kaos
		;;
	-zvmoe)
		os=-zvmoe
		;;
	-dicos*)
		os=-dicos
		;;
        -nacl*)
	        ;;
	-none)
		;;
	*)
		# Get rid of the `-' at the beginning of $os.
		os=`echo $os | sed 's/[^-]*-//'`
		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
		exit 1
		;;
esac
else

# Here we handle the default operating systems that come with various machines.
# The value should be what the vendor currently ships out the door with their
# machine or put another way, the most popular os provided with the machine.

# Note that if you're going to try to match "-MANUFACTURER" here (say,
# "-sun"), then you have to tell the case statement up towards the top
# that MANUFACTURER isn't an operating system.  Otherwise, code above
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.

case $basic_machine in
        score-*)
		os=-elf
		;;
        spu-*)
		os=-elf
		;;
	*-acorn)
		os=-riscix1.2
		;;
	arm*-rebel)
		os=-linux
		;;
	arm*-semi)
		os=-aout
		;;
        c4x-* | tic4x-*)
        	os=-coff
		;;
	tic54x-*)
		os=-coff
		;;
	tic55x-*)
		os=-coff
		;;
	tic6x-*)
		os=-coff
		;;
	# This must come before the *-dec entry.
	pdp10-*)
		os=-tops20
		;;
	pdp11-*)
		os=-none
		;;
	*-dec | vax-*)
		os=-ultrix4.2
		;;
	m68*-apollo)
		os=-domain
		;;
	i386-sun)
		os=-sunos4.0.2
		;;
	m68000-sun)
		os=-sunos3
		# This also exists in the configure program, but was not the
		# default.
		# os=-sunos4
		;;
	m68*-cisco)
		os=-aout
		;;
        mep-*)
		os=-elf
		;;
	mips*-cisco)
		os=-elf
		;;
	mips*-*)
		os=-elf
		;;
	or32-*)
		os=-coff
		;;
	*-tti)	# must be before sparc entry or we get the wrong os.
		os=-sysv3
		;;
	sparc-* | *-sun)
		os=-sunos4.1.1
		;;
	*-be)
		os=-beos
		;;
	*-haiku)
		os=-haiku
		;;
	*-ibm)
		os=-aix
		;;
    	*-knuth)
		os=-mmixware
		;;
	*-wec)
		os=-proelf
		;;
	*-winbond)
		os=-proelf
		;;
	*-oki)
		os=-proelf
		;;
	*-hp)
		os=-hpux
		;;
	*-hitachi)
		os=-hiux
		;;
	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
		os=-sysv
		;;
	*-cbm)
		os=-amigaos
		;;
	*-dg)
		os=-dgux
		;;
	*-dolphin)
		os=-sysv3
		;;
	m68k-ccur)
		os=-rtu
		;;
	m88k-omron*)
		os=-luna
		;;
	*-next )
		os=-nextstep
		;;
	*-sequent)
		os=-ptx
		;;
	*-crds)
		os=-unos
		;;
	*-ns)
		os=-genix
		;;
	i370-*)
		os=-mvs
		;;
	*-next)
		os=-nextstep3
		;;
	*-gould)
		os=-sysv
		;;
	*-highlevel)
		os=-bsd
		;;
	*-encore)
		os=-bsd
		;;
	*-sgi)
		os=-irix
		;;
	*-siemens)
		os=-sysv4
		;;
	*-masscomp)
		os=-rtu
		;;
	f30[01]-fujitsu | f700-fujitsu)
		os=-uxpv
		;;
	*-rom68k)
		os=-coff
		;;
	*-*bug)
		os=-coff
		;;
	*-apple)
		os=-macos
		;;
	*-atari*)
		os=-mint
		;;
	*)
		os=-none
		;;
esac
fi

# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer.  We pick the logical manufacturer.
vendor=unknown
case $basic_machine in
	*-unknown)
		case $os in
			-riscix*)
				vendor=acorn
				;;
			-sunos*)
				vendor=sun
				;;
			-cnk*|-aix*)
				vendor=ibm
				;;
			-beos*)
				vendor=be
				;;
			-hpux*)
				vendor=hp
				;;
			-mpeix*)
				vendor=hp
				;;
			-hiux*)
				vendor=hitachi
				;;
			-unos*)
				vendor=crds
				;;
			-dgux*)
				vendor=dg
				;;
			-luna*)
				vendor=omron
				;;
			-genix*)
				vendor=ns
				;;
			-mvs* | -opened*)
				vendor=ibm
				;;
			-os400*)
				vendor=ibm
				;;
			-ptx*)
				vendor=sequent
				;;
			-tpf*)
				vendor=ibm
				;;
			-vxsim* | -vxworks* | -windiss*)
				vendor=wrs
				;;
			-aux*)
				vendor=apple
				;;
			-hms*)
				vendor=hitachi
				;;
			-mpw* | -macos*)
				vendor=apple
				;;
			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
				vendor=atari
				;;
			-vos*)
				vendor=stratus
				;;
		esac
		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
		;;
esac

echo $basic_machine$os
exit

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:

Added autosetup/cthulhu.tcl.

































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
###
# Utilities for automating the build process of C extensions
###
use codebale

# @synopsis:
#
# CTHULHU modules adds autobuild utilities
#

#::namespace eval ::cthulhu {}

###
# title: define which modules the source we are adding contributes to
###
proc cthulhu_config args {
  set ::cthulhu_config [dict merge $::cthulhu_config $args]
}

###
# topic: 9c0c2d73c1afa8ef83a739c5d01309d0
# title: Signal for a C header to be read with mkhdr
###
proc cthulhu_add_cheader {filename {trace 0}} {
  set hfilename [::cygrelative $::project(srcdir) $filename]
  if {$hfilename in $::project(headers_verbatim)} {
    return
  }
  if {$hfilename ni $::project(headers)} {
    lappend ::project(headers) $hfilename
    #::cthulhu_read_csourcefile $file
  }
}

###
# topic: c52ea7e1ff44f11f960d99a55e4ab998
# title: Add the contents of a header file verbatim to the internal headers and public headers
###
proc cthulhu_add_cheader_verbatim {filename {trace 0}} {
  set hfilename [::cygrelative $::project(srcdir) $filename]
  ldelete ::project(headers) $hfilename
  if {$hfilename ni $::project(headers_verbatim)} {
    lappend ::project(headers_verbatim) $hfilename
  }
}

###
# topic: 91e4d7da8dd82d78af41561360deab10
# title: Signal for a C source to be read with mkhdr
###
proc cthulhu_add_csource {filename {cmdconfig {}}} {
  set config [dict merge $::cthulhu_config $cmdconfig]
  
  set cfilename [::cygrelative $::project(srcdir) $filename]
  dict set ::thesources $cfilename $config
  if {$cfilename ni $::project(sources)} {
    lappend ::project(sources) $cfilename
  }
  if {[string is true [dictGetnull $config scan]]} {
    if {$cfilename ni $::project(scanlist)} {
      lappend ::project(scanlist) $cfilename
    }
  }
}

###
# topic: f11da5f705442524715e8f8fe9af5276
# title: Add a path containing C code
###
proc cthulhu_add_directory {here {cmdconfig {}}} {
  set config [dict merge {
    cthulhu-ignore-hfiles {}
    cthulhu-ignore-cfiles {}
    build-ignore-cfiles {}
    cthulhu-trace-cfiles {}
  } $::cthulhu_config $cmdconfig]

  dict with config {}
  
  set here [::realpath $here]
  ###
  # Execute any .tcl scripts in the generic directory
  ###
  foreach file [lsort  [glob -nocomplain [file join $here *.tcl]]] {
    if {[file tail $file] eq "pkgIndex.tcl"} continue
    cd $here
    uplevel #0 [list source $file]
  }
  ###
  # Build a list of all public header files that
  # need to be amalgamated into the publicly exported
  # version
  ###
  foreach file [lsort  [glob -nocomplain [file join $here *.h]]] {
    cthulhu_include_directory $here
    set fname [file tail $file]
    if {${cthulhu-ignore-hfiles} eq "*"} continue
    if { $fname in ${cthulhu-ignore-hfiles} } continue
    if {[string match *_cases.h $fname]} continue
    cthulhu_add_cheader $file
  }
  foreach file [lsort  [glob -nocomplain [file join $here *.c]]] {
    if {[file tail $file] in ${build-ignore-cfiles} } continue
    cthulhu_add_csource $file
  }
}

proc cthulhu_include_directory {here} {
   if { $here ni $::project(include_paths) } {
      lappend ::project(include_paths) $here
    }
}

###
# topic: 1d3a911fd58337df92205759a6d092c3
# title: Add a source file in Tcl that produces a C file
###
proc cthulhu_add_dynamic {csource tclscript} {
  set cfilename [::cygrelative $::project(srcdir) $csource]
  set tclfilename [::cygrelative $::project(srcdir) $tclscript]
  dict set ::thesources $cfilename tclscript $tclfilename
}

###
# topic: d10665e8da4dd0781bb0a9ced5486e40
# title: Add a pure-tcl library
###
proc cthulhu_add_library {here {cmdconfig {}}} {
  set config [dict merge {
    cthulhu-ignore-tclfiles {}
  } $::cthulhu_config $cmdconfig]

  dict with config {}
  set here [::realpath $here]
  foreach file [lsort [glob -nocomplain $here/*.tcl]] {
    if {[file tail $file] in ${cthulhu-ignore-tclfiles}} continue
    set libfilename [::cygrelative $::project(srcdir) $libfilename]
  }
}

###
# topic: ccfe65b26705afc498e08d3004031066
# title: Detect where we need to produce a _cases.h file to automate a C source
###
proc cthulhu_detect_cases filename {
  set cfilename [::cygrelative $::project(srcdir) $filename]
  set cases [codebale_detect_cases $filename]
  if {![llength $cases]} return
  set dirname [file dirname $cfilename]
  foreach case $cases {
    lappend result [file join $dirname $case]
  }
  dict set ::thesources $cfilename cases $result
}

###
# topic: 41d95037e5a1cab76939150efdef8939
# title: Declare an end to modifications of ::project
# description:
#    This directive is placed after the last set ::project(X) Y
#    but before the first ::cthulhu_add_*
###
proc cthulhu_init args {
  set ::cthulhu_config [dict merge {
    target pkg
  } $args]
  set ::project(strlen) [string length $::project(path)/]
  set ::project(cases)  {}
  set ::project(sources)  {}
  set ::project(headers)  {}
  set ::project(scanlist) {}
  set ::project(headers_verbatim) {}
}

###
# topic: 17c9931c3ec5ba115efafaaaa3cf61ed
###
proc cthulhu_mk_lib_init.c outfile {
  global project cout
  set cout      [open $outfile w]
  fconfigure $cout -translation crlf
  puts $cout $::project(standard_header)
  puts $cout "#include \"$::project(h_file_int)\""
  
  puts $cout "
  
  extern int DLLEXPORT ${project(init_funct)}( Tcl_Interp *interp ) \{
    Tcl_Namespace *modPtr\;
  "
  puts $cout {
      /* Initialise the stubs tables. */
  #ifdef USE_TCL_STUBS
      if (
          !Tcl_InitStubs(interp, "8.3", 0)
      ) {
          return TCL_ERROR;
      }
  #endif
  }

  foreach module $::project(modules) {
    puts $cout "  if(${module}(interp)) return TCL_ERROR\;"
  }
  foreach {nspace cmds} [lsort -stride 2 -dictionary [array get namespace_commands]] {
    puts $cout "
    modPtr=Tcl_FindNamespace(interp,\"$nspace\",NULL,TCL_NAMESPACE_ONLY)\;
    if(!modPtr) {
      modPtr = Tcl_CreateNamespace(interp, \"$nspace\", NULL, NULL);
    }
    "
    foreach {command cfunct} [lsort -stride 2 -dictionary $cmds] {
      puts $cout "  Tcl_CreateObjCommand(interp,\"::${nspace}::${command}\",(Tcl_ObjCmdProc *)$cfunct,NULL,NULL);"
    }
    puts $cout {
    Tcl_CreateEnsemble(interp, modPtr->fullName, modPtr, TCL_ENSEMBLE_PREFIX);
    Tcl_Export(interp, modPtr, "[a-z]*", 1);
    }
  }
  
  puts $cout {
      /* Register the package. */}
  puts $cout "    if (Tcl_PkgProvide(interp, \"${project(pkgname)}\", \"${project(pkgvers)}\")) return TCL_ERROR\;"
  
  
  puts $cout "  return TCL_OK\;\n\}"
  close $cout
}

###
# topic: 17c9931c3ec5ba115efafaaaa3cf61ed
###
proc cthulhu_mk_app_init.c outfile {
  global project cout
  set cout      [open $outfile w]
  fconfigure $cout -translation crlf
  puts $cout $::project(standard_header)
  puts $cout "#include \"$::project(h_file_int)\""
  
  puts $cout "
  
  int ${project(init_funct)}_static( Tcl_Interp *interp ) \{
    Tcl_Namespace *modPtr\;
  "

  foreach module $::project(modules) {
    puts $cout "
  if(${module}(interp)) \{
    return TCL_ERROR\;
  \}
  "
  }
  foreach {nspace cmds} [lsort -stride 2 -dictionary [array get namespace_commands]] {
    puts $cout "
    modPtr=Tcl_FindNamespace(interp,\"$nspace\",NULL,TCL_NAMESPACE_ONLY)\;
    if(!modPtr) {
      modPtr = Tcl_CreateNamespace(interp, \"$nspace\", NULL, NULL);
    }
    "
    foreach {command cfunct} [lsort -stride 2 -dictionary $cmds] {
      puts $cout "  Tcl_CreateObjCommand(interp,\"::${nspace}::${command}\",(Tcl_ObjCmdProc *)$cfunct,NULL,NULL);"
    }
    puts $cout {
    Tcl_CreateEnsemble(interp, modPtr->fullName, modPtr, TCL_ENSEMBLE_PREFIX);
    Tcl_Export(interp, modPtr, "[a-z]*", 1);
    }
  }
  
  puts $cout {
      /* Register the package. */}
  puts $cout "    if (Tcl_PkgProvide(interp, \"${project(pkgname)}\", \"${project(pkgvers)}\")) return TCL_ERROR\;"
  
  
  puts $cout "  return TCL_OK\;\n\}"
  close $cout
}

###
# topic: 06bca7e2bddebdca69537fc3a9a0735f
###
proc cthulhu_mk_sources {bldpath outfile} {
  global project
  file mkdir $bldpath
  set fout [open $outfile w]
  fconfigure $fout -translation crlf
  set pkg_sources {}
  set pkg_objects {}
  foreach {csource} $::project(sources) {
    set ofile [file join $bldpath [string trimleft [string map {/ _ .c .o .. {}} $csource] _]]
    lappend pkg_sources $csource
    lappend pkg_objects $ofile
    dict set ::thesources $csource ofile $ofile
  }
  set ILINE "MYINCLUDES="
  foreach ipath $::project(include_paths) {
    append ILINE \\\n"  -I[::cygrelative $::project(srcdir) $ipath]"
  }
  puts $fout $ILINE
  puts $fout {}
  define PKG_OBJECTS [lsort  $pkg_objects]
  define PKG_SOURCES [lsort  $pkg_sources]
  
  #puts $fout "build/$project(c_file):"
  #puts $fout "\t\${TCLSH} scripts/cthulhu.tcl\n"
  
  foreach {csource cinfo} $::thesources {
    if {[dict exists $cinfo ofile]} {
      set ofile [dict get $cinfo ofile]
    } else {
      set ofile {}
    }
    set hfiles {}
    if {[dict exists $cinfo cases]} {
      foreach hfile [dict get $cinfo cases] {
        puts $fout "$hfile:"
        puts $fout "\t\$(TCLSH_PROG) scripts/mktclopts.tcl $csource\n"
        lappend hfiles $hfile
      }
    }
    if {[dict exists $cinfo tclscript]} {
      puts $fout "$csource:"
      puts $fout "\t\$(TCLSH_PROG) [dict get $cinfo tclscript] $csource\n"
      if {$ofile != {}} {
        puts $fout "$ofile: $hfiles"
        puts $fout "\t\$(COMPILE) [dictGetnull $cinfo extra] \$(MYINCLUDES) -c $csource -o \$@\n"
      }
    } else {
      if {$ofile != {}} {
        puts $fout "$ofile: $hfiles"
        puts $fout "\t\$(COMPILE) [dictGetnull $cinfo extra] \$(MYINCLUDES) -c $csource -o \$@\n"
      }
    }
  }
  close $fout
}

###
# topic: f7eec240dada25d73c1f68a877fa40be
# title: Produce the PROJECT.decls file
# description: Tools for automating the process of building stubs libraries
###
proc cthulhu_mk_stub_decls {pkgname mkhdrfile path} {
  set outfile [file join $path/$pkgname.decls]
  
  ###
  # Build the decls file
  ###
  set fout [open $outfile w]
  puts $fout [subst {###
  # $outfile
  #
  # This file was generated by [info script]
  ###
  
  library $pkgname
  interface $pkgname
  }]
  
  set fin [open $mkhdrfile r]
  set thisline {}
  set functcount 0
  while {[gets $fin line]>=0} {
    append thisline \n $line
    if {![info complete $thisline]} continue
    set readline $thisline
    set thisline {}
    set type [lindex $readline 1]
    if { $type ne "f" } continue
  
    set infodict [lindex $readline end]
    if {![dict exists $infodict definition]} continue
    set def [dict get $infodict definition]
    set def [string trim $def]
    set def [string trimright $def \;]
    if {![string match "*STUB_EXPORT*" $def]} continue
    puts $fout [list declare [incr functcount] $def]
    
  }
  close $fin
  close $fout
  
  ###
  # Build [package]Decls.h
  ###
  set hout [open [file join $path ${pkgname}Decls.h] w]
  
  close $hout

  set cout [open [file join $path ${pkgname}StubInit.c] w]
puts $cout [string map [list %pkgname% $pkgname %PkgName% [string totitle $pkgname]] {
#ifndef USE_TCL_STUBS
#define USE_TCL_STUBS
#endif
#undef USE_TCL_STUB_PROCS

#include "tcl.h"
#include "%pkgname%.h"

 /*
 ** Ensure that Tdom_InitStubs is built as an exported symbol.  The other stub
 ** functions should be built as non-exported symbols.
 */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT

%PkgName%Stubs *%pkgname%StubsPtr;

 /*
 **----------------------------------------------------------------------
 **
 **  %PkgName%_InitStubs --
 **
 **        Checks that the correct version of %PkgName% is loaded and that it
 **        supports stubs. It then initialises the stub table pointers.
 **
 **  Results:
 **        The actual version of %PkgName% that satisfies the request, or
 **        NULL to indicate that an error occurred.
 **
 **  Side effects:
 **        Sets the stub table pointers.
 **
 **----------------------------------------------------------------------
 */

char *
%PkgName%_InitStubs (Tcl_Interp *interp, char *version, int exact)
{
  char *actualVersion;
  
  actualVersion = Tcl_PkgRequireEx(interp, "%pkgname%", version, exact,
                                                                   (ClientData *) &%pkgname%StubsPtr);
  if (!actualVersion) {
        return NULL;
  }
  
  if (!%pkgname%StubsPtr) {
        Tcl_SetResult(interp,
                                  "This implementation of %PkgName% does not support stubs",
                                  TCL_STATIC);
        return NULL;
  }
  
  return actualVersion;
}
}]
  close $cout
}

###
# topic: ba1d2c7e8eab96029e434d54f917ef5a
###
proc cthulhu_mkhdr_index {hout docfileout} {
  global project
  set scanlist {}
  foreach file $::project(headers) {
    lappend scanlist [::realpath [file join $::project(srcdir) $file]]
  }
  foreach file $::project(scanlist) {
    lappend scanlist [::realpath [file join $::project(srcdir) $file]]
  }
  ldelete scanlist  [::realpath $::project(srcdir)/generic/$::project(h_file_int)]
  ldelete scanlist  [::realpath $::project(srcdir)/generic/$::project(c_file)]
  puts "WRITING INTERNAL HEADERS TO $hout"
  set fout [open $hout w]
puts $fout "/*
** DO NOT EDIT THIS FILE
** It is automagically generated by scripts/cthulhu.tcl
*/"
  fconfigure $fout -translation crlf
  foreach file $::project(headers_verbatim) {
    puts $fout "/* Verbatim headers */"
    set fullname [file join $::project(srcdir) $file]
    set type [file type $fullname]
    if {$type ne "file"} continue
    puts $fout "/*\n *$file \n*/"
    set fin [open $fullname r]
    puts $fout [read $fin]
    close $fin
  }
  puts $fout "/* FUNCTION DECLARATIONS */"
  ###
  # Do get around platform line breaks, we output to a tmp file
  # and concat in Tcl
  ###
  set crscanlist {}
  foreach file $scanlist {
    set crfile $file.cr[file extension $file]
    set rawfin [open $file r]
    set rawfout [open $crfile w]
    fconfigure $rawfout -translation lf
    puts $rawfout [read $rawfin]
    close $rawfout
    close $rawfin
    lappend crscanlist $crfile
  }
  
  ::cthulhu_mkhdr -h -- {*}$crscanlist > $hout.cr
  set rawfin [open $hout.cr r]
  puts $fout [read $rawfin]
  close $rawfin
  file delete $hout.cr
  close $fout
  
  ::cthulhu_mkhdr -doc -- {*}$scanlist > $docfileout
  
  foreach file $crscanlist {
    file delete $file
  }

  foreach {prefix cases} $::project(cases) {
    ::codebale_cases_generate $prefix $cases
  }

  set fin [open $hout r]
  while {[gets $fin line]>=0} {
    if {[regexp TCL_MODULE $line] || [regexp DLLEXPORT $line]} {
      foreach regexp {
           {(.*) ([a-zA-Z_][a-zA-Z0-9_]*) *\((.*)\)}
           {(.*) (\x2a[a-zA-Z_][a-zA-Z0-9_]*) *\((.*)\)}
      } {
        if {[regexp $regexp $line all keywords funcname arglist]} {
          lappend ::project(modules) $funcname        
          break
        }
      }
    }
  }
}

proc cthulhu_find_mkhdr {} {
  set exename [lindex [find-an-executable mkhdr] 0]
  if {$exename ne {}} {
    return [list exec [::realpath $exename]]
  }
  if {[info exists ::odie(mkhdr)]} {
    if {[file exists [::realpath $::odie(mkhdr)]]} {
      return [list exec [::realpath $::odie(mkhdr)]]
    } 
  }
  doexec $::odie(cc) -o mkhdr.o -c $::odie(src_dir)/scripts/mkhdr.c
  doexec $::odie(cc) mkhdr.o -o mkhdr$::odie(exe_suffix)
  file copy -force mkhdr$::odie(exe_suffix) [::realpath $::odie(mkhdr)]
  return [list exec [::realpath $::odie(mkhdr)]]
  error {mkhdr not available}
}


proc cthulhu_mkhdr args {
  set cmd [cthulhu_find_mkhdr]
  {*}${cmd} {*}$args
}

array set ::project {
  include_paths {}
  sources {}
  tcl_sources {}
  modules {}
}

Added autosetup/default.auto.



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Auto-load module for 'make' build system integration

use init

autosetup_add_init_type make {Simple "make" build system} {
	autosetup_check_create auto.def \
{# Initial auto.def created by 'autosetup --init=make'

use cc

# Add any user options here
options {
}

make-config-header config.h
make-template Makefile.in
}

	if {![file exists Makefile.in]} {
		puts "Note: I don't see Makefile.in. You will probably need to create one."
	}
}

Added autosetup/fileutil.tcl.





































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
# fileutil.tcl --
#
#	Tcl implementations of standard UNIX utilities.
#
# Copyright (c) 1998-2000 by Ajuba Solutions.
# Copyright (c) 2002      by Phil Ehrens <[email protected]> (fileType)
# Copyright (c) 2005-2013 by Andreas Kupries <[email protected]>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: fileutil.tcl,v 1.78 2010/06/17 04:46:19 andreas_kupries Exp $

# @synopsis:
#
# CODEBALE modules adds a jimtcl compadible version of the fileutil package from tcllib
#

package provide cthulhu-fileutil 1.14.8

#namespace eval ::fileutil {
#    namespace export \
#	     find findByPattern cat touch foreachLine \
#	    jail stripPwd stripN stripPath tempdir tempfile \
#	    install fileType writeFile appendToFile \
#	    insertIntoFile removeFromFile replaceInFile \
#	    updateInPlace test tempdirReset
#}

# ::fileutil_grep --
#
#	Implementation of grep.  Adapted from the Tcler's Wiki.
#
# Arguments:
#	pattern		pattern to search for.
#	files		list of files to search; if NULL, uses stdin.
#
# Results:
#	results		list of matches

proc fileutil_grep {pattern {files {}}} {
    set result [list]
    if {[llength $files] == 0} {
	# read from stdin
	set lnum 0
	while {[gets stdin line] >= 0} {
	    incr lnum
	    if {[regexp -- $pattern $line]} {
		lappend result "${lnum}:${line}"
	    }
	}
    } else {
	foreach filename $files {
	    set file [open $filename r]
	    set lnum 0
	    while {[gets $file line] >= 0} {
		incr lnum
		if {[regexp -- $pattern $line]} {
		    lappend result "${filename}:${lnum}:${line}"
		}
	    }
	    close $file
	}
    }
    return $result
}

# ::fileutil_find ==

# Below is the core command, which is portable across Tcl versions and
# platforms. Functionality which is common or platform and/or Tcl
# version dependent, has been factored out/ encapsulated into separate
# (small) commands. Only these commands may have multiple variant
# implementations per the available features of the Tcl core /
# platform.
#
# These commands are
#
# FADD   - Add path result, performs filtering. Portable!
# GLOBF  - Return files in a directory.         Tcl version/platform dependent.
# GLOBD  - Return dirs  in a directory.         Tcl version/platform dependent.
# ACCESS - Check directory for accessibility.   Tcl version/platform dependent.

proc fileutil_find {{basedir .} {filtercmd {}}} {
    set result {}
    set filt   [string length $filtercmd]

    if {[file isfile $basedir]} {
	# The base is a file, and therefore only possible result,
	# modulo filtering.

	fileutil_FADD $basedir

    } elseif {[file isdirectory $basedir]} {

	# For a directory as base we do an iterative recursion through
	# the directory hierarchy starting at the base. We use a queue
	# (Tcl list) of directories we have to check. We access it by
	# index, and stop when we have reached beyond the end of the
	# list. This is faster than removing elements from the be-
	# ginning of the list, as that entails copying down a possibly
	# large list of directories, making it O(n*n). The index is
	# faster, O(n), at the expense of memory. Nothing is deleted
	# from the list until we have processed all directories in the
	# hierarchy.
	#
	# We scan each directory at least twice. First for files, then
	# for directories. The scans may internally make several
	# passes (normal vs hidden files).
	#
	# Looped directory structures due to symbolic links are
	# handled by _fully_ normalizing directory paths and checking
	# if we encountered the normalized form before. The array
	# 'known' is our cache where we record the known normalized
	# paths.

	set pending [list $basedir]
	set at      0
	array set   known {}

	while {$at < [llength $pending]} {
	    # Get next directory not yet processed.
	    set current [lindex $pending $at]
	    incr at

	    # Is the directory accessible? Continue if not.
	    fileutil_ACCESS $current

	    # Files first, then the sub-directories ...

	    foreach f [fileutil_GLOBF $current] { fileutil_FADD $f }

	    foreach f [fileutil_GLOBD $current] {
		# Ignore current and parent directory, this needs
		# explicit filtering outside of the filter command.
		if {
		    [string equal [file tail $f]  "."] ||
		    [string equal [file tail $f] ".."]
		} continue

		# Extend result, modulo filtering.
		fileutil_FADD $f

		# Detection of symlink loops via a portable path
		# normalization computing a canonical form of the path
		# followed by a check if that canonical form was
		# encountered before. If ok, record directory for
		# expansion in future iterations.

		set norm [fileutil_fullnormalize $f]
		if {[info exists known($norm)]} continue
		set known($norm) .

		lappend pending $f
	    }
	}
    } else {
	return -code error "$basedir does not exist"
    }

    return $result
}

# Helper command for fileutil_find. Performs the filtering of the
# result per a filter command for the candidates found by the
# traversal core, see above. This is portable.

proc fileutil_FADD {filename} {
    upvar 1 result result filt filt filtercmd filtercmd
    if {!$filt} {
	lappend result $filename
	return
    }

    set here [pwd]
    cd [file dirname $filename]

    if {[uplevel 2 [linsert $filtercmd end [file tail $filename]]]} {
	lappend result $filename
    }

    cd $here
    return
}

# The next three helper commands for fileutil_find depend strongly on
# the version of Tcl, and partially on the platform.

# 1. The -directory and -types switches were added to glob in Tcl
#    8.3. This means that we have to emulate them for Tcl 8.2.
#
# 2. In Tcl 8.3 using -types f will return only true files, but not
#    links to files. This changed in 8.4+ where links to files are
#    returned as well. So for 8.3 we have to handle the links
#    separately (-types l) and also filter on our own.
#    Note that Windows file links are hard links which are reported by
#    -types f, but not -types l, so we can optimize that for the two
#    platforms.
#
#    Note further that we have to handle broken links on our own. They
#    are not returned by glob yet we want them in the output.
#
# 3. In Tcl 8.3 we also have a crashing bug in glob (SIGABRT, "stat on
#    a known file") when trying to perform 'glob -types {hidden f}' on
#    a directory without e'x'ecute permissions. We code around by
#    testing if we can cd into the directory (stat might return enough
#    information too (mode), but possibly also not portable).
#
#    For Tcl 8.2 and 8.4+ glob simply delivers an empty result
#    (-nocomplain), without crashing. For them this command is defined
#    so that the bytecode compiler removes it from the bytecode.
#
#    This bug made the ACCESS helper necessary.
#    We code around the problem by testing if we can cd into the
#    directory (stat might return enough information too (mode), but
#    possibly also not portable).

set tclver [package present Tcl]
puts [list TCL VERSION $tclver]
if {$tclver eq {}} {
    # jimTcl emulates a pre-namespace tcl
    set tclver 7.8
}
puts [list TCL VERSION $tclver]

###
# Assume an austere environment
# circa 8.2.
# (Ad 1,2,3) We do not have -directory, nor -types. Full emulation required.
###
proc fileutil_ACCESS {args} {}
if {[string equal $::tcl_platform(platform) windows]} {
    # Hidden files cannot be handled by Tcl 8.2 in glob. We have
    # to punt.

    proc fileutil_GLOBF {current} {
	set current \\[join [split $current {}] \\]
	set res {}
	foreach x [glob -nocomplain -- [file join $current *]] {
	    if {[file isdirectory $x]} continue
	    if {[catch {file type $x}]} continue
	    # We have now accepted files, links to files, and
	    # broken links. We may also have accepted a directory
	    # as well, if the current path was inaccessible. This
	    # however will cause 'file type' to throw an error,
	    # hence the second check.
	    lappend res $x
	}
	return $res
    }

    proc fileutil_GLOBD {current} {
	set current \\[join [split $current {}] \\]
	set res {}
	foreach x [glob -nocomplain -- [file join $current *]] {
	    if {![file isdirectory $x]} continue
	    lappend res $x
	}
	return $res
    }
} else {
    # Hidden files on Unix are dot-files. We emulate the switch
    # '-types hidden' by using an explicit pattern.

    proc fileutil_GLOBF {current} {
	set current \\[join [split $current {}] \\]
	set res {}
	foreach x [glob -nocomplain -- [file join $current *] [file join $current .*]] {
	    if {[file isdirectory $x]} continue
	    if {[catch {file type $x}]} continue
	    # We have now accepted files, links to files, and
	    # broken links. We may also have accepted a directory
	    # as well, if the current path was inaccessible. This
	    # however will cause 'file type' to throw an error,
	    # hence the second check.

	    lappend res $x
	}
	return $res
    }

    proc fileutil_GLOBD {current} {
	set current \\[join [split $current {}] \\]
	set res {}
	foreach x [glob -nocomplain -- $current/* [file join $current .*]] {
	    if {![file isdirectory $x]} continue
	    lappend res $x
	}
	return $res
    }
}


# ::fileutil_findByPattern --
#
#	Specialization of find. Finds files based on their names,
#	which have to match the specified patterns. Options are used
#	to specify which type of patterns (regexp-, glob-style) is
#	used.
#
# Arguments:
#	basedir		Directory to start searching from.
#	args		Options (-glob, -regexp, --) followed by a
#			list of patterns to search for.
#
# Results:
#	files		a list of interesting files.

proc fileutil_findByPattern {basedir args} {
    set pos 0
    set cmd ::fileutil_FindGlob
    foreach a $args {
	incr pos
	switch -glob -- $a {
	    --      {break}
	    -regexp {set cmd ::fileutil_FindRegexp}
	    -glob   {set cmd ::fileutil_FindGlob}
	    -*      {return -code error "Unknown option $a"}
	    default {incr pos -1 ; break}
	}
    }

    set args [lrange $args $pos end]

    if {[llength $args] != 1} {
	set pname [lindex [info level 0] 0]
	return -code error \
		"wrong#args for \"$pname\", should be\
		\"$pname basedir ?-regexp|-glob? ?--? patterns\""
    }

    set patterns [lindex $args 0]
    return [find $basedir [list $cmd $patterns]]
}


# ::fileutil_FindRegexp --
#
#	Internal helper. Filter command used by 'findByPattern'
#	to match files based on regular expressions.
#
# Arguments:
#	patterns	List of regular expressions to match against.
#	filename	Name of the file to match against the patterns.
# Results:
#	interesting	A boolean flag. Set to true if the file
#			matches at least one of the patterns.

proc fileutil_FindRegexp {patterns filename} {
    foreach p $patterns {
	if {[regexp -- $p $filename]} {
	    return 1
	}
    }
    return 0
}

# ::fileutil_FindGlob --
#
#	Internal helper. Filter command used by 'findByPattern'
#	to match files based on glob expressions.
#
# Arguments:
#	patterns	List of glob expressions to match against.
#	filename	Name of the file to match against the patterns.
# Results:
#	interesting	A boolean flag. Set to true if the file
#			matches at least one of the patterns.

proc fileutil_FindGlob {patterns filename} {
    foreach p $patterns {
	if {[string match $p $filename]} {
	    return 1
	}
    }
    return 0
}

# ::fileutil_stripPwd --
#
#	If the specified path references is a path in [pwd] (or [pwd] itself) it
#	is made relative to [pwd]. Otherwise it is left unchanged.
#	In the case of [pwd] itself the result is the string '.'.
#
# Arguments:
#	path		path to modify
#
# Results:
#	path		The (possibly) modified path.

proc fileutil_stripPwd {path} {

    # [file split] is used to generate a canonical form for both
    # paths, for easy comparison, and also one which is easy to modify
    # using list commands.

    set pwd [pwd]
    if {[string equal $pwd $path]} {
	return "."
    }

    set pwd   [file split $pwd]
    set npath [file split $path]

    if {[string match ${pwd}* $npath]} {
	set path [eval [linsert [lrange $npath [llength $pwd] end] 0 file join ]]
    }
    return $path
}

# ::fileutil_stripN --
#
#	Removes N elements from the beginning of the path.
#
# Arguments:
#	path		path to modify
#	n		number of elements to strip
#
# Results:
#	path		The modified path

proc fileutil_stripN {path n} {
    set path [file split $path]
    if {$n >= [llength $path]} {
	return {}
    } else {
	return [eval [linsert [lrange $path $n end] 0 file join]]
    }
}

# ::fileutil_stripPath --
#
#	If the specified path references/is a path in prefix (or prefix itself) it
#	is made relative to prefix. Otherwise it is left unchanged.
#	In the case of it being prefix itself the result is the string '.'.
#
# Arguments:
#	prefix		prefix to strip from the path.
#	path		path to modify
#
# Results:
#	path		The (possibly) modified path.

if {[string equal $::tcl_platform(platform) windows]} {

    # Windows. While paths are stored with letter-case preserved al
    # comparisons have to be done case-insensitive. For reference see
    # SF Tcllib Bug 2499641.

    proc fileutil_stripPath {prefix path} {
	# [file split] is used to generate a canonical form for both
	# paths, for easy comparison, and also one which is easy to modify
	# using list commands.

	set prefix [file split $prefix]
	set npath  [file split $path]

	if {[string equal -nocase $prefix $npath]} {
	    return "."
	}

	if {[string match -nocase "${prefix} *" $npath]} {
	    set path [eval [linsert [lrange $npath [llength $prefix] end] 0 file join ]]
	}
	return $path
    }
} else {
    proc fileutil_stripPath {prefix path} {
	# [file split] is used to generate a canonical form for both
	# paths, for easy comparison, and also one which is easy to modify
	# using list commands.

	set prefix [file split $prefix]
	set npath  [file split $path]

	if {[string equal $prefix $npath]} {
	    return "."
	}

	if {[string match "${prefix} *" $npath]} {
	    set path [eval [linsert [lrange $npath [llength $prefix] end] 0 file join ]]
	}
	return $path
    }
}

# ::fileutil_jail --
#
#	Ensures that the input path 'filename' stays within the the
#	directory 'jail'. In this way it preventsuser-supplied paths
#	from escaping the jail.
#
# Arguments:
#	jail		The path to the directory the other must
#			not escape from.
#	filename	The path to prevent from escaping.
#
# Results:
#	path		The (possibly) modified path surely within
#			the confines of the jail.

proc fileutil_jail {jail filename} {
    if {![string equal [file pathtype $filename]  "relative"]} {
	# Although the path to check is absolute (or volumerelative on
	# windows) we cannot perform a simple prefix check to see if
	# the path is inside the jail or not. We have to normalize
	# both path and jail and then we can check. If the path is
	# outside we make the original path relative and prefix it
	# with the original jail. We do make the jail pseudo-absolute
	# by prefixing it with the current working directory for that.

	# Normalized jail. Fully resolved sym links, if any. Our main
	# complication is that normalize does not resolve symlinks in the
	# last component of the path given to it, so we add a bogus
	# component, resolve, and then strip it off again. That is why the
	# code is so large and long.

	set njail [eval [list file join] [lrange [file split \
		[fileutil_Normalize [file join $jail __dummy__]]] 0 end-1]]

	# Normalize filename. Fully resolved sym links, if
	# any. S.a. for an explanation of the complication.

	set nfile [eval [list file join] [lrange [file split \
		[fileutil_Normalize [file join $filename __dummy__]]] 0 end-1]]

	if {[string match ${njail}* $nfile]} {
	    return $filename
	}

	# Outside the jail, put it inside. ... We normalize the input
	# path lexically for this, to prevent escapes still lurking in
	# the original path. (We cannot use the normalized path,
	# symlinks may have bent it out of shape in unrecognizable ways.

	return [eval [linsert [lrange [file split \
		[fileutil_lexnormalize $filename]] 1 end] 0 file join [pwd] $jail]]
    } else {
	# The path is relative, consider it as outside
	# implicitly. Normalize it lexically! to prevent escapes, then
	# put the jail in front, use PWD to ensure absoluteness.

	return [eval [linsert [file split [fileutil_lexnormalize $filename]] 0 \
		file join [pwd] $jail]]
    }
}


# ::fileutil_test --
#
#	Simple API to testing various properties of
#	a path (read, write, file/dir, existence)
#
# Arguments:
#	path	path to test
#	codes	names of the properties to test
#	msgvar	Name of variable to leave an error
#		message in. Optional.
#	label	Label for error message, optional
#
# Results:
#	ok	boolean flag, set if the path passes
#		all tests.


global  test
array set test {
    read   {readable    {Read access is denied}}
    write  {writable    {Write access is denied}}
    exec   {executable  {Is not executable}}
    exists {exists      {Does not exist}}
    file   {isfile      {Is not a file}}
    dir    {isdirectory {Is not a directory}}
}


proc fileutil_test {path codes {msgvar {}} {label {}}} {
    global test

    if {[string equal $msgvar ""]} {
	set msg ""
    } else {
	upvar 1 $msgvar msg
    }

    if {![string equal $label ""]} {append label { }}

    if {![regexp {^(read|write|exec|exists|file|dir)} $codes]} {
	# Translate single characters into proper codes
	set codes [string map {
	    r read w write e exists x exec f file d dir
	} [split $codes {}]]
    }

    foreach c $codes {
	foreach {cmd text} $test($c) break
	if {![file $cmd $path]} {
	    set msg "$label\"$path\": $text"
	    return 0
	}
    }

    return 1
}

# ::fileutil_cat --
#
#	Tcl implementation of the UNIX "cat" command.  Returns the contents
#	of the specified files.
#
# Arguments:
#	args	names of the files to read, interspersed with options
#		to set encodings, translations, or eofchar.
#
# Results:
#	data	data read from the file.

proc fileutil_cat {args} {
    # Syntax: (?options? file)+
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    if {![llength $args]} {
	# Argument processing stopped with arguments missing.
	return -code error \
		"wrong#args: should be\
		[lindex [info level 0] 0] ?-eofchar|-translation|-encoding arg?+ file ..."
    }

    # We go through the arguments using foreach and keeping track of
    # the index we are at. We do not shift the arguments out to the
    # left. That is inherently quadratic, copying everything down.

    set opts {}
    set mode maybeopt
    set channels {}

    foreach a $args {
	if {[string equal $mode optarg]} {
	    lappend opts $a
	    set mode maybeopt
	    continue
	} elseif {[string equal $mode maybeopt]} {
	    if {[string match -* $a]} {
		switch -exact -- $a {
		    -encoding -
		    -translation -
		    -eofchar {
			lappend opts $a
			set mode optarg
			continue
		    }
		    -- {
			set mode file
			continue
		    }
		    default {
			return -code error \
				"Bad option \"$a\",\
				expected one of\
				-encoding, -eofchar,\
				or -translation"
		    }
		}
	    }
	    # Not an option, but a file. Change mode and fall through.
	    set mode file
	}
	# Process file arguments

	if {[string equal $a -]} {
	    # Stdin reference is special.

	    # Test that the current options are all ok.
	    # For stdin we have to avoid closing it.

	    set old [fconfigure stdin]
	    set fail [catch {
		SetOptions stdin $opts
	    } msg] ; # {}
	    SetOptions stdin $old

	    if {$fail} {
		return -code error $msg
	    }

	    lappend channels [list $a $opts 0]
	} else {
	    if {![file exists $a]} {
		return -code error "Cannot read file \"$a\", does not exist"
	    } elseif {![file isfile $a]} {
		return -code error "Cannot read file \"$a\", is not a file"
	    } elseif {![file readable $a]} {
		return -code error "Cannot read file \"$a\", read access is denied"
	    }

	    # Test that the current options are all ok.
	    set c [open $a r]
	    set fail [catch {
		SetOptions $c $opts
	    } msg] ; # {}
	    close $c
	    if {$fail} {
		return -code error $msg
	    }

	    lappend channels [list $a $opts [file size $a]]
	}

	# We may have more options and files coming after.
	set mode maybeopt
    }

    if {![string equal $mode maybeopt]} {
	# Argument processing stopped with arguments missing.
	return -code error \
		"wrong#args: should be\
		[lindex [info level 0] 0] ?-eofchar|-translation|-encoding arg?+ file ..."
    }

    set data ""
    foreach c $channels {
	foreach {fname opts size} $c break

	if {[string equal $fname -]} {
	    set old [fconfigure stdin]
	    SetOptions stdin $opts
	    append data [read stdin]
	    SetOptions stdin $old
	    continue
	}

	set c [open $fname r]
	SetOptions $c $opts

	if {$size > 0} {
	    # Used the [file size] command to get the size, which
	    # preallocates memory, rather than trying to grow it as
	    # the read progresses.
	    append data [read $c $size]
	} else {
	    # if the file has zero bytes it is either empty, or
	    # something where [file size] reports 0 but the file
	    # actually has data (like the files in the /proc
	    # filesystem on Linux).
	    append data [read $c]
	}
	close $c
    }

    return $data
}

# ::fileutil_writeFile --
#
#	Write the specified data into the named file,
#	creating it if necessary.
#
# Arguments:
#	options...	Options and arguments.
#	filename	Path to the file to write.
#	data		The data to write into the file
#
# Results:
#	None.

proc fileutil_writeFile {args} {
    # Syntax: ?options? file data
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    Spec Writable $args opts fname data

    # Now perform the requested operation.

    file mkdir [file dirname $fname]
    set              c [open $fname w]
    SetOptions      $c $opts
    puts -nonewline $c $data
    close           $c
    return
}

# ::fileutil_appendToFile --
#
#	Append the specified data at the end of the named file,
#	creating it if necessary.
#
# Arguments:
#	options...	Options and arguments.
#	filename	Path to the file to extend.
#	data		The data to extend the file with.
#
# Results:
#	None.

proc fileutil_appendToFile {args} {
    # Syntax: ?options? file data
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    Spec Writable $args opts fname data

    # Now perform the requested operation.

    file mkdir [file dirname $fname]
    set              c [open $fname a]
    SetOptions      $c $opts
    set at    [tell $c]
    puts -nonewline $c $data
    close           $c
    return $at
}

# ::fileutil_insertIntoFile --
#
#	Insert the specified data into the named file,
#	creating it if necessary, at the given locaton.
#
# Arguments:
#	options...	Options and arguments.
#	filename	Path to the file to extend.
#	data		The data to extend the file with.
#
# Results:
#	None.

proc fileutil_insertIntoFile {args} {

    # Syntax: ?options? file at data
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    Spec ReadWritable $args opts fname at data

    set max [file size $fname]
    CheckLocation $at $max insertion

    if {[string length $data] == 0} {
	# Another degenerate case, inserting nothing.
	# Leave the file well enough alone.
	return
    }

    foreach {c o t} [Open2 $fname $opts] break

    # The degenerate cases of both appending and insertion at the
    # beginning of the file allow more optimized implementations of
    # the operation.

    if {$at == 0} {
	puts -nonewline    $o $data
	fcopy           $c $o
    } elseif {$at == $max} {
	fcopy           $c $o
	puts -nonewline    $o $data
    } else {
	fcopy           $c $o -size $at
	puts -nonewline    $o $data
	fcopy           $c $o
    }

    Close2 $fname $t $c $o
    return
}

# ::fileutil_removeFromFile --
#
#	Remove n characters from the named file,
#	starting at the given locaton.
#
# Arguments:
#	options...	Options and arguments.
#	filename	Path to the file to extend.
#	at		Location to start the removal from.
#	n		Number of characters to remove.
#
# Results:
#	None.

proc fileutil_removeFromFile {args} {

    # Syntax: ?options? file at n
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    Spec ReadWritable $args opts fname at n

    set max [file size $fname]
    CheckLocation    $at $max removal
    CheckLength   $n $at $max removal

    if {$n == 0} {
	# Another degenerate case, removing nothing.
	# Leave the file well enough alone.
	return
    }

    foreach {c o t} [Open2 $fname $opts] break

    # The degenerate cases of both removal from the beginning or end
    # of the file allow more optimized implementations of the
    # operation.

    if {$at == 0} {
	seek  $c    $n current
	fcopy $c $o
    } elseif {($at + $n) == $max} {
	fcopy $c $o -size $at
	# Nothing further to copy.
    } else {
	fcopy $c $o -size $at
	seek  $c    $n current
	fcopy $c $o
    }

    Close2 $fname $t $c $o
    return
}

# ::fileutil_replaceInFile --
#
#	Remove n characters from the named file,
#	starting at the given locaton, and replace
#	it with the given data.
#
# Arguments:
#	options...	Options and arguments.
#	filename	Path to the file to extend.
#	at		Location to start the removal from.
#	n		Number of characters to remove.
#	data		The replacement data.
#
# Results:
#	None.

proc fileutil_replaceInFile {args} {

    # Syntax: ?options? file at n data
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    Spec ReadWritable $args opts fname at n data

    set max [file size $fname]
    CheckLocation    $at $max replacement
    CheckLength   $n $at $max replacement

    if {
	($n == 0) &&
	([string length $data] == 0)
    } {
	# Another degenerate case, replacing nothing with
	# nothing. Leave the file well enough alone.
	return
    }

    foreach {c o t} [Open2 $fname $opts] break

    # Check for degenerate cases and handle them separately,
    # i.e. strip the no-op parts out of the general implementation.

    if {$at == 0} {
	if {$n == 0} {
	    # Insertion instead of replacement.

	    puts -nonewline    $o $data
	    fcopy           $c $o

	} elseif {[string length $data] == 0} {
	    # Removal instead of replacement.

	    seek  $c    $n current
	    fcopy $c $o

	} else {
	    # General replacement at front.

	    seek         $c    $n current
	    puts -nonewline $o $data
	    fcopy        $c $o
	}
    } elseif {($at + $n) == $max} {
	if {$n == 0} {
	    # Appending instead of replacement

	    fcopy           $c $o
	    puts -nonewline    $o $data

	} elseif {[string length $data] == 0} {
	    # Truncating instead of replacement

	    fcopy $c $o -size $at
	    # Nothing further to copy.

	} else {
	    # General replacement at end

	    fcopy        $c $o -size $at
	    puts -nonewline $o $data
	}
    } else {
	if {$n == 0} {
	    # General insertion.

	    fcopy           $c $o -size $at
	    puts -nonewline    $o $data
	    fcopy           $c $o

	} elseif {[string length $data] == 0} {
	    # General removal.

	    fcopy $c $o -size $at
	    seek  $c    $n current
	    fcopy $c $o

	} else {
	    # General replacement.

	    fcopy        $c $o -size $at
	    seek         $c    $n current
	    puts -nonewline $o $data
	    fcopy        $c $o
	}
    }

    Close2 $fname $t $c $o
    return
}

# ::fileutil_updateInPlace --
#
#	Run command prefix on the contents of the
#	file and replace them with the result of
#	the command.
#
# Arguments:
#	options...	Options and arguments.
#	filename	Path to the file to extend.
#	cmd		Command prefix to run.
#
# Results:
#	None.

proc fileutil_updateInPlace {args} {
    # Syntax: ?options? file cmd
    # options = -encoding    ENC
    #         | -translation TRA
    #         | -eofchar     ECH
    #         | --

    Spec ReadWritable $args opts fname cmd

    # readFile/cat inlined ...

    set             c [open $fname r]
    SetOptions     $c $opts
    set data [read $c]
    close          $c

    # Transformation. Abort and do not modify the target file if an
    # error was raised during this step.

    lappend cmd $data
    set code [catch {uplevel 1 $cmd} res]
    if {$code} {
	return -code $code $res
    }

    # writeFile inlined, with careful preservation of old contents
    # until we are sure that the write was ok.

    if {[catch {
	file rename -force $fname ${fname}.bak

	set              o [open $fname w]
	SetOptions      $o $opts
	puts -nonewline $o $res
	close           $o

	file delete -force ${fname}.bak
    } msg]} {
	if {[file exists ${fname}.bak]} {
	    catch {
		file rename -force ${fname}.bak $fname
	    }
	    return -code error $msg
	}
    }
    return
}

proc fileutil_Writable {fname mv} {
    upvar 1 $mv msg
    if {[file exists $fname]} {
	if {![file isfile $fname]} {
	    set msg "Cannot use file \"$fname\", is not a file"
	    return 0
	} elseif {![file writable $fname]} {
	    set msg "Cannot use file \"$fname\", write access is denied"
	    return 0
	}
    }
    return 1
}

proc fileutil_ReadWritable {fname mv} {
    upvar 1 $mv msg
    if {![file exists $fname]} {
	set msg "Cannot use file \"$fname\", does not exist"
	return 0
    } elseif {![file isfile $fname]} {
	set msg "Cannot use file \"$fname\", is not a file"
	return 0
    } elseif {![file writable $fname]} {
	set msg "Cannot use file \"$fname\", write access is denied"
	return 0
    } elseif {![file readable $fname]} {
	set msg "Cannot use file \"$fname\", read access is denied"
	return 0
    }
    return 1
}

proc fileutil_Spec {check alist ov fv args} {
    upvar 1 $ov opts $fv fname

    set  n [llength $args] ; # Num more args
    incr n                 ; # Count path as well

    set opts {}
    set mode maybeopt

    set at 0
    foreach a $alist {
	if {[string equal $mode optarg]} {
	    lappend opts $a
	    set mode maybeopt
	    incr at
	    continue
	} elseif {[string equal $mode maybeopt]} {
	    if {[string match -* $a]} {
		switch -exact -- $a {
		    -encoding -
		    -translation -
		    -eofchar {
			lappend opts $a
			set mode optarg
			incr at
			continue
		    }
		    -- {
			# Stop processing.
			incr at
			break
		    }
		    default {
			return -code error \
				"Bad option \"$a\",\
				expected one of\
				-encoding, -eofchar,\
				or -translation"
		    }
		}
	    }
	    # Not an option, but a file.
	    # Stop processing.
	    break
	}
    }

    if {([llength $alist] - $at) != $n} {
	# Argument processing stopped with arguments missing, or too
	# many
	return -code error \
		"wrong#args: should be\
		[lindex [info level 1] 0] ?-eofchar|-translation|-encoding arg? file $args"
    }

    set fname [lindex $alist $at]
    incr at
    foreach \
	    var $args \
	    val [lrange $alist $at end] {
	upvar 1 $var A
	set A $val
    }

    # Check given path ...

    if {![eval [linsert $check end $a msg]]} {
	return -code error $msg
    }

    return
}

proc fileutil_Open2 {fname opts} {
    set c [open $fname r]
    set t [tempfile]
    set o [open $t     w]

    SetOptions $c $opts
    SetOptions $o $opts

    return [list $c $o $t]
}

proc fileutil_Close2 {f temp in out} {
    close $in
    close $out

    file copy   -force $f ${f}.bak
    file rename -force $temp $f
    file delete -force ${f}.bak
    return
}

proc fileutil_SetOptions {c opts} {
    if {![llength $opts]} return
    eval [linsert $opts 0 fconfigure $c]
    return
}

proc fileutil_CheckLocation {at max label} {
    if {![string is integer -strict $at]} {
	return -code error \
		"Expected integer but got \"$at\""
    } elseif {$at < 0} {
	return -code error \
		"Bad $label point $at, before start of data"
    } elseif {$at > $max} {
	return -code error \
		"Bad $label point $at, behind end of data"
    }
}

proc fileutil_CheckLength {n at max label} {
    if {![string is integer -strict $n]} {
	return -code error \
		"Expected integer but got \"$n\""
    } elseif {$n < 0} {
	return -code error \
		"Bad $label size $n"
    } elseif {($at + $n) > $max} {
	return -code error \
		"Bad $label size $n, going behind end of data"
    }
}

# ::fileutil_foreachLine --
#
#	Executes a script for every line in a file.
#
# Arguments:
#	var		name of the variable to contain the lines
#	filename	name of the file to read.
#	cmd		The script to execute.
#
# Results:
#	None.

proc fileutil_foreachLine {var filename cmd} {
    upvar 1 $var line
    set fp [open $filename r]

    # -future- Use try/eval from tcllib/control
    catch {
	set code 0
	set result {}
	while {[gets $fp line] >= 0} {
	    set code [catch {uplevel 1 $cmd} result]
	    if {($code != 0) && ($code != 4)} {break}
	}
    }
    close $fp

    if {($code == 0) || ($code == 3) || ($code == 4)} {
        return $result
    }
    if {$code == 1} {
        global errorCode errorInfo
        return \
		-code      $code      \
		-errorcode $errorCode \
		-errorinfo $errorInfo \
		$result
    }
    return -code $code $result
}

# ::fileutil_fileType --
#
#	Do some simple heuristics to determine file type.
#
#
# Arguments:
#	filename        Name of the file to test.
#
# Results
#	type            Type of the file.  May be a list if multiple tests
#                       are positive (eg, a file could be both a directory 
#                       and a link).  In general, the list proceeds from most
#                       general (eg, binary) to most specific (eg, gif), so
#                       the full type for a GIF file would be 
#                       "binary graphic gif"
#
#                       At present, the following types can be detected:
#
#                       directory
#                       empty
#                       binary
#                       text
#                       script <interpreter>
#                       executable [elf, dos, ne, pe]
#                       binary graphic [gif, jpeg, png, tiff, bitmap, icns]
#                       ps, eps, pdf
#                       html
#                       xml <doctype>
#                       message pgp
#                       compressed [bzip, gzip, zip, tar]
#                       audio [mpeg, wave]
#                       gravity_wave_data_frame
#                       link
#			doctools, doctoc, and docidx documentation files.
#                  

proc fileutil_fileType {filename} {
    ;## existence test
    if { ! [ file exists $filename ] } {
        set err "file not found: '$filename'"
        return -code error $err
    }
    ;## directory test
    if { [ file isdirectory $filename ] } {
        set type directory
        if { ! [ catch {file readlink $filename} ] } {
            lappend type link
        }
        return $type
    }
    ;## empty file test
    if { ! [ file size $filename ] } {
        set type empty
        if { ! [ catch {file readlink $filename} ] } {
            lappend type link
        }
        return $type
    }
    set bin_rx {[\x00-\x08\x0b\x0e-\x1f]}

    if { [ catch {
        set fid [ open $filename r ]
        fconfigure $fid -translation binary
        fconfigure $fid -buffersize 1024
        fconfigure $fid -buffering full
        set test [ read $fid 1024 ]
        ::close $fid
    } err ] } {
        catch { ::close $fid }
        return -code error "::fileutil_fileType: $err"
    }

    if { [ regexp $bin_rx $test ] } {
        set type binary
        set binary 1
    } else {
        set type text
        set binary 0
    }

    # SF Tcllib bug [795585]. Allowing whitespace between #!
    # and path of script interpreter

    set metakit 0

    if { [ regexp {^\#\!\s*(\S+)} $test -> terp ] } {
        lappend type script $terp
    } elseif {([regexp "\\\[manpage_begin " $test] &&
	       !([regexp -- {--- !doctools ---} $test] || [regexp -- "!tcl\.tk//DSL doctools//EN//" $test])) ||
                ([regexp -- {--- doctools ---} $test]  || [regexp -- "tcl\.tk//DSL doctools//EN//" $test])} {
	lappend type doctools
    } elseif {([regexp "\\\[toc_begin " $test] &&
	       !([regexp -- {--- !doctoc ---} $test] || [regexp -- "!tcl\.tk//DSL doctoc//EN//" $test])) ||
                ([regexp -- {--- doctoc ---} $test]  || [regexp -- "tcl\.tk//DSL doctoc//EN//" $test])} {
	lappend type doctoc
    } elseif {([regexp "\\\[index_begin " $test] &&
	       !([regexp -- {--- !docidx ---} $test] || [regexp -- "!tcl\.tk//DSL docidx//EN//" $test])) ||
              ([regexp -- {--- docidx ---} $test] || [regexp -- "tcl\.tk//DSL docidx//EN//" $test])} {
	lappend type docidx
    } elseif {[regexp -- "tcl\\.tk//DSL diagram//EN//" $test]} {
	lappend type tkdiagram
    } elseif { $binary && [ regexp {^[\x7F]ELF} $test ] } {
        lappend type executable elf
    } elseif { $binary && [string match "MZ*" $test] } {
        if { [scan [string index $test 24] %c] < 64 } {
            lappend type executable dos
        } else {
            binary scan [string range $test 60 61] s next
            set sig [string range $test $next [expr {$next + 1}]]
            if { $sig == "NE" || $sig == "PE" } {
                lappend type executable [string tolower $sig]
            } else {
                lappend type executable dos
            }
        }
    } elseif { $binary && [string match "BZh91AY\&SY*" $test] } {
        lappend type compressed bzip
    } elseif { $binary && [string match "\x1f\x8b*" $test] } {
        lappend type compressed gzip
    } elseif { $binary && [string range $test 257 262] == "ustar\x00" } {
        lappend type compressed tar
    } elseif { $binary && [string match "\x50\x4b\x03\x04*" $test] } {
        lappend type compressed zip
    } elseif { $binary && [string match "GIF*" $test] } {
        lappend type graphic gif
    } elseif { $binary && [string match "icns*" $test] } {
        lappend type graphic icns bigendian
    } elseif { $binary && [string match "snci*" $test] } {
        lappend type graphic icns smallendian
    } elseif { $binary && [string match "\x89PNG*" $test] } {
        lappend type graphic png
    } elseif { $binary && [string match "\xFF\xD8\xFF*" $test] } {
        binary scan $test x3H2x2a5 marker txt
        if { $marker == "e0" && $txt == "JFIF\x00" } {
            lappend type graphic jpeg jfif
        } elseif { $marker == "e1" && $txt == "Exif\x00" } {
            lappend type graphic jpeg exif
        }
    } elseif { $binary && [string match "MM\x00\**" $test] } {
        lappend type graphic tiff
    } elseif { $binary && [string match "BM*" $test] && [string range $test 6 9] == "\x00\x00\x00\x00" } {
        lappend type graphic bitmap
    } elseif { $binary && [string match "\%PDF\-*" $test] } {
        lappend type pdf
    } elseif { ! $binary && [string match -nocase "*\<html\>*" $test] } {
        lappend type html
    } elseif { [string match "\%\!PS\-*" $test] } {
       lappend type ps
       if { [string match "* EPSF\-*" $test] } {
           lappend type eps
       }
    } elseif { [string match -nocase "*\<\?xml*" $test] } {
        lappend type xml
        if { [ regexp -nocase {\<\!DOCTYPE\s+(\S+)} $test -> doctype ] } {
            lappend type $doctype
        }
    } elseif { [string match {*BEGIN PGP MESSAGE*} $test] } {
        lappend type message pgp
    } elseif { $binary && [string match {IGWD*} $test] } {
        lappend type gravity_wave_data_frame
    } elseif {[string match "JL\x1a\x00*" $test] && ([file size $filename] >= 27)} {
	lappend type metakit smallendian
	set metakit 1
    } elseif {[string match "LJ\x1a\x00*" $test] && ([file size $filename] >= 27)} {
	lappend type metakit bigendian
	set metakit 1
    } elseif { $binary && [string match "RIFF*" $test] && [string range $test 8 11] == "WAVE" } {
        lappend type audio wave
    } elseif { $binary && [string match "ID3*" $test] } {
        lappend type audio mpeg
    } elseif { $binary && [binary scan $test S tmp] && [expr {$tmp & 0xFFE0}] == 65504 } {
        lappend type audio mpeg
    }

    # Additional checks of file contents at the end of the file,
    # possibly pointing into the middle too (attached metakit,
    # attached zip).

    ## Metakit File format: http://www.equi4.com/metakit/metakit-ff.html
    ## Metakit database attached ? ##

    if {!$metakit && ([file size $filename] >= 27)} {
	# The offsets in the footer are in always bigendian format

	if { [ catch {
	    set fid [ open $filename r ]
	    fconfigure $fid -translation binary
	    fconfigure $fid -buffersize 1024
	    fconfigure $fid -buffering full
	    seek $fid -16 end
	    set test [ read $fid 16 ]
	    ::close $fid
	} err ] } {
	    catch { ::close $fid }
	    return -code error "::fileutil_fileType: $err"
	}

	binary scan $test IIII __ hdroffset __ __
	set hdroffset [expr {[file size $filename] - 16 - $hdroffset}]

	# Further checks iff the offset is actually inside the file.

	if {($hdroffset >= 0) && ($hdroffset < [file size $filename])} {
	    # Seek to the specified location and try to match a metakit header
	    # at this location.

	    if { [ catch {
		set         fid [ open $filename r ]
		fconfigure $fid -translation binary
		fconfigure $fid -buffersize 1024
		fconfigure $fid -buffering full
		seek       $fid $hdroffset start
		set test [ read $fid 16 ]
		::close $fid
	    } err ] } {
		catch { ::close $fid }
		return -code error "::fileutil_fileType: $err"
	    }

	    if {[string match "JL\x1a\x00*" $test]} {
		lappend type attached metakit smallendian
		set metakit 1
	    } elseif {[string match "LJ\x1a\x00*" $test]} {
		lappend type attached metakit bigendian
		set metakit 1
	    }
	}
    }

    ## Zip File Format: http://zziplib.sourceforge.net/zzip-parse.html
    ## http://www.pkware.com/products/enterprise/white_papers/appnote.html


    ;## lastly, is it a link?
    if { ! [ catch {file readlink $filename} ] } {
        lappend type link
    }
    return $type
}

# ::fileutil_tempdir --
#
#	Return the correct directory to use for temporary files.
#	Python attempts this sequence, which seems logical:
#
#       1. The directory named by the `TMPDIR' environment variable.
#
#       2. The directory named by the `TEMP' environment variable.
#
#       3. The directory named by the `TMP' environment variable.
#
#       4. A platform-specific location:
#            * On Macintosh, the `Temporary Items' folder.
#
#            * On Windows, the directories `C:\\TEMP', `C:\\TMP',
#              `\\TEMP', and `\\TMP', in that order.
#
#            * On all other platforms, the directories `/tmp',
#              `/var/tmp', and `/usr/tmp', in that order.
#
#       5. As a last resort, the current working directory.
#
#	The code here also does
#
#	0. The directory set by invoking tempdir with an argument.
#	   If this is present it is used exclusively.
#
# Arguments:
#	None.
#
# Side Effects:
#	None.
#
# Results:
#	The directory for temporary files.

proc fileutil_tempdir {args} {
    if {[llength $args] > 1} {
	return -code error {wrong#args: should be "::fileutil_tempdir ?path?"}
    } elseif {[llength $args] == 1} {
	global tempdir
	set tempdir [lindex $args 0]
	global tempdirSet
	set tempdirSet 1
	return
    }
    return [fileutil_Normalize [TempDir]]
}

proc fileutil_tempdirReset {} {
    global tempdir
    set tempdir    {}
    global tempdirSet
    set tempdirSet 0
    return
}

proc fileutil_TempDir {} {
    global tcl_platform env tempdir tempdirSet

    set attempdirs [list]
    set problems   {}

    if {$tempdirSet} {
	lappend attempdirs $tempdir
	lappend problems {User/Application specified tempdir}
    } else {
	foreach tmp {TMPDIR TEMP TMP} {
	    if { [info exists env($tmp)] } {
		lappend attempdirs $env($tmp)
	    } else {
		lappend problems "No environment variable $tmp"
	    }
	}

	switch $tcl_platform(platform) {
	    windows {
		lappend attempdirs "C:\\TEMP" "C:\\TMP" "\\TEMP" "\\TMP"
	    }
	    macintosh {
		lappend attempdirs $env(TRASH_FOLDER)  ;# a better place?
	    }
	    default {
		lappend attempdirs \
		    [file join / tmp] \
		    [file join / var tmp] \
		    [file join / usr tmp]
	    }
	}

	lappend attempdirs [pwd]
    }

    foreach tmp $attempdirs {
	if { [file isdirectory $tmp] && [file writable $tmp] } {
	    return $tmp
	} elseif { ![file isdirectory $tmp] } {
	    lappend problems "Not a directory: $tmp"
	} else {
	    lappend problems "Not writable: $tmp"
	}
    }

    # Fail if nothing worked.
    return -code error "Unable to determine a proper directory for temporary files\n[join $problems \n]"
}

set tempdir {}
set tempdirSet 0

# ::fileutil_tempfile --
#
#   generate a temporary file name suitable for writing to
#   the file name will be unique, writable and will be in the 
#   appropriate system specific temp directory
#   Code taken from http://mini.net/tcl/772 attributed to
#    Igor Volobouev and anon.
#
# Arguments:
#   prefix     - a prefix for the filename, p
# Results:
#   returns a file name
#

proc fileutil_tempfile {{prefix {}}} {
    return [fileutil_Normalize [TempFile $prefix]]
}

proc fileutil_TempFile {prefix} {
    set tmpdir [tempdir]

    set chars       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    set nrand_chars 10
    set maxtries    10
    set access      [list RDWR CREAT EXCL]
    set permission  0600
    set channel ""
    set checked_dir_writable 0

    for {set i 0} {$i < $maxtries} {incr i} {
 	set newname $prefix
 	for {set j 0} {$j < $nrand_chars} {incr j} {
 	    append newname [string index $chars \
		    [expr {int(rand()*62)}]]
 	}
	set newname [file join $tmpdir $newname]

	if {[catch {open $newname $access $permission} channel]} {
	    if {!$checked_dir_writable} {
		set dirname [file dirname $newname]
		if {![file writable $dirname]} {
		    return -code error "Directory $dirname is not writable"
		}
		set checked_dir_writable 1
	    }
	} else {
	    # Success
	    close $channel
	    return $newname
	}

    }
    if {[string compare $channel ""]} {
 	return -code error "Failed to open a temporary file: $channel"
    } else {
 	return -code error "Failed to find an unused temporary file name"
    }
}

# ::fileutil_install --
#
#	Tcl version of the 'install' command, which copies files from
#	one places to another and also optionally sets some attributes
#	such as group, owner, and permissions.
#
# Arguments:
#	-m		Change the file permissions to the specified
#                       value.  Valid arguments are those accepted by
#			file attributes -permissions
#
# Results:
#	None.

# TODO - add options for group/owner manipulation.

proc fileutil_install {args} {
    set options {
	{m.arg "" "Set permission mode"}
    }
    set usage ": [lindex [info level 0] 0]\
\[options] source destination \noptions:"
    array set params [::cmdline::getoptions args $options $usage]
    # Args should now just be the source and destination.
    if { [llength $args] < 2 } {
	return -code error $usage
    }
    set src [lindex $args 0]
    set dst [lindex $args 1]
    file copy -force $src $dst
    if { $params(m) != "" } {
	set targets [::fileutil_find $dst]
	foreach fl $targets {
	    file attributes $fl -permissions $params(m)
	}
    }
}

# ### ### ### ######### ######### #########

proc fileutil_lexnormalize {sp} {
    set spx [file split $sp]

    # Resolution of embedded relative modifiers (., and ..).

    if {
	([lsearch -exact $spx . ] < 0) &&
	([lsearch -exact $spx ..] < 0)
    } {
	# Quick path out if there are no relative modifiers
	return $sp
    }

    set absolute [expr {![string equal [file pathtype $sp] relative]}]
    # A volumerelative path counts as absolute for our purposes.

    set sp $spx
    set np {}
    set noskip 1

    while {[llength $sp]} {
	set ele    [lindex $sp 0]
	set sp     [lrange $sp 1 end]
	set islast [expr {[llength $sp] == 0}]

	if {[string equal $ele ".."]} {
	    if {
		($absolute  && ([llength $np] >  1)) ||
		(!$absolute && ([llength $np] >= 1))
	    } {
		# .. : Remove the previous element added to the
		# new path, if there actually is enough to remove.
		set np [lrange $np 0 end-1]
	    }
	} elseif {[string equal $ele "."]} {
	    # Ignore .'s, they stay at the current location
	    continue
	} else {
	    # A regular element.
	    lappend np $ele
	}
    }
    if {[llength $np] > 0} {
	return [eval [linsert $np 0 file join]]
	# 8.5: return [file join {*}$np]
    }
    return {}
}

# ### ### ### ######### ######### #########
## Forward compatibility. Some routines require path normalization,
## something we have supported by the builtin 'file' only since Tcl
## 8.4. For versions of Tcl before that, to be supported by the
## module, we implement a normalizer in Tcl itself. Slow, but working.

if {[package vcompare [package provide Tcl] 8.4] < 0} {
    # Pre 8.4. We do not have 'file-normalize'. We create an
    # approximation for it based on earlier commands.

    # ... Hm. This is lexical normalization. It does not resolve
    # symlinks in the path to their origin.

    proc fileutil_Normalize {sp} {
	set sp [file split $sp]

	# Conversion of the incoming path to absolute.
	if {[string equal [file pathtype [lindex $sp 0]] "relative"]} {
	    set sp [file split [eval [list file join [pwd]] $sp]]
	}

	# Resolution of symlink components, and embedded relative
	# modifiers (., and ..).

	set np {}
	set noskip 1
	while {[llength $sp]} {
	    set ele    [lindex $sp 0]
	    set sp     [lrange $sp 1 end]
	    set islast [expr {[llength $sp] == 0}]

	    if {[string equal $ele ".."]} {
		if {[llength $np] > 1} {
		    # .. : Remove the previous element added to the
		    # new path, if there actually is enough to remove.
		    set np [lrange $np 0 end-1]
		}
	    } elseif {[string equal $ele "."]} {
		# Ignore .'s, they stay at the current location
		continue
	    } else {
		# A regular element. If it is not the last component
		# then check if the combination is a symlink, and if
		# yes, resolve it.

		lappend np $ele

		if {!$islast && $noskip} {
		    # The flag 'noskip' is technically not required,
		    # just 'file exists'. However if a path P does not
		    # exist, then all longer paths starting with P can
		    # not exist either, and using the flag to store
		    # this knowledge then saves us a number of
		    # unnecessary stat calls. IOW this a performance
		    # optimization.

		    set p [eval file join $np]
		    set noskip [file exists $p]
		    if {$noskip} {
			if {[string equal link [file type $p]]} {
			    set dst [file readlink $p]

			    # We always push the destination in front of
			    # the source path (in expanded form). So that
			    # we handle .., .'s, and symlinks inside of
			    # this path as well. An absolute path clears
			    # the result, a relative one just removes the
			    # last, now resolved component.

			    set sp [eval [linsert [file split $dst] 0 linsert $sp 0]]

			    if {![string equal relative [file pathtype $dst]]} {
				# Absolute|volrelative destination, clear
				# result, we have to start over.
				set np {}
			    } else {
				# Relative link, just remove the resolved
				# component again.
				set np [lrange $np 0 end-1]
			    }
			}
		    }
		}
	    }
	}
	if {[llength $np] > 0} {
	    return [eval file join $np]
	}
	return {}
    }
} else {
    proc fileutil_Normalize {sp} {
	file-normalize $sp
    }
}

# ::fileutil_relative --
#
#	Taking two _directory_ paths, a base and a destination, computes the path
#	of the destination relative to the base.
#
# Arguments:
#	base	The path to make the destination relative to.
#	dst	The destination path
#
# Results:
#	The path of the destination, relative to the base.

proc fileutil_relative {base dst} {
    # Ensure that the link to directory 'dst' is properly done relative to
    # the directory 'base'.

    if {![string equal [file pathtype $base] [file pathtype $dst]]} {
	return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $base] vs. [file pathtype $dst], ($base vs. $dst)"
    }

    set base [fileutil_lexnormalize [file join [pwd] $base]]
    set dst  [fileutil_lexnormalize [file join [pwd] $dst]]

    set save $dst
    set base [file split $base]
    set dst  [file split $dst]

    while {[string equal [lindex $dst 0] [lindex $base 0]]} {
	set dst  [lrange $dst  1 end]
	set base [lrange $base 1 end]
	if {![llength $dst]} {break}
    }

    set dstlen  [llength $dst]
    set baselen [llength $base]

    if {($dstlen == 0) && ($baselen == 0)} {
	# Cases:
	# (a) base == dst

	set dst .
    } else {
	# Cases:
	# (b) base is: base/sub = sub
	#     dst  is: base     = {}

	# (c) base is: base     = {}
	#     dst  is: base/sub = sub

	while {$baselen > 0} {
	    set dst [linsert $dst 0 ..]
	    incr baselen -1
	}
	# 8.5: set dst [file join {*}$dst]
	set dst [eval [linsert $dst 0 file join]]
    }

    return $dst
}

# ::fileutil_relativeUrl --
#
#	Taking two _file_ paths, a base and a destination, computes the path
#	of the destination relative to the base, from the inside of the base.
#
#	This is how a browser resolves relative links in a file, hence the
#	url in the command name.
#
# Arguments:
#	base	The file path to make the destination relative to.
#	dst	The destination file path
#
# Results:
#	The path of the destination file, relative to the base file.

proc fileutil_relativeUrl {base dst} {
    # Like 'relative', but for links from _inside_ a file to a
    # different file.

    if {![string equal [file pathtype $base] [file pathtype $dst]]} {
	return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $base] vs. [file pathtype $dst], ($base vs. $dst)"
    }

    set base [fileutil_lexnormalize [file join [pwd] $base]]
    set dst  [fileutil_lexnormalize [file join [pwd] $dst]]

    set basedir [file dirname $base]
    set dstdir  [file dirname $dst]

    set dstdir  [relative $basedir $dstdir]

    # dstdir == '.' on input => dstdir output has trailing './'. Strip
    # this superfluous segment off.

    if {[string equal $dstdir "."]} {
	return [file tail $dst]
    } elseif {[string equal [file tail $dstdir] "."]} {
	return [file join [file dirname $dstdir] [file tail $dst]]
    } else {
	return [file join $dstdir [file tail $dst]]
    }
}

# ::fileutil_fullnormalize --
#
#	Normalizes a path completely. I.e. a symlink in the last
#	element is resolved as well, not only symlinks in the higher
#	elements.
#
# Arguments:
#	path	The path to normalize
#
# Results:
#	The input path with all symlinks resolved.

proc fileutil_fullnormalize {path} {
    # When encountering symlinks in a file copy operation Tcl copies
    # the link, not the contents of the file it references. There are
    # situations there this is not acceptable. For these this command
    # resolves all symbolic links in the path, including in the last
    # element of the path. A "file copy" using the return value of
    # this command copies an actual file, it will not encounter
    # symlinks.

    # BUG / WORKAROUND. Using the / instead of the join seems to work
    # around a bug in the path handling on windows which can break the
    # core 'file-normalize' for symbolic links. This was exposed by
    # the find testsuite which could not reproduced outside. I believe
    # that there is some deep path bug in the core triggered under
    # special circumstances. Use of / likely forces a refresh through
    # the string rep and so avoids the problem with the path intrep.

    return [file dirname [fileutil_Normalize $path/__dummy__]]
    #return [file dirname [fileutil_Normalize [file join $path __dummy__]]]
}

set tclver [package present Tcl]
if {$tclver ne {} && [package vsatisfies [package present Tcl] 8.5]} {
    # Tcl 8.5+.
    # We have to check readability of "current" on our own, glob
    # changed to error out instead of returning nothing.

    proc fileutil_ACCESS {args} {}

    proc fileutil_GLOBF {current} {
	if {![file readable $current]} {
	    return {}
	}
	if {([file type $current] eq "link") &&
	    !([file exists   [file readlink $current]] &&
	      [file readable [file readlink $current]])} {
	    return {}
	}

	set res [lsort -unique [concat \
		     [glob -nocomplain -directory $current -types f          -- *] \
		     [glob -nocomplain -directory $current -types {hidden f} -- *]]]

	# Look for broken links (They are reported as neither file nor directory).
	foreach l [lsort -unique [concat \
		       [glob -nocomplain -directory $current -types l          -- *] \
		       [glob -nocomplain -directory $current -types {hidden l} -- *]]] {
	    if {[file isfile      $l]} continue
	    if {[file isdirectory $l]} continue
	    lappend res $l
	}
	return [lsort -unique $res]
    }

    proc fileutil_GLOBD {current} {
	if {![file readable $current]} {
	    return {}
	}
	if {([file type $current] eq "link") &&
	    !([file exists   [file readlink $current]] &&
	      [file readable [file readlink $current]])} {
	    return {}
	}

	lsort -unique [concat \
	    [glob -nocomplain -directory $current -types d          -- *] \
	    [glob -nocomplain -directory $current -types {hidden d} -- *]]
    }

}

Added autosetup/find-tclsh.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
d=`dirname "$0"`
{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
PATH="$PATH:$d/../../../bin:$d"; export PATH
for tclsh in tclsh8.6 tclsh86.exe  tclsh8.5 tclsh85.exe tclsh tclsh.exe jimsh  ; do
	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
	"$d/jimsh0" "$d/test-tclsh" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
echo false

Added autosetup/install.tcl.





































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# @synopsis:
#
# Helper script for Makefiles
#

proc use args {
  foreach pkg $args {
    if {[file exists $::here/${pkg}.tcl]} {
      source $::here/${pkg}.tcl
    } elseif {[file exists $::here/../lib/${pkg}.tcl]} {
      source $::here/../lib/${pkg}.tcl
    } else {
      error "Could not find package $args"
    }
  }
}

set ::here [file dirname [file normalize [info script]]]
use fileutil

proc file-normalize args {
  return [file normalize {*}$args]
}
proc _istcl name {
  return [string match *.tcl $name]
}

###
# topic: ea4ac0a84ae990dafee965b995f48e63
###
proc _istm name {
  return [string match *.tm $name]
}

proc _isdirectory name {
  return [file isdirectory $name]
}

foreach {src dest} $argv {
  set src [file normalize $src]
  set dest [file normalize $dest]
  file mkdir $dest
  foreach {file} [fileutil_find $src _istcl] {
    set relname [fileutil_relative $src $file]
    set destfile [file join $dest $relname]
    file mkdir [file dirname $destfile]
    file copy -force $file [file join $dest $relname]
  }
}

Added autosetup/system.tcl.































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# This module supports common system interrogation and options
# such as --host, --build, --prefix, and setting srcdir, builddir, and EXEXT.
#
# It also support the 'feature' naming convention, where searching
# for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
#
module-options {
	host:host-alias =>		{a complete or partial cpu-vendor-opsys for the system where
							the application will run (defaults to the same value as --build)}
	build:build-alias =>	{a complete or partial cpu-vendor-opsys for the system
							where the application will be built (defaults to the
							result of running config.guess)}
	prefix:dir =>			{the target directory for the build (defaults to /usr/local)}

	# These (hidden) options are supported for autoconf/automake compatibility
	exec-prefix:
	bindir:
	sbindir:
	includedir:
	mandir:
	infodir:
	libexecdir:
	datadir:
	libdir:
	sysconfdir:
	sharedstatedir:
	localstatedir:
	maintainer-mode=0
	dependency-tracking=0
}

# Returns 1 if exists, or 0 if  not
#
proc check-feature {name code} {
	msg-checking "Checking for $name..."
	set r [uplevel 1 $code]
	define-feature $name $r
	if {$r} {
		msg-result "ok"
	} else {
		msg-result "not found"
	}
	return $r
}

# @have-feature name ?default=0?
#
# Returns the value of the feature if defined, or $default if not.
# See 'feature-define-name' for how the feature name
# is translated into the define name.
#
proc have-feature {name {default 0}} {
	get-define [feature-define-name $name] $default
}

# @define-feature name ?value=1?
#
# Sets the feature 'define' to the given value.
# See 'feature-define-name' for how the feature name
# is translated into the define name.
#
proc define-feature {name {value 1}} {
	define [feature-define-name $name] $value
}

# @feature-checked name
#
# Returns 1 if the feature has been checked, whether true or not
#
proc feature-checked {name} {
	is-defined [feature-define-name $name]
}

# @feature-define-name name ?prefix=HAVE_?
#
# Converts a name to the corresponding define,
# e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
#
# Converts * to P and all non-alphanumeric to underscore.
#
proc feature-define-name {name {prefix HAVE_}} {
	string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
}

# If $file doesn't exist, or it's contents are different than $buf,
# the file is written and $script is executed.
# Otherwise a "file is unchanged" message is displayed.
proc write-if-changed {file buf {script {}}} {
	set old [readfile $file ""]
	if {$old eq $buf && [file exists $file]} {
		msg-result "$file is unchanged"
	} else {
		writefile $file $buf\n
		uplevel 1 $script
	}
}

# @make-template template ?outfile?
#
# Reads the input file <srcdir>/$template and writes the output file $outfile.
# If $outfile is blank/omitted, $template should end with ".in" which
# is removed to create the output file name.
#
# Each pattern of the form @define@ is replaced the the corresponding
# define, if it exists, or left unchanged if not.
# 
# The special value @srcdir@ is substituted with the relative
# path to the source directory from the directory where the output
# file is created, while the special value @top_srcdir@ is substituted
# with the relative path to the top level source directory.
#
# Conditional sections may be specified as follows:
## @if name == value
## lines
## @else
## lines
## @endif
#
# Where 'name' is a defined variable name and @else is optional.
# If the expression does not match, all lines through '@endif' are ignored.
#
# The alternative forms may also be used:
## @if name
## @if name != value
#
# Where the first form is true if the variable is defined, but not empty or 0
#
# Currently these expressions can't be nested.
#
proc make-template {template {out {}}} {
	set infile [file join $::autosetup(srcdir) $template]

	if {![file exists $infile]} {
		user-error "Template $template is missing"
	}

	# Define this as late as possible
	define AUTODEPS $::autosetup(deps)

	if {$out eq ""} {
		if {[file ext $template] ne ".in"} {
			autosetup-error "make_template $template has no target file and can't guess"
		}
		set out [file rootname $template]
	}

	set outdir [file dirname $out]

	# Make sure the directory exists
	file mkdir $outdir

	# Set up srcdir and top_srcdir to be relative to the target dir
	define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
	define top_srcdir [relative-path $::autosetup(srcdir) $outdir]

	set mapping {}
	foreach {n v} [array get ::define] {
		lappend mapping @$n@ $v
	}
	set result {}
	foreach line [split [readfile $infile] \n] {
		if {[info exists cond]} {
			set l [string trimright $line]
			if {$l eq "@endif"} {
				unset cond
				continue
			}
			if {$l eq "@else"} {
				set cond [expr {!$cond}]
				continue
			}
			if {$cond} {
				lappend result $line
			}
			continue
		}
		if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
			lassign $expression equal value
			set varval [get-define $name ""]
			if {$equal eq ""} {
				set cond [expr {$varval ni {"" 0}}]
			} else {
				set cond [expr {$varval eq $value}]
				if {$equal ne "=="} {
					set cond [expr {!$cond}]
				}
			}
			continue
		}
		lappend result $line
	}
	writefile $out [string map $mapping [join $result \n]]\n

	msg-result "Created [relative-path $out] from [relative-path $template]"
}

# build/host tuples and cross-compilation prefix
set build [opt-val build]
define build_alias $build
if {$build eq ""} {
	define build [config_guess]
} else {
	define build [config_sub $build]
}

set host [opt-val host]
define host_alias $host
if {$host eq ""} {
	define host [get-define build]
	set cross ""
} else {
	define host [config_sub $host]
	set cross $host-
}
define cross [get-env CROSS $cross]

# Do "define defaultprefix myvalue" to set the default prefix *before* the first "use"
set prefix [opt-val prefix [get-define defaultprefix /usr/local]]

# These are for compatibility with autoconf
define target [get-define host]
define prefix $prefix
define builddir $autosetup(builddir)
define srcdir $autosetup(srcdir)
# Allow this to come from the environment
define top_srcdir [get-env top_srcdir [get-define srcdir]]

# autoconf supports all of these
set exec_prefix [opt-val exec-prefix $prefix]
define exec_prefix $exec_prefix
foreach {name defpath} {
	bindir /bin
	sbindir /sbin
	libexecdir /libexec
	libdir /lib
} {
	define $name [opt-val $name $exec_prefix$defpath]
}
foreach {name defpath} {
	datadir /share
	sysconfdir /etc
	sharedstatedir /com
	localstatedir /var
	infodir /share/info
	mandir /share/man
	includedir /include
} {
	define $name [opt-val $name $prefix$defpath]
}

define SHELL [get-env SHELL [find-an-executable sh bash ksh]]

# Windows vs. non-Windows
switch -glob -- [get-define host] {
	*-*-ming* - *-*-cygwin - *-*-msys {
		define-feature windows
		define EXEEXT .exe
	}
	default {
		define EXEEXT ""
	}
}

# Display
msg-result "Host System...[get-define host]"
msg-result "Build System...[get-define build]"

Added autosetup/test-tclsh.









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# A small Tcl script to verify that the chosen
# interpreter works. Sometimes we might e.g. pick up
# an interpreter for a different arch.
# Outputs the full path to the interpreter

if {[catch {info version} version] == 0} {
	# This is Jim Tcl
	if {$version >= 0.72} {
		# Ensure that regexp works
		regexp (a.*?) a
		puts [info nameofexecutable]
		exit 0
	}
} elseif {[catch {info tclversion} version] == 0} {
	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
		puts [info nameofexecutable]
		exit 0
	}
}
exit 1

Changes to bin/README.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
httpd.tcl	Sample startup script.  To run a server on port 8015, just do:
	wish httpd.tcl -debug 1
		This should work with any Tcl 8.0 or later wish or tclsh.
		To run on a different port and in the background, try:
	tclsh httpd.tcl -port 80 &
		To try out threads, run with a thread-enabled tclsh and do:
	tclsh httpd.tcl -threads 5
		where this means use up to 5 worker threads.

		httpd.tcl depends on both tclhttpd.rc and httpdthread.tcl,
		as well as the packages in ../lib

tclhttpd.rc	Configuration file with default port, etc.
httpdthread.tcl	Per-thread initialization.

tclhttpd.etc.init
		This is a Solaris startup script:
		/etc/init.d/tclhttpd










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
httpd.tcl	Sample startup script.  To run a server on port 8015, just do:
	wish httpd.tcl -debug 1
		This should work with any Tcl 8.0 or later wish or tclsh.
		To run on a different port and in the background, try:
	tclsh httpd.tcl -port 80 &
		To try out threads, run with a thread-enabled tclsh and do:
	tclsh httpd.tcl -threads 5
		where this means use up to 5 worker threads.

		httpd.tcl depends on both tclhttpd.rc and httpdthread.tcl,
		as well as the packages in ../modules/tclhttpd

tclhttpd.rc	Configuration file with default port, etc.
httpdthread.tcl	Per-thread initialization.

tclhttpd.etc.init
		This is a Solaris startup script:
		/etc/init.d/tclhttpd

Changes to bin/httpd.tcl.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# tclhttpd.rc	This has configuration settings like port and host.
#		It is sourced one time by the server during start up
#		before command line arguments are processed.
# httpdthread.tcl	This has the bulk of the initialization code.  It is
#		split out into its own file because it is loaded by
#		by each thread: the main thread and any worker threads
#		created by the "-threads N" command line argument.
# ../lib	The script library that contains most of the TclHttpd
#		implementation
# ../tcllib	The Standard Tcl Library.  TclHttpd ships with a copy
#		of this library because it depends on it.  If you already
#		have copy installed TclHttpd will attempt to find it.
#
# TclHttpd now requires Tcl 8.0 or higher because it depends on some
#	modules in the Standard Tcl Library (tcllib) that use namespaces.







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# tclhttpd.rc	This has configuration settings like port and host.
#		It is sourced one time by the server during start up
#		before command line arguments are processed.
# httpdthread.tcl	This has the bulk of the initialization code.  It is
#		split out into its own file because it is loaded by
#		by each thread: the main thread and any worker threads
#		created by the "-threads N" command line argument.
# ../modules/tclhttpd	The script library that contains most of the TclHttpd
#		implementation
# ../tcllib	The Standard Tcl Library.  TclHttpd ships with a copy
#		of this library because it depends on it.  If you already
#		have copy installed TclHttpd will attempt to find it.
#
# TclHttpd now requires Tcl 8.0 or higher because it depends on some
#	modules in the Standard Tcl Library (tcllib) that use namespaces.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
set home [file join [pwd] $home]

# Auto-detect the configuration
# 1. Development - look for $home/../lib and $home/../../tcllib/modules
# 2. Standalone install - look for $home/../lib/tclhttpd $home/tcllib
# 3. Tcl package install - look for $tcl_library/../tclhttpd

set v 3.5.2

if {[file exist [file join $home ../lib/httpd.tcl]]} {
    # Cases 1 and 2
    set Config(lib) [file join $home ../lib]
} elseif {[file exist [file join $home ../lib/tclhttpd$v]]} {
    # Standard package install (e.g., TclPro)
    # By going one level up, we make all Tcl packages available.
    set Config(lib) [file join $home ../lib]
} else {
    # Hmm - see if Tcl can find it for us.
    tcl_findLibrary tclhttpd $v $v version.tcl TCL_HTTPD_LIBRARY Config(lib)
}
if {![info exist Config(lib)]} {
    error "Cannot find TclHttpd library in auto_path:\n[join $auto_path \n]"
}
# Put the library in front in case there is both the development
# library and an installed library

set auto_path [concat [list $Config(lib)] $auto_path]

# Search around for the Standard Tcl Library
# We used to require "tcllib", but that now causes complaints
# Tcllib 1.6 has inconsistencies with md5 1.4.3 and 2.0.0,
# and requiring 1.0 cures later conflicts with 2.0

if {![catch {package require md5 1}]} {
    # Already available in environment
} elseif {[file exist [file join $home ../tcllib]]} {
    lappend auto_path [file join $home ../tcllib]
} else {
    # Look for the CVS development sources
    set cvs [lindex [lsort -decreasing \
	[glob -nocomplain [file join $home ../../tcllib*]]] 0]







|

|

|













<







|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
set home [file join [pwd] $home]

# Auto-detect the configuration
# 1. Development - look for $home/../lib and $home/../../tcllib/modules
# 2. Standalone install - look for $home/../lib/tclhttpd $home/tcllib
# 3. Tcl package install - look for $tcl_library/../tclhttpd

set v 4.0.0

if {[file exist [file join $home ../modules/httpd/httpd.tcl]]} {
    # Cases 1 and 2
    set Config(lib) [file join $home ../modules]
} elseif {[file exist [file join $home ../lib/tclhttpd$v]]} {
    # Standard package install (e.g., TclPro)
    # By going one level up, we make all Tcl packages available.
    set Config(lib) [file join $home ../lib]
} else {
    # Hmm - see if Tcl can find it for us.
    tcl_findLibrary tclhttpd $v $v version.tcl TCL_HTTPD_LIBRARY Config(lib)
}
if {![info exist Config(lib)]} {
    error "Cannot find TclHttpd library in auto_path:\n[join $auto_path \n]"
}
# Put the library in front in case there is both the development
# library and an installed library

set auto_path [concat [list $Config(lib)] $auto_path]

# Search around for the Standard Tcl Library
# We used to require "tcllib", but that now causes complaints
# Tcllib 1.6 has inconsistencies with md5 1.4.3 and 2.0.0,
# and requiring 1.0 cures later conflicts with 2.0

if {![catch {package require md5 2}]} {
    # Already available in environment
} elseif {[file exist [file join $home ../tcllib]]} {
    lappend auto_path [file join $home ../tcllib]
} else {
    # Look for the CVS development sources
    set cvs [lindex [lsort -decreasing \
	[glob -nocomplain [file join $home ../../tcllib*]]] 0]
206
207
208
209
210
211
212

213



214
215
216
217
218
219
220
    if {[catch {package require httpd::stdin}]} {
	puts "No command loop available"
	set Config(debug) 0
    }
}

if {$Config(compat)} {

    if {[catch {package require httpd::compat}]} {



	puts stderr "tclhttpd$Config(compat) compatibility mode failed."
    } else {
	# Messages here just confuse people
    }
}

###################







>
|
>
>
>







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    if {[catch {package require httpd::stdin}]} {
	puts "No command loop available"
	set Config(debug) 0
    }
}

if {$Config(compat)} {
    if {[catch {
    package require httpd::compat
    httpd::compat_level $Config(compat)

    }]} {
	puts stderr "tclhttpd$Config(compat) compatibility mode failed."
    } else {
	# Messages here just confuse people
    }
}

###################

Changes to bin/httpdthread.tcl.

29
30
31
32
33
34
35

36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
}

# Core modules
package require httpd          	;# Protocol stack
package require httpd::version	;# Version number
package require httpd::url	;# URL dispatching
package require httpd::mtype	;# Mime types


# Search for mime.types either right in Config(lib), or down
# one level in the installed tclhttpd subdirectory

foreach path [list \
    [file join $Config(lib) mime.types] \

    [glob -nocomplain [file join $Config(lib) tclhttpd* mime.types]] \
    ] {
  if {[llength $path] > 0} {
    set path [lindex $path 0]
  }
  if {[file exists $path]} {
    Mtype_ReadTypes $path
    break
  }
}

package require httpd::counter	;# Statistics
Counter_Init $Config(secs)
package require httpd::utils	;# handy stuff like "lassign"

package require httpd::redirect	;# URL redirection
package require httpd::auth	;# Basic authentication
package require httpd::log	;# Standard logging







>



<


>










>







29
30
31
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
}

# Core modules
package require httpd          	;# Protocol stack
package require httpd::version	;# Version number
package require httpd::url	;# URL dispatching
package require httpd::mtype	;# Mime types
package require httpd::bootstrap	;# Mime types

# Search for mime.types either right in Config(lib), or down
# one level in the installed tclhttpd subdirectory

foreach path [list \
    [file join $Config(lib) mime.types] \
    [file join $Config(lib) httpd mime.types] \
    [glob -nocomplain [file join $Config(lib) tclhttpd* mime.types]] \
    ] {
  if {[llength $path] > 0} {
    set path [lindex $path 0]
  }
  if {[file exists $path]} {
    Mtype_ReadTypes $path
    break
  }
}

package require httpd::counter	;# Statistics
Counter_Init $Config(secs)
package require httpd::utils	;# handy stuff like "lassign"

package require httpd::redirect	;# URL redirection
package require httpd::auth	;# Basic authentication
package require httpd::log	;# Standard logging
72
73
74
75
76
77
78


























79
80
81
82
83
84
85
}
# These packages are required for "normal" web servers

# doc
# provides access to files on the local file systems.

package require httpd::doc



























# Doc_Root defines the top-level directory, or folder, for
# your web-visible file structure.

Doc_Root			$Config(docRoot)

# Merge in a second file system into the URL tree.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
}
# These packages are required for "normal" web servers

# doc
# provides access to files on the local file systems.

package require httpd::doc
package require httpd::qwiki

set mainconfig {}
dict set mainconfig filename $Config(MainDatabaseFile)
foreach {f v} [array get Config] {
  dict set mainconfig $f $v
}

tao::class mainclass {
  superclass httpd.qwiki
  
  option docRoot {}
  
  
  ###
  # The main page reads from the docroot
  ###
  method /html resultObj {
    ###
    # By default, act as a conduit to DocRoot
    ###
    ::DocDomain [my cget virtual] [my cget docRoot] [$resultObj sock] [$resultObj cget suffix]
  }
}

mainclass create MAIN / $mainconfig

# Doc_Root defines the top-level directory, or folder, for
# your web-visible file structure.

Doc_Root			$Config(docRoot)

# Merge in a second file system into the URL tree.
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

if {[catch {
    Auth_InitCrypt			;# Probe for crypt module
} err]} {
    catch {puts "No .htaccess support: $err"}
}

# This is currently broken
if {0} {
    package require httpd::safetcl	;# External process running safetcl shells
}

#######################################
# Load Custom Code
#######################################

if {[info exist Config(library)] && [string length $Config(library)]} {
    if {![file isdirectory $Config(library)]} {







<
<
<
<







196
197
198
199
200
201
202




203
204
205
206
207
208
209

if {[catch {
    Auth_InitCrypt			;# Probe for crypt module
} err]} {
    catch {puts "No .htaccess support: $err"}
}






#######################################
# Load Custom Code
#######################################

if {[info exist Config(library)] && [string length $Config(library)]} {
    if {![file isdirectory $Config(library)]} {

Changes to bin/tclhttpd.rc.

221
222
223
224
225
226
227




# Default group file - used if .htaccess doesn't specify AuthGroupFile
# this defaults to the authentication array authdefault()
#Config AuthGroupFile {}

# Default mail servers - the smtp servers to use when sending mail
Config MailServer {}










>
>
>
221
222
223
224
225
226
227
228
229
230

# Default group file - used if .htaccess doesn't specify AuthGroupFile
# this defaults to the authentication array authdefault()
#Config AuthGroupFile {}

# Default mail servers - the smtp servers to use when sending mail
Config MailServer {}

# Default master index file location
Config MainDatabaseFile [file join [Config home] httpd.sqlite]

Added bin/test/common.tcl.



































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#
# Tcl HTTPD
#
# This is the main script for an HTTP server. 
# To test out of the box, do
# tclsh httpd.tcl -debug 1
# or
# wish httpd.tcl -debug 1
#
# For a quick spin, just pass the appropriate settings via the command line.
# For fully custom operation, see the notes in README_custom.
#
# A note about the code structure:
# ../lib	The script library that contains most of the TclHttpd
#		implementation
# ../tcllib	The Standard Tcl Library.  TclHttpd ships with a copy
#		of this library because it depends on it.  If you already
#		have copy installed TclHttpd will attempt to find it.
#
# TclHttpd now requires Tcl 8.0 or higher because it depends on some
#	modules in the Standard Tcl Library (tcllib) that use namespaces.
#	In practice, some of the modules in tcllib may depend on
#	new string commands introduced in Tcl 8.2 and 8.3.  However,
#	the server core only depends on the base64 and ncgi packages
#	that may/should be/are compatible with Tcl 8.0
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 Scriptics Corporation
# Copyright (c) 2001-2002 Panasas
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: httpd.tcl,v 1.61 2006/04/27 00:24:51 wart Exp $
#

# Auto-detect the configuration
# 1. Development - look for $home/../lib and $home/../../tcllib/modules
# 2. Standalone install - look for $home/../lib/tclhttpd $home/tcllib
# 3. Tcl package install - look for $tcl_library/../tclhttpd

set v 4.0.0

# Put the library in front in case there is both the development
# library and an installed library

set auto_path [concat [list $Config(lib)] $auto_path]

# Search around for the Standard Tcl Library
# We used to require "tcllib", but that now causes complaints
# Tcllib 1.6 has inconsistencies with md5 1.4.3 and 2.0.0,
# and requiring 1.0 cures later conflicts with 2.0

if {![catch {package require md5 2}]} {
    # Already available in environment
} elseif {[file exist [file join $home ../tcllib]]} {
    lappend auto_path [file join $home ../tcllib]
} else {
    # Look for the CVS development sources
    set cvs [lindex [lsort -decreasing \
	[glob -nocomplain [file join $home ../../tcllib*]]] 0]
    if {[file exist [file join $cvs modules]]} {
	lappend auto_path [file join $cvs modules]
    } elseif {[file exist [file join $cvs pkgIndex.tcl]]} {
	lappend auto_path $cvs
    } else {
	error "Cannot find Standard Tcl Library in auto_path:\n[join $auto_path \n]"
    }
}

set Config(home) $home
unset home

# Add operating-specific directories to the auto_path for
# the binary extensions

regsub -all { } $tcl_platform(os) {} tmp
foreach dir [list \
	[file join $Config(lib) Binaries $tmp] \
	[file join $Config(lib) Binaries $tmp $tcl_platform(osVersion)] \
	] {
    if {[file isdirectory $dir]} {
	lappend auto_path $dir
    }
}
unset tmp dir

proc ::Config {field args} {
  switch {[llength $args]>1} {
    error "Usage: Config field ?value?"
  }
  global Config
  if {[llength $args]} {
    set Config($field) [lindex $args 0]
  }
  if {[info exists Config($field)]} {
    return $Config($field)
  }
}
##############
# Config file
##############

# Load the configuration file into the Config array
# First, we preload a couple of defaults

set Config(docRoot) [file join [file dirname [Config home]] htdocs]
set Config(library) [file join [file dirname [Config home]] custom]
set Config(main) [file join [Config home] httpdthread.tcl]
set Config(debug) 0
set Config(compat) 3.3

# The configuration bootstrap goes like this:
# 1) Look on the command line for a -config rcfile name argument
# 2) Load this configuration file via the config module
# 3) Process the rest of the command line arguments so the user
#       can override the settings in the rc file with them.

set ix [lsearch $argv -config]
if {$ix >= 0} {
    incr ix
    set Config(config) [lindex $argv $ix]
} else {
    set Config(config) [file join [Config home] tclhttpd.rc]
}

package require httpd 1.6
package require httpd::version		;# For Version proc
package require httpd::utils		;# For Stderr
package require httpd::counter		;# For Count
package require fileutil                ;# For tempdir support: needed on Windows

package require httpd::config		;# for config::init


proc ::cget {field} {
  global Config
  if {[info exists Config($field)]} {
    return $Config($field)
  }
}
proc ::DebugCheckRandomPassword input {
  return 1
}
array set Config {
  debug 1
  port 8015
  https_port	8016
  uid 50
  gid 50
  ipaddr {}
  https_ipaddr {}
  secsPerMinute	60
  threads 0
  gui        1
LogFlushMinutes 0
LogDebug 0
CompressProg gzip
MaxFileDescriptors	256
SSL_REQUEST	0
SSL_REQUIRE	0
SSL_CAFILE 	""
}
Config docroot [file join [Config home] .. htdocs]
Config library [file join [Config home] .. custom]
Config main [file join [Config home]  httpdthread.tcl]
Config host [info hostname]
Config https_host [info hostname]
Config webmaster	webmaster@[info hostname]
Config LogFile [file join [::fileutil::tempdir] log]
Config SSL_CADIR	[file join [file dirname [Config home]] certs])
Config SSL_CERTFILE	[file join [Config SSL_CADIR] server.pem]
Config MailServer {}
# The Config array now reflects the info in the configuration file

#########################
# command line arguments
#########################

# Override config file settings with command line arguments.
# The CommandLineOptions global is known to some of the
# web pages that document the server.

package require cmdline
set CommandLineOptions [list \
        [list virtual.arg      [cget virtual]      {Virtual host config list}] \
        [list config.arg       [cget config]       {Configuration File}] \
        [list main.arg         [cget main]         {Per-Thread Tcl script}] \
        [list docRoot.arg      [cget docRoot]      {Root directory for documents}] \
        [list port.arg         [cget port]         {Port number server is to listen on}] \
        [list host.arg         [cget host]         {Server name, should be fully qualified}] \
        [list ipaddr.arg       [cget ipaddr]       {Interface server should bind to}] \
        [list https_port.arg   [cget https_port]   {SSL Port number}] \
        [list https_host.arg   [cget https_host]   {SSL Server name, should be fully qualified}] \
        [list https_ipaddr.arg [cget https_ipaddr] {Interface SSL server should bind to}] \
        [list webmaster.arg    [cget webmaster]    {E-mail address for errors}] \
        [list uid.arg          [cget uid]          {User Id that server runs under}] \
        [list gid.arg          [cget gid]          {Group Id for caching templates}] \
        [list secs.arg          [cget secsPerMinute] {Seconds per "minute" for time-based histograms}] \
        [list threads.arg      [cget threads]      {Number of worker threads (zero for non-threaded)}] \
        [list library.arg      [cget library]      {Directory list where custom packages and auto loads are}] \
        [list debug.arg	       0	        {If true, start interactive command loop}] \
        [list compat.arg       3.3	        {version compatibility to maintain}] \
        [list gui.arg           [cget gui]      {flag for launching the user interface}] \
        [list mail.arg           [cget MailServer]      {Mail Servers for sending email from tclhttpd}] \
        [list daemon.arg        0      		   {Run in the background as a daemon process.  Requires the 'Expect' package.}] \
    ]
array set Config [cmdline::getoptions argv $CommandLineOptions \
    "usage: httpd.tcl options:"]

if {[string length $Config(library)]} {
    lappend auto_path $Config(library)
}

if {$Config(debug)} {
    puts stderr "auto_path:\n[join $auto_path \n]"
    if {[catch {package require httpd::stdin}]} {
	puts "No command loop available"
	set Config(debug) 0
    }
}

if {$Config(compat)} {
    if {[catch {
    package require httpd::compat
    httpd::compat_level $Config(compat)
    } err]} {
	puts stderr "tclhttpd$Config(compat) compatibility mode failed: $err \n $::errorInfo"
    } else {
	# Messages here just confuse people
    }
}

###################
# Start the server
###################

Httpd_Init
#Counter_Init $Config(secs)

# Open the listening sockets
Httpd_Server $Config(port) $Config(host) $Config(ipaddr)
append startup "httpd started on port $Config(port)\n"

if {[catch {source $Config(main)} message]} then {
    global errorInfo
    set error "Error processing main startup script \"[file nativename $Config(main)]\"."
    append error "\n$errorInfo"
    error $error
}

# The main thread owns the log

Log_CompressProg	[cget CompressProg]
Log_SetFile		[cget LogFile]$Config(port)_
Log_FlushMinutes	[cget LogFlushMinutes]
Log_Flush

Added bin/test/directoo.tcl.



















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/bin/sh
# \
exec tclsh "$0" ${1+"$@"}

############
# auto_path
############

# Configure the auto_path so we can find the script library.
# home is the directory containing this script

set home [string trimright [file dirname [info script]] ./]
set home [file normalize [file join [pwd] $home ..]]
set Config(lib) [file join $home .. modules]

source $home/test/common.tcl

###
# Test for DirectOO
###
package require httpd::directoo

oo::class create ootest {
  superclass httpd.url

  ###
  # title: Implement html content at a toplevel
  ###
  method /html resultObj {
    $resultObj configure title {Welcome!}
    $resultObj puts [my pageHeader]
    $resultObj puts {
Hello World!
<p>
Try the following links:
<ul>
    }
    set prefix [$resultObj cget url_prefix]
    foreach {url comment} {
      errorurl {Throw an internal error from Tcl}
      deadurl  {Page that generates a 505 error}
      suburl   {Valid Suburl}
      missing  {Non-existent url}
    } {
      $resultObj puts "<li><a href=$prefix/$url>$url</a> - $comment</li>"
    }
    $resultObj puts {</ul>}
    $resultObj puts [my pageFooter]
  }

  method /html/errorurl resultObj {
    error "Die Yuppie Scum!"
  }

  method /html/deadurl resultObj {
    $resultObj configure title {Page Error!}
    $resultObj configure code 501
    $resultObj puts [my pageHeader]
    $resultObj puts {
I threw an error this way
    }
    $resultObj puts [my pageFooter]
  }

  ###
  # title: Implement html content at a toplevel
  ###
  method /html/suburl resultObj {
    $resultObj configure title {Sub Url!}
    $resultObj puts [my pageHeader]
    $resultObj puts {Sub Url}
    $resultObj puts "<p><a href=\"[my cget virtual]\">Back</a>"
    $resultObj puts [my pageFooter]
  }

  ###
  # title: Implement html content at a toplevel
  ###
  method /html/default resultObj {
    $resultObj configure title {Not Found}
    $resultObj configure code 404
    $resultObj puts [my pageHeader]
    $resultObj puts "The page: [$resultObj cgi get REQUEST_URI] coult not be cound}
    $resultObj puts "<p><a href=\"[my cget virtual]\">Back</a>"
    $resultObj puts [my pageFooter]
  }
}
ootest create OOTEST /ootest {}

vwait forever
if 0 {
# Start up the user interface and event loop.
package require Tk
package require httpd::srvui
package require httpd::stdin
SrvUI_Init "Tcl HTTPD $Httpd(version)"
Stderr $startup
if {[info commands "console"] == "console"} {
    console show
} else {
    Stdin_Start "httpd % "
    Httpd_Shutdown
}
}

Added bin/test/qwiki.tcl.





































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/bin/sh
# \
exec tclsh "$0" ${1+"$@"}

############
# auto_path
############

# Configure the auto_path so we can find the script library.
# home is the directory containing this script

set home [string trimright [file dirname [info script]] ./]
set home [file normalize [file join [pwd] $home ..]]
set Config(lib) [file join $home .. modules]
set Config(MainDatabaseFile) [file join $home test qwiki.sqlite]
source $home/test/common.tcl

###
# Begin the test
###
package require httpd::qwiki

tao::class qwikitest {
  superclass httpd.qwiki

  ###
  # title: Implement html content at a toplevel
  ###
  method /html resultObj {
    $resultObj configure title {Welcome to Qwiki!}

    $resultObj puts [my pageHeader]
    $resultObj puts {
Hello World!
<p>
    }
    $resultObj puts "Logged in as user: [$resultObj session get username]<br>"
    $resultObj puts "Logged with session: [$resultObj cget sessionid]<br>"
    $resultObj puts {
Try the following links:
<ul>
    }
    set prefix [my cget virtual]
    foreach {url comment} {
      errorurl {Throw an internal error from Tcl}
      deadurl  {Page that generates a 505 error}
      suburl   {Valid Suburl}
      missing  {Non-existent url}
      login    {Log In}
      logout   {Log Out}
    } {
      $resultObj puts "<li><a href=$prefix/$url>$url</a> - $comment</li>"
    }
    $resultObj puts {</ul>}
    $resultObj puts [my pageFooter]
  }

  method /html/errorurl resultObj {
    error "Die Yuppie Scum!"
  }

  method /html/deadurl resultObj {
    $resultObj configure title {Page Error!}
    $resultObj configure code 501
    $resultObj puts [my pageHeader]
    $resultObj puts {
I threw an error this way
    }
    $resultObj puts [my pageFooter]
  }

  ###
  # title: Implement html content at a toplevel
  ###
  method /html/suburl resultObj {
    $resultObj configure title {Sub Url!}
    $resultObj puts [my pageHeader]
    $resultObj puts {Sub Url}
    $resultObj puts "<p><a href=\"[my cget virtual]\">Back</a>"
    $resultObj puts [my pageFooter]
  }

  ###
  # title: Implement html content at a toplevel
  ###
  method /html/default resultObj {
    $resultObj configure title {Not Found}
    $resultObj configure code 404
    $resultObj puts [my pageHeader]
    $resultObj puts "The page: [$resultObj cgi get REQUEST_URI] coult not be cound"
    $resultObj puts "<p><a href=\"[my cget virtual]\">Back</a>"
    $resultObj puts [my pageFooter]
  }
}

qwikitest create HOME /home [list filename [Config MainDatabaseFile]]
HOME task_daily

vwait forever
if 0 {
# Start up the user interface and event loop.
package require Tk
package require httpd::srvui
package require httpd::stdin
SrvUI_Init "Tcl HTTPD $Httpd(version)"
Stderr $startup
if {[info commands "console"] == "console"} {
    console show
} else {
    Stdin_Start "httpd % "
    Httpd_Shutdown
}
}

Changes to bin/util/crypt.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh
# htpass.tcl
# Crude interface to generate encrypted passwords for htaccess files
#
# \
exec expect "$0" ${1+"$@"}

# Obviously, edit this to reference the appropriate crypt .so file
#load /home/welch/cvs/tclhttpd/lib/Binaries/SunOS/5.6/crypt.so
load /usr/lib/tclhttpd3.5.0/libcrypt1.0.so

stty -echo
send_user "Enter a word to crypt: "
expect_user {
    -re "(\[^\n]+)\n" { set pass1 $expect_out(1,string) ; send_user \r\n}
    timeout { send_user timeout\n ; exit 1}
}









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh
# htpass.tcl
# Crude interface to generate encrypted passwords for htaccess files
#
# \
exec expect "$0" ${1+"$@"}

# Obviously, edit this to reference the appropriate crypt .so file
#load /home/welch/cvs/tclhttpd/lib/Binaries/SunOS/5.6/crypt.so
load /usr/lib/tclhttpd4.0.0/libcrypt1.0.so

stty -echo
send_user "Enter a word to crypt: "
expect_user {
    -re "(\[^\n]+)\n" { set pass1 $expect_out(1,string) ; send_user \r\n}
    timeout { send_user timeout\n ; exit 1}
}

Changes to certs/README.ssl.

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
It's signed by your own CA.

You can make any number of certs by repeating steps
two through four again with different file names.

To set up tclhttpd, copy the key and the cert into the
tclhttpd/certs subdirectory.  E.g., 
cd /usr/local/tclhttpd-3.5.1/
mkdir certs
cp /usr/local/ssl/key1.pem certs/skey.pem
cp /usr/local/ssl/demoCA/newcerts/02.pem certs/server.pem

It appears that the default location for the certs directory
is a "bin/certs", a subdirectory of the bin directory.  If
you want to change that, edit bin/tclhttpd.rc and fix







|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
It's signed by your own CA.

You can make any number of certs by repeating steps
two through four again with different file names.

To set up tclhttpd, copy the key and the cert into the
tclhttpd/certs subdirectory.  E.g., 
cd /usr/local/tclhttpd-4.0.0/
mkdir certs
cp /usr/local/ssl/key1.pem certs/skey.pem
cp /usr/local/ssl/demoCA/newcerts/02.pem certs/server.pem

It appears that the default location for the certs directory
is a "bin/certs", a subdirectory of the bin directory.  If
you want to change that, edit bin/tclhttpd.rc and fix

Changes to configure.

1
2
3
4


5

6
7
8



9

















10
11






















































































































































































































































































































































































































































































































































12

13





14







15













16






















17
18








































19















20





































21




















22


23
24


25



26








27
28
29




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49







50
51
52
53

54
55
56
57
58
59

60
61
62
63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78
79
80
81
82
83

84
85
86
87
88


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106



107
108
109



110



111
112
113
114
115
116

117










118



119
120




121
122
123
124
125
126
127
128
129


130

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205






206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231





232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301










302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356

357
358

359
360


361

362
363
364
365
366
367
368
369

370
371

372


373





374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393

394
395










396


397
398
399
400
401
402
403
404
405
406
407
408
409
410

411
412
413
414
415
416
417

418
419
420
421
422
423
424

425
426
427
428
429
430
431
432
433
434
435
436
437
438



439


440
441
442
443
444
445


446


447


448

449
450
451
452
453
454
455

456

457
458

459



460


461
462
463
464
465



466


467
468
469
470
471
472
473
474
475
476




















477
478
479
480
481
482
483
484
485






















486




























































































































































487






















488




















489











490


491















































































































































































































































































































































































































































































































































492


















493


494






495
496

497
498

499
500
501


502

503

504




505
506
507
508




509
510




511

512
513
514
515





























































516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548




549
550
551
552
553
554





555

556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592

593
594
595
596
597
598
599
600
601
602
603
#! /bin/sh

# Guess values for system-dependent variables and create Makefiles.
# Generated automatically using autoconf version 2.13 


# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.

#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.





















# Defaults:
ac_help=






















































































































































































































































































































































































































































































































































ac_default_prefix=/usr/local

# Any additions from configure.in:





ac_help="$ac_help







 --with-serverroot=DIR         Location of where to install the server document tree"













ac_help="$ac_help






















  --enable-gcc            allow use of gcc if available [--disable-gcc]"
ac_help="$ac_help








































  --with-tcl              directory containing tcl configuration (tclConfig.sh)"















ac_help="$ac_help





































 --with-tclinclude      directory containing the public Tcl header files."




















ac_help="$ac_help


  --enable-threads        build with threads"
ac_help="$ac_help


  --enable-shared         build and link with shared libraries [--enable-shared]"



ac_help="$ac_help








  --enable-symbols        build with debugging symbols [--disable-symbols]"

# Initialize some variables set by options.




# The variables have the same names as the options, with
# dashes changed to underlines.
build=NONE
cache_file=./config.cache
exec_prefix=NONE
host=NONE
no_create=
nonopt=NONE
no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=
target=NONE
verbose=
x_includes=NONE
x_libraries=NONE







bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datadir='${prefix}/share'

sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
libdir='${exec_prefix}/lib'
includedir='${prefix}/include'
oldincludedir='/usr/include'

infodir='${prefix}/info'
mandir='${prefix}/man'

# Initialize some other variables.
subdirs=
MFLAGS= MAKEFLAGS=
SHELL=${CONFIG_SHELL-/bin/sh}
# Maximum number of lines to put in a shell here document.
ac_max_here_lines=12

ac_prev=

for ac_option
do

  # If the previous option needs an argument, assign it.
  if test -n "$ac_prev"; then
    eval "$ac_prev=\$ac_option"
    ac_prev=
    continue
  fi

  case "$ac_option" in
  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
  *) ac_optarg= ;;

  esac

  # Accept the important Cygnus configure options, so we can diagnose typos.

  case "$ac_option" in



  -bindir | --bindir | --bindi | --bind | --bin | --bi)
    ac_prev=bindir ;;
  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
    bindir="$ac_optarg" ;;

  -build | --build | --buil | --bui | --bu)
    ac_prev=build ;;
  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
    build="$ac_optarg" ;;

  -cache-file | --cache-file | --cache-fil | --cache-fi \
  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
    ac_prev=cache_file ;;
  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
    cache_file="$ac_optarg" ;;




  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
    ac_prev=datadir ;;
  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \



  | --da=*)



    datadir="$ac_optarg" ;;

  -disable-* | --disable-*)
    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
    # Reject names that are not valid shell variable names.
    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then

      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }










    fi



    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
    eval "enable_${ac_feature}=no" ;;





  -enable-* | --enable-*)
    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
    # Reject names that are not valid shell variable names.
    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
    fi
    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
    case "$ac_option" in


      *=*) ;;

      *) ac_optarg=yes ;;
    esac
    eval "enable_${ac_feature}='$ac_optarg'" ;;

  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
  | --exec | --exe | --ex)
    ac_prev=exec_prefix ;;
  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
  | --exec=* | --exe=* | --ex=*)
    exec_prefix="$ac_optarg" ;;

  -gas | --gas | --ga | --g)
    # Obsolete; use --with-gas.
    with_gas=yes ;;

  -help | --help | --hel | --he)
    # Omit some internal or obsolete options to make the list less imposing.
    # This message is too long to be a string in the A/UX 3.1 sh.
    cat << EOF
Usage: configure [options] [host]
Options: [defaults in brackets after descriptions]
Configuration:
  --cache-file=FILE       cache test results in FILE
  --help                  print this message
  --no-create             do not create output files
  --quiet, --silent       do not print \`checking...' messages
  --version               print the version of autoconf that created configure
Directory and file names:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [$ac_default_prefix]
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                          [same as prefix]
  --bindir=DIR            user executables in DIR [EPREFIX/bin]
  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
  --datadir=DIR           read-only architecture-independent data in DIR
                          [PREFIX/share]
  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
                          [PREFIX/com]
  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
  --includedir=DIR        C header files in DIR [PREFIX/include]
  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
  --infodir=DIR           info documentation in DIR [PREFIX/info]
  --mandir=DIR            man documentation in DIR [PREFIX/man]
  --srcdir=DIR            find the sources in DIR [configure dir or ..]
  --program-prefix=PREFIX prepend PREFIX to installed program names
  --program-suffix=SUFFIX append SUFFIX to installed program names
  --program-transform-name=PROGRAM
                          run sed PROGRAM on installed program names
EOF
    cat << EOF
Host type:
  --build=BUILD           configure for building on BUILD [BUILD=HOST]
  --host=HOST             configure for HOST [guessed]
  --target=TARGET         configure for TARGET [TARGET=HOST]
Features and packages:
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --x-includes=DIR        X include files are in DIR
  --x-libraries=DIR       X library files are in DIR
EOF
    if test -n "$ac_help"; then
      echo "--enable and --with options recognized:$ac_help"
    fi
    exit 0 ;;

  -host | --host | --hos | --ho)
    ac_prev=host ;;
  -host=* | --host=* | --hos=* | --ho=*)






    host="$ac_optarg" ;;

  -includedir | --includedir | --includedi | --included | --include \
  | --includ | --inclu | --incl | --inc)
    ac_prev=includedir ;;
  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
  | --includ=* | --inclu=* | --incl=* | --inc=*)
    includedir="$ac_optarg" ;;

  -infodir | --infodir | --infodi | --infod | --info | --inf)
    ac_prev=infodir ;;
  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
    infodir="$ac_optarg" ;;

  -libdir | --libdir | --libdi | --libd)
    ac_prev=libdir ;;
  -libdir=* | --libdir=* | --libdi=* | --libd=*)
    libdir="$ac_optarg" ;;

  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
  | --libexe | --libex | --libe)
    ac_prev=libexecdir ;;
  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
  | --libexe=* | --libex=* | --libe=*)
    libexecdir="$ac_optarg" ;;






  -localstatedir | --localstatedir | --localstatedi | --localstated \
  | --localstate | --localstat | --localsta | --localst \
  | --locals | --local | --loca | --loc | --lo)
    ac_prev=localstatedir ;;
  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
    localstatedir="$ac_optarg" ;;

  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
    ac_prev=mandir ;;
  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
    mandir="$ac_optarg" ;;

  -nfp | --nfp | --nf)
    # Obsolete; use --without-fp.
    with_fp=no ;;

  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
  | --no-cr | --no-c)
    no_create=yes ;;

  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
    no_recursion=yes ;;

  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
  | --oldin | --oldi | --old | --ol | --o)
    ac_prev=oldincludedir ;;
  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
    oldincludedir="$ac_optarg" ;;

  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
    ac_prev=prefix ;;
  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
    prefix="$ac_optarg" ;;

  -program-prefix | --program-prefix | --program-prefi | --program-pref \
  | --program-pre | --program-pr | --program-p)
    ac_prev=program_prefix ;;
  -program-prefix=* | --program-prefix=* | --program-prefi=* \
  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
    program_prefix="$ac_optarg" ;;

  -program-suffix | --program-suffix | --program-suffi | --program-suff \
  | --program-suf | --program-su | --program-s)
    ac_prev=program_suffix ;;
  -program-suffix=* | --program-suffix=* | --program-suffi=* \
  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
    program_suffix="$ac_optarg" ;;

  -program-transform-name | --program-transform-name \
  | --program-transform-nam | --program-transform-na \
  | --program-transform-n | --program-transform- \
  | --program-transform | --program-transfor \
  | --program-transfo | --program-transf \
  | --program-trans | --program-tran \
  | --progr-tra | --program-tr | --program-t)
    ac_prev=program_transform_name ;;
  -program-transform-name=* | --program-transform-name=* \
  | --program-transform-nam=* | --program-transform-na=* \
  | --program-transform-n=* | --program-transform-=* \
  | --program-transform=* | --program-transfor=* \
  | --program-transfo=* | --program-transf=* \
  | --program-trans=* | --program-tran=* \
  | --progr-tra=* | --program-tr=* | --program-t=*)
    program_transform_name="$ac_optarg" ;;











  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil)
    silent=yes ;;

  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
    ac_prev=sbindir ;;
  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
  | --sbi=* | --sb=*)
    sbindir="$ac_optarg" ;;

  -sharedstatedir | --sharedstatedir | --sharedstatedi \
  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
  | --sharedst | --shareds | --shared | --share | --shar \
  | --sha | --sh)
    ac_prev=sharedstatedir ;;
  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
  | --sha=* | --sh=*)
    sharedstatedir="$ac_optarg" ;;

  -site | --site | --sit)
    ac_prev=site ;;
  -site=* | --site=* | --sit=*)
    site="$ac_optarg" ;;

  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
    ac_prev=srcdir ;;
  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
    srcdir="$ac_optarg" ;;

  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
  | --syscon | --sysco | --sysc | --sys | --sy)
    ac_prev=sysconfdir ;;
  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
    sysconfdir="$ac_optarg" ;;

  -target | --target | --targe | --targ | --tar | --ta | --t)
    ac_prev=target ;;
  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
    target="$ac_optarg" ;;

  -v | -verbose | --verbose | --verbos | --verbo | --verb)
    verbose=yes ;;

  -version | --version | --versio | --versi | --vers)
    echo "configure generated by autoconf version 2.13"
    exit 0 ;;

  -with-* | --with-*)
    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
    # Reject names that are not valid shell variable names.
    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then

      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
    fi

    ac_package=`echo $ac_package| sed 's/-/_/g'`
    case "$ac_option" in


      *=*) ;;

      *) ac_optarg=yes ;;
    esac
    eval "with_${ac_package}='$ac_optarg'" ;;

  -without-* | --without-*)
    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
    # Reject names that are not valid shell variable names.
    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then

      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
    fi

    ac_package=`echo $ac_package| sed 's/-/_/g'`


    eval "with_${ac_package}=no" ;;






  --x)
    # Obsolete; use --with-x.
    with_x=yes ;;

  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
  | --x-incl | --x-inc | --x-in | --x-i)
    ac_prev=x_includes ;;
  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
    x_includes="$ac_optarg" ;;

  -x-libraries | --x-libraries | --x-librarie | --x-librari \
  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
    ac_prev=x_libraries ;;
  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
    x_libraries="$ac_optarg" ;;

  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }

    ;;











  *)


    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
      echo "configure: warning: $ac_option: invalid host type" 1>&2
    fi
    if test "x$nonopt" != xNONE; then
      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
    fi
    nonopt="$ac_option"
    ;;

  esac
done

if test -n "$ac_prev"; then
  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }

fi

trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15

# File descriptor usage:
# 0 standard input
# 1 file creation

# 2 errors and warnings
# 3 some systems may open it to /dev/tty
# 4 used on the Kubota Titan
# 6 checking for... messages and results
# 5 compiler messages saved in config.log
if test "$silent" = yes; then
  exec 6>/dev/null

else
  exec 6>&1
fi
exec 5>./config.log

echo "\
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
" 1>&5

# Strip out --no-create and --no-recursion so they do not pile up.
# Also quote any args containing shell metacharacters.
ac_configure_args=
for ac_arg



do


  case "$ac_arg" in
  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
  | --no-cr | --no-c) ;;
  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)


  ac_configure_args="$ac_configure_args '$ac_arg'" ;;


  *) ac_configure_args="$ac_configure_args $ac_arg" ;;


  esac

done

# NLS nuisances.
# Only set these to C if already set.  These must not be set unconditionally
# because not all systems understand e.g. LANG=C (notably SCO).
# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
# Non-C LC_CTYPE values break the ctype check.

if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi

if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi

if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi






# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -rf conftest* confdefs.h
# AIX cpp loses on an empty file, so make sure it contains at least a newline.
echo > confdefs.h




# A filename unique to this package, relative to the directory that


# configure is in, which we can look for to find out if srcdir is correct.
ac_unique_file=bin/httpd.tcl

# Find the source files, if location was not specified.
if test -z "$srcdir"; then
  ac_srcdir_defaulted=yes
  # Try the directory containing this script, then its parent.
  ac_prog=$0
  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.




















  srcdir=$ac_confdir
  if test ! -r $srcdir/$ac_unique_file; then
    srcdir=..
  fi
else
  ac_srcdir_defaulted=no
fi
if test ! -r $srcdir/$ac_unique_file; then
  if test "$ac_srcdir_defaulted" = yes; then






















    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }




























































































































































  else






















    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }




















  fi











fi


srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`


































































































































































































































































































































































































































































































































































# Prefer explicitly selected file to automatically selected ones.


if test -z "$CONFIG_SITE"; then






  if test "x$prefix" != xNONE; then
    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"

  else
    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"

  fi
fi
for ac_site_file in $CONFIG_SITE; do


  if test -r "$ac_site_file"; then

    echo "loading site script $ac_site_file"

    . "$ac_site_file"




  fi
done

if test -r "$cache_file"; then




  echo "loading cache $cache_file"
  . $cache_file




else

  echo "creating cache $cache_file"
  > $cache_file
fi






























































ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='$CPP $CPPFLAGS'
ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
cross_compiling=$ac_cv_prog_cc_cross

ac_exeext=
ac_objext=o
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
  # Stardent Vistra SVR4 grep lacks -e, says [email protected].
  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
    ac_n= ac_c='
' ac_t='	'
  else
    ac_n=-n ac_c= ac_t=
  fi
else
  ac_n= ac_c='\c' ac_t=
fi



ac_aux_dir=
for ac_dir in config $srcdir/config; do
  if test -f $ac_dir/install-sh; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install-sh -c"
    break
  elif test -f $ac_dir/install.sh; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install.sh -c"
    break




  fi
done
if test -z "$ac_aux_dir"; then
  { echo "configure: error: can not find install-sh or install.sh in config $srcdir/config" 1>&2; exit 1; }
fi
ac_config_guess=$ac_aux_dir/config.guess





ac_config_sub=$ac_aux_dir/config.sub

ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.

CONFIGDIR=${srcdir}/config


#--------------------------------------------------------------------
# __CHANGE__
# Set your package name and version numbers here.  The NODOT_VERSION is
# required for constructing the library name on systems that don't like
# dots in library names (Windows).  The VERSION variable is used on the
# other systems.
#--------------------------------------------------------------------

PACKAGE=tclhttpd

MAJOR_VERSION=3
MINOR_VERSION=4
PATCHLEVEL=".3"
RELEASE=`grep Release: ${srcdir}/${PACKAGE}.spec | sed -e 's/Release: *//'`

VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
WIN_VERSION=`echo ${VERSION} | sed -e 's/\.//g'`

TCL_VERSION=8.3.4
TCLLIB_VERSION=1.3
THREAD_VERSION=2.4

# We build two minor packages for the crypt and limit C extensions

CRYPT_PACKAGE=crypt
CRYPT_VERSION="1.0"
WIN_CRYPT_VERSION=`echo ${CRYPT_VERSION} | sed -e 's/\.//g'`
LIMIT_PACKAGE=limit
LIMIT_VERSION="1.0"
WIN_LIMIT_VERSION=`echo ${LIMIT_VERSION} | sed -e 's/\.//g'`


# Check whether --with-serverroot or --without-serverroot was given.
if test "${with_serverroot+set}" = set; then
  withval="$with_serverroot"
  SERVER_ROOT=${withval}
else
  SERVER_ROOT='$(prefix)/$(PACKAGE)'
fi





<

|
>
>
|
>



>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
<
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>
|


>
>
>
>


<
|

<

<








<



>
>
>
>
>
>
>



|
>



<


>
|
|
|
|
|
|
|
|
<


>


<


|




|
|
|
>




|
>
>




|


|

|






|

>
>
>
|

|
>
>
>
|
>
>
>
|


|

<
>
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
|
>
>
>
>


|

|
|
|
|
|
>
>
|
>
|

|








|





|
<
|
<
<
<
<
<
|
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
|


|

>
>
>
>
>
>
|






|




|




|






|

>
>
>
>
>

|
<


|
<
|




|






|













|




|






|






|
















|
>
>
>
>
>
>
>
>
>
>









|










|




|




|






|


|

|




|
|
<


|

<
>
|
<
>
|
|
>
>
|
>
|

|


|

<
>
|
<
>
|
>
>
|
>
>
>
>
>










|






|

|
>


>
>
>
>
>
>
>
>
>
>

>
>
|
|
<
<
<
<
|






|
>


<
|
<
<
|
>
|
<
<
<
<
<
<
>
|
<

<

<
<
<
<
|
<
<
<
|
>
>
>

>
>
|
<
<
<
<
<
>
>
|
>
>
|
>
>

>


|
|
|
|
|
>
|
>
|
|
>
|
>
>
>

>
>
|
|
|
<

>
>
>
|
>
>
|
<




|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|





|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>

>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
>
>
>
>
|
|
>
|
|
>
|
<
|
>
>
|
>
|
>
|
>
>
>
>




>
>
>
>
|
|
>
>
>
>

>
|
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<

|
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<




|
|



|



>
>
>
>



|

|
>
>
>
>
>
|
>
|














|
|
|






|
|
|










>
|
|
<
|







1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741

742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765

766
767

768

769
770
771
772
773
774
775
776

777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794

795
796
797
798
799
800
801
802
803
804
805

806
807
808
809
810

811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864

865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917

918





919





920



































921


922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965

966
967
968

969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090

1091
1092
1093
1094

1095
1096

1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110

1111
1112

1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160




1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171

1172


1173
1174
1175






1176
1177

1178

1179




1180



1181
1182
1183
1184
1185
1186
1187
1188





1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221

1222
1223
1224
1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068

2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162

2163
2164
2165

2166













2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236

2237
2238
2239
2240
2241
2242
2243
2244
#! /bin/sh

# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##

# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi


as_nl='
'
export as_nl
# Printing a long string crashes Solaris 7 /usr/bin/printf.
as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='print -r --'
  as_echo_n='print -rn --'
elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='printf %s\n'
  as_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
    as_echo_n='/usr/ucb/echo -n'
  else
    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    as_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$as_nl"*)
	expr "X$arg" : "X\\(.*\\)$as_nl";
	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
    '
    export as_echo_n_body
    as_echo_n='sh -c $as_echo_n_body as_echo'
  fi
  export as_echo_body
  as_echo='sh -c $as_echo_body as_echo'
fi

# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
  PATH_SEPARATOR=:
  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
      PATH_SEPARATOR=';'
  }
fi


# IFS
# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent editors from complaining about space-tab.
# (If _AS_PATH_WALK were called with IFS unset, it would disable word
# splitting by setting IFS to empty value.)
IFS=" ""	$as_nl"

# Find who we are.  Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
  *[\\/]* ) as_myself=$0 ;;
  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
  done
IFS=$as_save_IFS

     ;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
  as_myself=$0
fi
if test ! -f "$as_myself"; then
  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
  exit 1
fi

# Unset variables that we do not need and which cause bugs (e.g. in
# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
# suppresses any "Segmentation fault" message there.  '((' could
# trigger a bug in pdksh 5.2.14.
for as_var in BASH_ENV ENV MAIL MAILPATH
do eval test x\${$as_var+set} = xset \
  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
done
PS1='$ '
PS2='> '
PS4='+ '

# NLS nuisances.
LC_ALL=C
export LC_ALL
LANGUAGE=C
export LANGUAGE

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH

# Use a proper internal environment variable to ensure we don't fall
  # into an infinite loop, continuously re-executing ourselves.
  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
    _as_can_reexec=no; export _as_can_reexec;
    # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
case $- in # ((((
  *v*x* | *x*v* ) as_opts=-vx ;;
  *v* ) as_opts=-v ;;
  *x* ) as_opts=-x ;;
  * ) as_opts= ;;
esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
as_fn_exit 255
  fi
  # We don't want this to propagate to other subprocesses.
          { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '\${1+\"\$@\"}'='\"\$@\"'
  setopt NO_GLOB_SUBST
else
  case \`(set -o) 2>/dev/null\` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi
"
  as_required="as_fn_return () { (exit \$1); }
as_fn_success () { as_fn_return 0; }
as_fn_failure () { as_fn_return 1; }
as_fn_ret_success () { return 0; }
as_fn_ret_failure () { return 1; }

exitcode=0
as_fn_success || { exitcode=1; echo as_fn_success failed.; }
as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :

else
  exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1
test -x / || exit 1"
  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
test \$(( 1 + 1 )) = 2 || exit 1"
  if (eval "$as_required") 2>/dev/null; then :
  as_have_required=yes
else
  as_have_required=no
fi
  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :

else
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_found=false
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
  as_found=:
  case $as_dir in #(
	 /*)
	   for as_base in sh bash ksh sh5; do
	     # Try only shells that exist, to save several forks.
	     as_shell=$as_dir/$as_base
	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
  CONFIG_SHELL=$as_shell as_have_required=yes
		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
  break 2
fi
fi
	   done;;
       esac
  as_found=false
done
$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
  CONFIG_SHELL=$SHELL as_have_required=yes
fi; }
IFS=$as_save_IFS


      if test "x$CONFIG_SHELL" != x; then :
  export CONFIG_SHELL
             # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
case $- in # ((((
  *v*x* | *x*v* ) as_opts=-vx ;;
  *v* ) as_opts=-v ;;
  *x* ) as_opts=-x ;;
  * ) as_opts= ;;
esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
exit 255
fi

    if test x$as_have_required = xno; then :
  $as_echo "$0: This script requires a shell more modern than all"
  $as_echo "$0: the shells that I found on your system."
  if test x${ZSH_VERSION+set} = xset ; then
    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
  else
    $as_echo "$0: Please tell [email protected] about your system,
$0: including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
  fi
  exit 1
fi
fi
fi
SHELL=${CONFIG_SHELL-/bin/sh}
export SHELL
# Unset more variables known to interfere with behavior of common tools.
CLICOLOR_FORCE= GREP_OPTIONS=
unset CLICOLOR_FORCE GREP_OPTIONS

## --------------------- ##
## M4sh Shell Functions. ##
## --------------------- ##
# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
  { eval $1=; unset $1;}
}
as_unset=as_fn_unset

# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
  return $1
} # as_fn_set_status

# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
  set +e
  as_fn_set_status $1
  exit $1
} # as_fn_exit

# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{

  case $as_dir in #(
  -*) as_dir=./$as_dir;;
  esac
  test -d "$as_dir" || eval $as_mkdir_p || {
    as_dirs=
    while :; do
      case $as_dir in #(
      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
      *) as_qdir=$as_dir;;
      esac
      as_dirs="'$as_qdir' $as_dirs"
      as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_dir" : 'X\(//\)[^/]' \| \
	 X"$as_dir" : 'X\(//\)$' \| \
	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_dir" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
      test -d "$as_dir" && break
    done
    test -z "$as_dirs" || eval "mkdir $as_dirs"
  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"


} # as_fn_mkdir_p

# as_fn_executable_p FILE
# -----------------------
# Test if FILE is an executable regular file.
as_fn_executable_p ()
{
  test -f "$1" && test -x "$1"
} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
  eval 'as_fn_append ()
  {
    eval $1+=\$2
  }'
else
  as_fn_append ()
  {
    eval $1=\$$1\$2
  }
fi # as_fn_append

# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
  eval 'as_fn_arith ()
  {
    as_val=$(( $* ))
  }'
else
  as_fn_arith ()
  {
    as_val=`expr "$@" || test $? -eq 1`
  }
fi # as_fn_arith


# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
  as_status=$1; test $as_status -eq 0 && as_status=1
  if test "$4"; then
    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
  fi
  $as_echo "$as_me: error: $2" >&2
  as_fn_exit $as_status
} # as_fn_error

if expr a : '\(a\)' >/dev/null 2>&1 &&
   test "X`expr 00001 : '.*\(...\)'`" = X001; then
  as_expr=expr
else
  as_expr=false
fi

if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
  as_basename=basename
else
  as_basename=false
fi

if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
  as_dirname=dirname
else
  as_dirname=false
fi

as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
	 X"$0" : 'X\(//\)$' \| \
	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$0" |
    sed '/^.*\/\([^/][^/]*\)\/*$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`

# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits


  as_lineno_1=$LINENO as_lineno_1a=$LINENO
  as_lineno_2=$LINENO as_lineno_2a=$LINENO
  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
  sed -n '
    p
    /[$]LINENO/=
  ' <$as_myself |
    sed '
      s/[$]LINENO.*/&-/
      t lineno
      b
      :lineno
      N
      :loop
      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
      t loop
      s/-\n.*//
    ' >$as_me.lineno &&
  chmod +x "$as_me.lineno" ||
    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }

  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
  # already done that, so ensure we don't try to do so again and fall
  # in an infinite loop.  This has already happened in practice.
  _as_can_reexec=no; export _as_can_reexec
  # Don't try to exec as it changes $[0], causing all sort of problems
  # (the dirname of $[0] is not the place where we might find the
  # original and so on.  Autoconf is especially sensitive to this).
  . "./$as_me.lineno"
  # Exit status is that of the last command.
  exit
}

ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
  case `echo 'xy\c'` in
  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
  xy)  ECHO_C='\c';;
  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
       ECHO_T='	';;
  esac;;
*)
  ECHO_N='-n';;
esac

rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
  rm -f conf$$.dir/conf$$.file
else
  rm -f conf$$.dir
  mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
  if ln -s conf$$.file conf$$ 2>/dev/null; then
    as_ln_s='ln -s'
    # ... but there are two gotchas:
    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
    # In both cases, we have to default to `cp -pR'.
    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
      as_ln_s='cp -pR'
  elif ln conf$$.file conf$$ 2>/dev/null; then
    as_ln_s=ln
  else
    as_ln_s='cp -pR'
  fi
else
  as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null

if mkdir -p . 2>/dev/null; then
  as_mkdir_p='mkdir -p "$as_dir"'
else
  test -d ./-p && rmdir ./-p
  as_mkdir_p=false
fi

as_test_x='test -x'
as_executable_p=as_fn_executable_p

# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"

# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"


test -n "$DJDIR" || exec 7<&0 </dev/null
exec 6>&1

# Name of the host.
# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`

#
# Initializations.
#
ac_default_prefix=/usr/local
ac_clean_files=
ac_config_libobj_dir=.
LIBOBJS=
cross_compiling=no
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME=
PACKAGE_TARNAME=
PACKAGE_VERSION=
PACKAGE_STRING=
PACKAGE_BUGREPORT=
PACKAGE_URL=

ac_unique_file="bin/httpd.tcl"
# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
#  include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
#  include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif"

ac_subst_vars='LTLIBOBJS
LIBOBJS
TCLSH_PROG
SHLIB_LD_LIBS
crypt_LIB_FILE
limit_LIB_FILE
SHARED_BUILD
MAKE_STATIC_LIB
MAKE_SHARED_LIB
MAKE_LIB
LDFLAGS_DEFAULT
CFLAGS_DEFAULT
BUILD_LIMIT
LIMIT_EXTENSION
EGREP
GREP
CPP
CRYPT_OBJS
SHLIB_LDFLAGS
SHLIB_CFLAGS
SHLIB_LD
STLIB_LD
CFLAGS_OPTIMIZE
CFLAGS_DEBUG
CLEANFILES
TCL_INCLUDES
TCL_BUILD_STUB_LIB_SPEC
TCL_STUB_LIB_SPEC
TCL_BUILD_LIB_SPEC
TCL_LIB_SPEC
TCL_STUB_LIB_FILE
TCL_LD_FLAGS
TCL_EXTRA_CFLAGS
TCL_SHLIB_LD_LIBS
TCL_DEFS
TCL_LIBS
TCL_LIB_FILE
TCL_SRC_DIR
TCL_BIN_DIR
TCL_DBGX
RELPATH
CYGPATH
host_os
host_vendor
host_cpu
host
build_os
build_vendor
build_cpu
build
RANLIB
SET_MAKE
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
OBJEXT
EXEEXT
ac_ct_CC
CPPFLAGS
LDFLAGS
CFLAGS
CC
THREAD_VERSION
TCLLIB_VERSION
TCL_VERSION
WIN_LIMIT_VERSION
LIMIT_VERSION
LIMIT_PACKAGE
WIN_CRYPT_VERSION
CRYPT_VERSION
CRYPT_PACKAGE
WIN_VERSION
RELEASE
VERSION
SERVER_ROOT
PACKAGE
CONFIGDIR
target_alias
host_alias
build_alias
LIBS
ECHO_T
ECHO_N
ECHO_C
DEFS
mandir
localedir
libdir
psdir
pdfdir
dvidir
htmldir
infodir
docdir
oldincludedir
includedir
localstatedir
sharedstatedir
sysconfdir
datadir
datarootdir
libexecdir
sbindir
bindir
program_transform_name
prefix
exec_prefix
PACKAGE_URL
PACKAGE_BUGREPORT
PACKAGE_STRING
PACKAGE_VERSION
PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
with_serverroot
enable_gcc

with_tcl
with_tclinclude
enable_threads
enable_shared
enable_symbols
'
      ac_precious_vars='build_alias
host_alias
target_alias
CC
CFLAGS
LDFLAGS
LIBS
CPPFLAGS
CPP'


# Initialize some variables set by options.
ac_init_help=
ac_init_version=false
ac_unrecognized_opts=
ac_unrecognized_sep=
# The variables have the same names as the options, with
# dashes changed to underlines.

cache_file=/dev/null
exec_prefix=NONE

no_create=

no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=

verbose=
x_includes=NONE
x_libraries=NONE

# Installation directory options.
# These are left unexpanded so users can "make install exec_prefix=/foo"
# and all the variables that are supposed to be based on exec_prefix
# by default will actually change.
# Use braces instead of parens because sh, perl, etc. also accept them.
# (The list follows the same order as the GNU Coding Standards.)
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datarootdir='${prefix}/share'
datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'

includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
infodir='${datarootdir}/info'
htmldir='${docdir}'
dvidir='${docdir}'
pdfdir='${docdir}'
psdir='${docdir}'
libdir='${exec_prefix}/lib'
localedir='${datarootdir}/locale'
mandir='${datarootdir}/man'


ac_prev=
ac_dashdash=
for ac_option
do

  # If the previous option needs an argument, assign it.
  if test -n "$ac_prev"; then
    eval $ac_prev=\$ac_option
    ac_prev=
    continue
  fi

  case $ac_option in
  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
  *=)   ac_optarg= ;;
  *)    ac_optarg=yes ;;
  esac

  # Accept the important Cygnus configure options, so we can diagnose typos.

  case $ac_dashdash$ac_option in
  --)
    ac_dashdash=yes ;;

  -bindir | --bindir | --bindi | --bind | --bin | --bi)
    ac_prev=bindir ;;
  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
    bindir=$ac_optarg ;;

  -build | --build | --buil | --bui | --bu)
    ac_prev=build_alias ;;
  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
    build_alias=$ac_optarg ;;

  -cache-file | --cache-file | --cache-fil | --cache-fi \
  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
    ac_prev=cache_file ;;
  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
    cache_file=$ac_optarg ;;

  --config-cache | -C)
    cache_file=config.cache ;;

  -datadir | --datadir | --datadi | --datad)
    ac_prev=datadir ;;
  -datadir=* | --datadir=* | --datadi=* | --datad=*)
    datadir=$ac_optarg ;;

  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
  | --dataroo | --dataro | --datar)
    ac_prev=datarootdir ;;
  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
    datarootdir=$ac_optarg ;;

  -disable-* | --disable-*)
    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
    # Reject names that are not valid shell variable names.

    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid feature name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"enable_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval enable_$ac_useropt=no ;;

  -docdir | --docdir | --docdi | --doc | --do)
    ac_prev=docdir ;;
  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
    docdir=$ac_optarg ;;

  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
    ac_prev=dvidir ;;
  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
    dvidir=$ac_optarg ;;

  -enable-* | --enable-*)
    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid feature name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"enable_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval enable_$ac_useropt=\$ac_optarg ;;

  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
  | --exec | --exe | --ex)
    ac_prev=exec_prefix ;;
  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
  | --exec=* | --exe=* | --ex=*)
    exec_prefix=$ac_optarg ;;

  -gas | --gas | --ga | --g)
    # Obsolete; use --with-gas.
    with_gas=yes ;;

  -help | --help | --hel | --he | -h)

    ac_init_help=long ;;





  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)





    ac_init_help=recursive ;;



































  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)


    ac_init_help=short ;;

  -host | --host | --hos | --ho)
    ac_prev=host_alias ;;
  -host=* | --host=* | --hos=* | --ho=*)
    host_alias=$ac_optarg ;;

  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
    ac_prev=htmldir ;;
  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
  | --ht=*)
    htmldir=$ac_optarg ;;

  -includedir | --includedir | --includedi | --included | --include \
  | --includ | --inclu | --incl | --inc)
    ac_prev=includedir ;;
  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
  | --includ=* | --inclu=* | --incl=* | --inc=*)
    includedir=$ac_optarg ;;

  -infodir | --infodir | --infodi | --infod | --info | --inf)
    ac_prev=infodir ;;
  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
    infodir=$ac_optarg ;;

  -libdir | --libdir | --libdi | --libd)
    ac_prev=libdir ;;
  -libdir=* | --libdir=* | --libdi=* | --libd=*)
    libdir=$ac_optarg ;;

  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
  | --libexe | --libex | --libe)
    ac_prev=libexecdir ;;
  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
  | --libexe=* | --libex=* | --libe=*)
    libexecdir=$ac_optarg ;;

  -localedir | --localedir | --localedi | --localed | --locale)
    ac_prev=localedir ;;
  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
    localedir=$ac_optarg ;;

  -localstatedir | --localstatedir | --localstatedi | --localstated \
  | --localstate | --localstat | --localsta | --localst | --locals)

    ac_prev=localstatedir ;;
  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)

    localstatedir=$ac_optarg ;;

  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
    ac_prev=mandir ;;
  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
    mandir=$ac_optarg ;;

  -nfp | --nfp | --nf)
    # Obsolete; use --without-fp.
    with_fp=no ;;

  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
  | --no-cr | --no-c | -n)
    no_create=yes ;;

  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
    no_recursion=yes ;;

  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
  | --oldin | --oldi | --old | --ol | --o)
    ac_prev=oldincludedir ;;
  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
    oldincludedir=$ac_optarg ;;

  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
    ac_prev=prefix ;;
  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
    prefix=$ac_optarg ;;

  -program-prefix | --program-prefix | --program-prefi | --program-pref \
  | --program-pre | --program-pr | --program-p)
    ac_prev=program_prefix ;;
  -program-prefix=* | --program-prefix=* | --program-prefi=* \
  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
    program_prefix=$ac_optarg ;;

  -program-suffix | --program-suffix | --program-suffi | --program-suff \
  | --program-suf | --program-su | --program-s)
    ac_prev=program_suffix ;;
  -program-suffix=* | --program-suffix=* | --program-suffi=* \
  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
    program_suffix=$ac_optarg ;;

  -program-transform-name | --program-transform-name \
  | --program-transform-nam | --program-transform-na \
  | --program-transform-n | --program-transform- \
  | --program-transform | --program-transfor \
  | --program-transfo | --program-transf \
  | --program-trans | --program-tran \
  | --progr-tra | --program-tr | --program-t)
    ac_prev=program_transform_name ;;
  -program-transform-name=* | --program-transform-name=* \
  | --program-transform-nam=* | --program-transform-na=* \
  | --program-transform-n=* | --program-transform-=* \
  | --program-transform=* | --program-transfor=* \
  | --program-transfo=* | --program-transf=* \
  | --program-trans=* | --program-tran=* \
  | --progr-tra=* | --program-tr=* | --program-t=*)
    program_transform_name=$ac_optarg ;;

  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
    ac_prev=pdfdir ;;
  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
    pdfdir=$ac_optarg ;;

  -psdir | --psdir | --psdi | --psd | --ps)
    ac_prev=psdir ;;
  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
    psdir=$ac_optarg ;;

  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil)
    silent=yes ;;

  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
    ac_prev=sbindir ;;
  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
  | --sbi=* | --sb=*)
    sbindir=$ac_optarg ;;

  -sharedstatedir | --sharedstatedir | --sharedstatedi \
  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
  | --sharedst | --shareds | --shared | --share | --shar \
  | --sha | --sh)
    ac_prev=sharedstatedir ;;
  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
  | --sha=* | --sh=*)
    sharedstatedir=$ac_optarg ;;

  -site | --site | --sit)
    ac_prev=site ;;
  -site=* | --site=* | --sit=*)
    site=$ac_optarg ;;

  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
    ac_prev=srcdir ;;
  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
    srcdir=$ac_optarg ;;

  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
  | --syscon | --sysco | --sysc | --sys | --sy)
    ac_prev=sysconfdir ;;
  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
    sysconfdir=$ac_optarg ;;

  -target | --target | --targe | --targ | --tar | --ta | --t)
    ac_prev=target_alias ;;
  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
    target_alias=$ac_optarg ;;

  -v | -verbose | --verbose | --verbos | --verbo | --verb)
    verbose=yes ;;

  -version | --version | --versio | --versi | --vers | -V)
    ac_init_version=: ;;


  -with-* | --with-*)
    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
    # Reject names that are not valid shell variable names.

    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid package name: $ac_useropt"

    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"with_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval with_$ac_useropt=\$ac_optarg ;;

  -without-* | --without-*)
    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
    # Reject names that are not valid shell variable names.

    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid package name: $ac_useropt"

    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"with_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval with_$ac_useropt=no ;;

  --x)
    # Obsolete; use --with-x.
    with_x=yes ;;

  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
  | --x-incl | --x-inc | --x-in | --x-i)
    ac_prev=x_includes ;;
  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
    x_includes=$ac_optarg ;;

  -x-libraries | --x-libraries | --x-librarie | --x-librari \
  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
    ac_prev=x_libraries ;;
  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
    x_libraries=$ac_optarg ;;

  -*) as_fn_error $? "unrecognized option: \`$ac_option'
Try \`$0 --help' for more information"
    ;;

  *=*)
    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
    # Reject names that are not valid shell variable names.
    case $ac_envvar in #(
      '' | [0-9]* | *[!_$as_cr_alnum]* )
      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
    esac
    eval $ac_envvar=\$ac_optarg
    export $ac_envvar ;;

  *)
    # FIXME: should be removed in autoconf 3.0.
    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2




    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
    ;;

  esac
done

if test -n "$ac_prev"; then
  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
  as_fn_error $? "missing argument to $ac_option"
fi


if test -n "$ac_unrecognized_opts"; then


  case $enable_option_checking in
    no) ;;
    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;






    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
  esac

fi






# Check all directory arguments for consistency.



for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
		datadir sysconfdir sharedstatedir localstatedir includedir \
		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
		libdir localedir mandir
do
  eval ac_val=\$$ac_var
  # Remove trailing slashes.
  case $ac_val in





    */ )
      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
      eval $ac_var=\$ac_val;;
  esac
  # Be sure to have absolute directory names.
  case $ac_val in
    [\\/$]* | ?:[\\/]* )  continue;;
    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
  esac
  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
done

# There might be people who depend on the old broken behavior: `$host'
# used to hold the argument of --host etc.
# FIXME: To remove some day.
build=$build_alias
host=$host_alias
target=$target_alias

# FIXME: To remove some day.
if test "x$host_alias" != x; then
  if test "x$build_alias" = x; then
    cross_compiling=maybe
  elif test "x$build_alias" != "x$host_alias"; then
    cross_compiling=yes
  fi
fi

ac_tool_prefix=
test -n "$host_alias" && ac_tool_prefix=$host_alias-

test "$silent" = yes && exec 6>/dev/null



ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
  as_fn_error $? "working directory cannot be determined"
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
  as_fn_error $? "pwd does not report name of working directory"



# Find the source files, if location was not specified.
if test -z "$srcdir"; then
  ac_srcdir_defaulted=yes
  # Try the directory containing this script, then the parent directory.
  ac_confdir=`$as_dirname -- "$as_myself" ||
$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_myself" : 'X\(//\)[^/]' \| \
	 X"$as_myself" : 'X\(//\)$' \| \
	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_myself" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  srcdir=$ac_confdir
  if test ! -r "$srcdir/$ac_unique_file"; then
    srcdir=..
  fi
else
  ac_srcdir_defaulted=no
fi
if test ! -r "$srcdir/$ac_unique_file"; then
  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
fi
ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
ac_abs_confdir=`(
	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
	pwd)`
# When building in place, set srcdir=.
if test "$ac_abs_confdir" = "$ac_pwd"; then
  srcdir=.
fi
# Remove unnecessary trailing slashes from srcdir.
# Double slashes in file names in object file debugging info
# mess up M-x gdb in Emacs.
case $srcdir in
*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
esac
for ac_var in $ac_precious_vars; do
  eval ac_env_${ac_var}_set=\${${ac_var}+set}
  eval ac_env_${ac_var}_value=\$${ac_var}
  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
  eval ac_cv_env_${ac_var}_value=\$${ac_var}
done

#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures this package to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.

Configuration:
  -h, --help              display this help and exit
      --help=short        display options specific to this package
      --help=recursive    display the short help of all the included packages
  -V, --version           display version information and exit
  -q, --quiet, --silent   do not print \`checking ...' messages
      --cache-file=FILE   cache test results in FILE [disabled]
  -C, --config-cache      alias for \`--cache-file=config.cache'
  -n, --no-create         do not create output files
      --srcdir=DIR        find the sources in DIR [configure dir or \`..']

Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [$ac_default_prefix]
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                          [PREFIX]

By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
an installation prefix other than \`$ac_default_prefix' using \`--prefix',
for instance \`--prefix=\$HOME'.

For better control, use the options below.

Fine tuning of the installation directories:
  --bindir=DIR            user executables [EPREFIX/bin]
  --sbindir=DIR           system admin executables [EPREFIX/sbin]
  --libexecdir=DIR        program executables [EPREFIX/libexec]
  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
  --libdir=DIR            object code libraries [EPREFIX/lib]
  --includedir=DIR        C header files [PREFIX/include]
  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
  --infodir=DIR           info documentation [DATAROOTDIR/info]
  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
  --mandir=DIR            man documentation [DATAROOTDIR/man]
  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
  --htmldir=DIR           html documentation [DOCDIR]
  --dvidir=DIR            dvi documentation [DOCDIR]
  --pdfdir=DIR            pdf documentation [DOCDIR]
  --psdir=DIR             ps documentation [DOCDIR]
_ACEOF

  cat <<\_ACEOF

System types:
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then

  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-gcc            allow use of gcc if available --disable-gcc
  --enable-threads        build with threads
  --enable-shared         build and link with shared libraries --enable-shared
  --enable-symbols        build with debugging symbols --disable-symbols

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
 --with-serverroot=DIR         Location of where to install the server document tree
  --with-tcl              directory containing tcl configuration (tclConfig.sh)
 --with-tclinclude      directory containing the public Tcl header files.

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CPP         C preprocessor

Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.

Report bugs to the package provider.
_ACEOF
ac_status=$?
fi

if test "$ac_init_help" = "recursive"; then
  # If there are subdirs, report their specific --help.
  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
    test -d "$ac_dir" ||
      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
      continue
    ac_builddir=.

case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
  # A ".." for each directory in $ac_dir_suffix.
  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
  case $ac_top_builddir_sub in
  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
  esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix

case $srcdir in
  .)  # We are building in place.
    ac_srcdir=.
    ac_top_srcdir=$ac_top_builddir_sub
    ac_abs_top_srcdir=$ac_pwd ;;
  [\\/]* | ?:[\\/]* )  # Absolute name.
    ac_srcdir=$srcdir$ac_dir_suffix;
    ac_top_srcdir=$srcdir
    ac_abs_top_srcdir=$srcdir ;;
  *) # Relative name.
    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
    ac_top_srcdir=$ac_top_build_prefix$srcdir
    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix

    cd "$ac_dir" || { ac_status=$?; continue; }
    # Check for guested configure.
    if test -f "$ac_srcdir/configure.gnu"; then
      echo &&
      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
    elif test -f "$ac_srcdir/configure"; then
      echo &&
      $SHELL "$ac_srcdir/configure" --help=recursive
    else
      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
    fi || ac_status=$?
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
configure
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
fi

## ------------------------ ##
## Autoconf initialization. ##
## ------------------------ ##

# ac_fn_c_try_compile LINENO
# --------------------------
# Try to compile conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext
  if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_c_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest.$ac_objext; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile

# ac_fn_c_try_link LINENO
# -----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_link ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext conftest$ac_exeext
  if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_c_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest$ac_exeext && {
	 test "$cross_compiling" = yes ||
	 test -x conftest$ac_exeext
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
  # interfere with the next link command; also delete a directory that is
  # left behind by Apple's compiler.  We do this before executing the actions.
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_link

# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
ac_fn_c_check_func ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
#define $2 innocuous_$2

/* System header to define __stub macros and hopefully few prototypes,
    which can conflict with char $2 (); below.
    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
    <limits.h> exists even on freestanding compilers.  */

#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif

#undef $2

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char $2 ();
/* The GNU C library defines this for functions which it implements
    to always fail with ENOSYS.  Some functions are actually named
    something starting with __ and the normal name is an alias.  */
#if defined __stub_$2 || defined __stub___$2
choke me
#endif

int
main ()
{
return $2 ();
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
  eval "$3=yes"
else
  eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_func

# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_cpp ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } > conftest.i && {
	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
	 test ! -s conftest.err
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

    ac_retval=1
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_cpp

# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists, giving a warning if it cannot be compiled using
# the include files in INCLUDES and setting the cache variable VAR
# accordingly.
ac_fn_c_check_header_mongrel ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if eval \${$3+:} false; then :
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
else
  # Is the header compilable?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
$as_echo_n "checking $2 usability... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_header_compiler=yes
else
  ac_header_compiler=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
$as_echo "$ac_header_compiler" >&6; }

# Is the header present?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
$as_echo_n "checking $2 presence... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <$2>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  ac_header_preproc=yes
else
  ac_header_preproc=no
fi
rm -f conftest.err conftest.i conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
$as_echo "$ac_header_preproc" >&6; }

# So?  What about this header?
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
  yes:no: )
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
    ;;
  no:yes:* )
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
    ;;
esac
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
else
  eval "$3=\$ac_header_compiler"
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_mongrel

# ac_fn_c_try_run LINENO
# ----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
# that executables *can* be run.
ac_fn_c_try_run ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then :
  ac_retval=0
else
  $as_echo "$as_me: program exited with status $ac_status" >&5
       $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

       ac_retval=$ac_status
fi
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_run

# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  eval "$3=yes"
else
  eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_compile
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by $as_me, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
cat <<_ASUNAME
## --------- ##
## Platform. ##
## --------- ##

hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`

/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`

_ASUNAME

as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    $as_echo "PATH: $as_dir"
  done
IFS=$as_save_IFS

} >&5

cat >&5 <<_ACEOF


## ----------- ##
## Core tests. ##
## ----------- ##

_ACEOF


# Keep a trace of the command line.
# Strip out --no-create and --no-recursion so they do not pile up.
# Strip out --silent because we don't want to record it for future runs.
# Also quote any args containing shell meta-characters.
# Make two passes to allow for proper duplicate-argument suppression.
ac_configure_args=
ac_configure_args0=
ac_configure_args1=
ac_must_keep_next=false
for ac_pass in 1 2
do
  for ac_arg
  do
    case $ac_arg in
    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
    | -silent | --silent | --silen | --sile | --sil)
      continue ;;
    *\'*)
      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
    esac
    case $ac_pass in
    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
    2)
      as_fn_append ac_configure_args1 " '$ac_arg'"
      if test $ac_must_keep_next = true; then
	ac_must_keep_next=false # Got value, back to normal.
      else
	case $ac_arg in
	  *=* | --config-cache | -C | -disable-* | --disable-* \
	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
	  | -with-* | --with-* | -without-* | --without-* | --x)
	    case "$ac_configure_args0 " in
	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
	    esac
	    ;;
	  -* ) ac_must_keep_next=true ;;
	esac
      fi
      as_fn_append ac_configure_args " '$ac_arg'"
      ;;
    esac
  done
done
{ ac_configure_args0=; unset ac_configure_args0;}
{ ac_configure_args1=; unset ac_configure_args1;}

# When interrupted or exit'd, cleanup temporary files, and complete
# config.log.  We remove comments because anyway the quotes in there
# would cause problems or look ugly.
# WARNING: Use '\'' to represent an apostrophe within the trap.
# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
trap 'exit_status=$?
  # Save into config.log some information that might help in debugging.
  {
    echo

    $as_echo "## ---------------- ##
## Cache variables. ##
## ---------------- ##"
    echo
    # The following way of writing the cache mishandles newlines in values,
(
  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
    eval ac_val=\$$ac_var
    case $ac_val in #(
    *${as_nl}*)
      case $ac_var in #(
      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      esac
      case $ac_var in #(
      _ | IFS | as_nl) ;; #(
      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
      *) { eval $ac_var=; unset $ac_var;} ;;
      esac ;;
    esac
  done
  (set) 2>&1 |
    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
    *${as_nl}ac_space=\ *)
      sed -n \
	"s/'\''/'\''\\\\'\'''\''/g;
	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
      ;; #(
    *)
      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
      ;;
    esac |
    sort
)
    echo

    $as_echo "## ----------------- ##
## Output variables. ##
## ----------------- ##"
    echo
    for ac_var in $ac_subst_vars
    do
      eval ac_val=\$$ac_var
      case $ac_val in
      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
      esac
      $as_echo "$ac_var='\''$ac_val'\''"
    done | sort
    echo

    if test -n "$ac_subst_files"; then
      $as_echo "## ------------------- ##
## File substitutions. ##
## ------------------- ##"
      echo
      for ac_var in $ac_subst_files
      do
	eval ac_val=\$$ac_var
	case $ac_val in
	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
	esac
	$as_echo "$ac_var='\''$ac_val'\''"
      done | sort
      echo
    fi

    if test -s confdefs.h; then
      $as_echo "## ----------- ##
## confdefs.h. ##
## ----------- ##"
      echo
      cat confdefs.h
      echo
    fi
    test "$ac_signal" != 0 &&
      $as_echo "$as_me: caught signal $ac_signal"
    $as_echo "$as_me: exit $exit_status"
  } >&5
  rm -f core *.core core.conftest.* &&
    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
    exit $exit_status
' 0
for ac_signal in 1 2 13 15; do
  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
done
ac_signal=0

# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h

$as_echo "/* confdefs.h */" > confdefs.h

# Predefined preprocessor variables.

cat >>confdefs.h <<_ACEOF
#define PACKAGE_NAME "$PACKAGE_NAME"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_VERSION "$PACKAGE_VERSION"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_STRING "$PACKAGE_STRING"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_URL "$PACKAGE_URL"
_ACEOF


# Let the site file select an alternate cache file if it wants to.
# Prefer an explicitly selected file to automatically selected ones.
ac_site_file1=NONE
ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
  # We do not want a PATH search for config.site.
  case $CONFIG_SITE in #((
    -*)  ac_site_file1=./$CONFIG_SITE;;
    */*) ac_site_file1=$CONFIG_SITE;;
    *)   ac_site_file1=./$CONFIG_SITE;;
  esac
elif test "x$prefix" != xNONE; then
  ac_site_file1=$prefix/share/config.site
  ac_site_file2=$prefix/etc/config.site
else
  ac_site_file1=$ac_default_prefix/share/config.site
  ac_site_file2=$ac_default_prefix/etc/config.site
fi

for ac_site_file in "$ac_site_file1" "$ac_site_file2"
do
  test "x$ac_site_file" = xNONE && continue
  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
$as_echo "$as_me: loading site script $ac_site_file" >&6;}
    sed 's/^/| /' "$ac_site_file" >&5
    . "$ac_site_file" \
      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "failed to load site script $ac_site_file
See \`config.log' for more details" "$LINENO" 5; }
  fi
done

if test -r "$cache_file"; then
  # Some versions of bash will fail to source /dev/null (special files
  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
$as_echo "$as_me: loading cache $cache_file" >&6;}
    case $cache_file in
      [\\/]* | ?:[\\/]* ) . "$cache_file";;
      *)                      . "./$cache_file";;
    esac
  fi
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
$as_echo "$as_me: creating cache $cache_file" >&6;}
  >$cache_file
fi

# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
for ac_var in $ac_precious_vars; do
  eval ac_old_set=\$ac_cv_env_${ac_var}_set
  eval ac_new_set=\$ac_env_${ac_var}_set
  eval ac_old_val=\$ac_cv_env_${ac_var}_value
  eval ac_new_val=\$ac_env_${ac_var}_value
  case $ac_old_set,$ac_new_set in
    set,)
      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
      ac_cache_corrupted=: ;;
    ,set)
      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
      ac_cache_corrupted=: ;;
    ,);;
    *)
      if test "x$ac_old_val" != "x$ac_new_val"; then
	# differences in whitespace do not lead to failure.
	ac_old_val_w=`echo x $ac_old_val`
	ac_new_val_w=`echo x $ac_new_val`
	if test "$ac_old_val_w" != "$ac_new_val_w"; then
	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
	  ac_cache_corrupted=:
	else
	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
	  eval $ac_var=\$ac_old_val
	fi
	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
      fi;;
  esac
  # Pass precious variables to config.status.
  if test "$ac_new_set" = set; then
    case $ac_new_val in
    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
    *) ac_arg=$ac_var=$ac_new_val ;;
    esac
    case " $ac_configure_args " in
      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
    esac
  fi
done
if $ac_cache_corrupted; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
## -------------------- ##

ac_ext=c

ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'

ac_compiler_gnu=$ac_cv_c_compiler_gnu
















ac_aux_dir=
for ac_dir in config "$srcdir"/config; do
  if test -f "$ac_dir/install-sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install-sh -c"
    break
  elif test -f "$ac_dir/install.sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install.sh -c"
    break
  elif test -f "$ac_dir/shtool"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/shtool install -c"
    break
  fi
done
if test -z "$ac_aux_dir"; then
  as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5
fi

# These three variables are undocumented and unsupported,
# and are intended to be withdrawn in a future Autoconf release.
# They can cause serious problems if a builder's source tree is in a directory
# whose full name contains unusual characters.
ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.


CONFIGDIR=${srcdir}/config


#--------------------------------------------------------------------
# __CHANGE__
# Set your package name and version numbers here.  The NODOT_VERSION is
# required for constructing the library name on systems that don't like
# dots in library names (Windows).  The VERSION variable is used on the
# other systems.
#--------------------------------------------------------------------

PACKAGE=tclhttpd

MAJOR_VERSION=4
MINOR_VERSION=0
PATCHLEVEL=".0"
RELEASE=`grep Release: ${srcdir}/${PACKAGE}.spec | sed -e 's/Release: *//'`

VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
WIN_VERSION=`echo ${VERSION} | sed -e 's/\.//g'`

TCL_VERSION=8.6.4
TCLLIB_VERSION=1.6
THREAD_VERSION=2.6

# We build two minor packages for the crypt and limit C extensions

CRYPT_PACKAGE=crypt
CRYPT_VERSION="1.0"
WIN_CRYPT_VERSION=`echo ${CRYPT_VERSION} | sed -e 's/\.//g'`
LIMIT_PACKAGE=limit
LIMIT_VERSION="1.0"
WIN_LIMIT_VERSION=`echo ${LIMIT_VERSION} | sed -e 's/\.//g'`


# Check whether --with-serverroot was given.
if test "${with_serverroot+set}" = set; then :

  withval=$with_serverroot; SERVER_ROOT=${withval}
else
  SERVER_ROOT='$(prefix)/$(PACKAGE)'
fi




619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659






660
661
662
663
664
665
666
667
668
669
670
671












672










673
674




















675

676
677
678

679

680
681
682
683

684
685

686
687















688
689

690
691
692
693
694
695
696





















697



















698
699
700
701
702
703


704

705
706
707
708
709
710

711
712
713

714

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731










































732

733
734



735



736



























































737
738
739
740
741
742
743
744
745
746
747

748
749
750

751
752
753
754
755
756

757



758



759
760


761
762















763


764









765




766

767












768

769



770




771











772


773
774
775
776
777
778
779
780
781
782
783
784
785
786



787


788
789
790
791
792




793
794
795











796















797
798




799



800
801
802
803
804
805
806
807
808
809
810
811
812
813
814

815
816

817
818
819
820
821




822
823








824


825












826
827
828
829
830
831
832
833
834


835


836
837































838
839
840


841



842

843


844




845























846

















847
848
849
850
851
852
853
854






855



856





857
858





























859
860
861
862

863
864



865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880


















881

882












































































883
884
885
886
887
888
889

890
891
892

893

894
895
896
897
898
899
900
901



902
903



904
905
906
907
908
909

910
911
912
913
914




915









916
917
918
919
920
921
922
923
924
925
926











927
928
929
930
931
932
933
934
935
936

937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954

955
956
957
958

959
960
961
962
963
964

965
966

967
968

969
970
971

972
973
974

975
976
977
978
979
980
981
982
983

984
985
986
987
988
989
990
991
992
993
994
995
996


997

998
999

1000
1001
1002

1003
1004
1005
1006
1007
1008

1009
1010






































1011


















1012
1013
1014
1015
1016
1017
1018
1019


1020


1021
1022
1023

1024
1025




1026



















1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043

1044
1045
1046
1047


















1048
1049



1050

1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148


#--------------------------------------------------------------------
# We put this here so that you can compile with -DVERSION="1.2" to
# encode the package version directly into the source files.
#--------------------------------------------------------------------

eval cat >> confdefs.h <<EOF
#define VERSION "${VERSION}"
EOF


#--------------------------------------------------------------------
# Check whether --enable-gcc or --disable-gcc was given.  Do this 
# before AC_CYGWIN is called so the compiler can 
# be fully tested by built-in autoconf tools.
# This macro also calls AC_PROG_CC to set the compiler if --enable-gcc
# was not used.
#--------------------------------------------------------------------


    # Check whether --enable-gcc or --disable-gcc was given.
if test "${enable_gcc+set}" = set; then
  enableval="$enable_gcc"
  ok=$enableval
else
  ok=no
fi

    if test "$ok" = "yes"; then
	CC=gcc
    else
	case "`uname -s`" in
	    *win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)
		CC=cl
	    ;;
	    *)
		CC=${CC-cc}
	    ;;
	esac
    fi






    # Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:664: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
  ac_dummy="$PATH"












  for ac_dir in $ac_dummy; do










    test -z "$ac_dir" && ac_dir=.
    if test -f $ac_dir/$ac_word; then




















      ac_cv_prog_CC="gcc"

      break
    fi
  done

  IFS="$ac_save_ifs"

fi
fi
CC="$ac_cv_prog_CC"
if test -n "$CC"; then

  echo "$ac_t""$CC" 1>&6
else

  echo "$ac_t""no" 1>&6
fi
















if test -z "$CC"; then

  # Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:694: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else





















  if test -n "$CC"; then



















  ac_cv_prog_CC="$CC" # Let the user override the test.
else
  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
  ac_prog_rejected=no
  ac_dummy="$PATH"
  for ac_dir in $ac_dummy; do


    test -z "$ac_dir" && ac_dir=.

    if test -f $ac_dir/$ac_word; then
      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
	continue
      fi
      ac_cv_prog_CC="cc"

      break
    fi
  done

  IFS="$ac_save_ifs"

if test $ac_prog_rejected = yes; then
  # We found a bogon in the path, so make sure we never use it.
  set dummy $ac_cv_prog_CC
  shift
  if test $# -gt 0; then
    # We chose a different compiler from the bogus one.
    # However, it has the same basename, so the bogon will be chosen
    # first if we set CC to just the basename; use the full file name.
    shift
    set dummy "$ac_dir/$ac_word" "$@"
    shift
    ac_cv_prog_CC="$@"
  fi
fi
fi
fi
CC="$ac_cv_prog_CC"










































if test -n "$CC"; then

  echo "$ac_t""$CC" 1>&6
else



  echo "$ac_t""no" 1>&6



fi




























































  if test -z "$CC"; then
    case "`uname -s`" in
    *win32* | *WIN32*)
      # Extract the first word of "cl", so it can be a program name with args.
set dummy cl; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:745: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else

  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else

  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
  ac_dummy="$PATH"
  for ac_dir in $ac_dummy; do
    test -z "$ac_dir" && ac_dir=.
    if test -f $ac_dir/$ac_word; then
      ac_cv_prog_CC="cl"

      break



    fi



  done
  IFS="$ac_save_ifs"


fi
fi















CC="$ac_cv_prog_CC"


if test -n "$CC"; then









  echo "$ac_t""$CC" 1>&6




else

  echo "$ac_t""no" 1>&6












fi

 ;;



    esac




  fi











  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }


fi

echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
echo "configure:777: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5

ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='$CPP $CPPFLAGS'
ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
cross_compiling=$ac_cv_prog_cc_cross

cat > conftest.$ac_ext << EOF




#line 788 "configure"


#include "confdefs.h"

main(){return(0);}
EOF
if { (eval echo configure:793: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then




  ac_cv_prog_cc_works=yes
  # If we can't run a trivial program, we are probably using a cross compiler.
  if (./conftest; exit) 2>/dev/null; then











    ac_cv_prog_cc_cross=no















  else
    ac_cv_prog_cc_cross=yes




  fi



else
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5
  ac_cv_prog_cc_works=no
fi
rm -fr conftest*
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='$CPP $CPPFLAGS'
ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
cross_compiling=$ac_cv_prog_cc_cross

echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
if test $ac_cv_prog_cc_works = no; then

  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi

echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
echo "configure:819: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross





echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
echo "configure:824: checking whether we are using GNU C" >&5








if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then


  echo $ac_n "(cached) $ac_c" 1>&6












else
  cat > conftest.c <<EOF
#ifdef __GNUC__
  yes;
#endif
EOF
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:833: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
  ac_cv_prog_gcc=yes
else


  ac_cv_prog_gcc=no


fi
fi
































echo "$ac_t""$ac_cv_prog_gcc" 1>&6



if test $ac_cv_prog_gcc = yes; then



  GCC=yes

else


  GCC=




fi









































ac_test_CFLAGS="${CFLAGS+set}"
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
echo "configure:852: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else






  echo 'void f(){}' > conftest.c



if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then





  ac_cv_prog_cc_g=yes
else





























  ac_cv_prog_cc_g=no
fi
rm -f conftest*


fi




echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
if test "$ac_test_CFLAGS" = set; then
  CFLAGS="$ac_save_CFLAGS"
elif test $ac_cv_prog_cc_g = yes; then
  if test "$GCC" = yes; then
    CFLAGS="-g -O2"
  else
    CFLAGS="-g"
  fi
else
  if test "$GCC" = yes; then
    CFLAGS="-O2"
  else
    CFLAGS=
  fi
fi

































































































# Find a good install program.  We prefer a C program (faster),
# so one script is as good as another.  But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install

# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"

# ./install, which can be erroneously created by make from ./install.sh.

echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
echo "configure:896: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
  for ac_dir in $PATH; do



    # Account for people who put trailing slashes in PATH elements.
    case "$ac_dir/" in



    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
    *)
      # OSF1 and SCO ODT 3.0 have their own names for install.
      # Don't use installbsd from OSF since it installs stuff as root
      # by default.
      for ac_prog in ginstall scoinst install; do

        if test -f $ac_dir/$ac_prog; then
	  if test $ac_prog = install &&
            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
	    # AIX install.  It has an incompatible calling convention.
	    :




	  else









	    ac_cv_path_install="$ac_dir/$ac_prog -c"
	    break 2
	  fi
	fi
      done
      ;;
    esac
  done
  IFS="$ac_save_IFS"

fi











  if test "${ac_cv_path_install+set}" = set; then
    INSTALL="$ac_cv_path_install"
  else
    # As a last resort, use the slow shell script.  We don't cache a
    # path for INSTALL within a source directory, because that will
    # break other packages using the cache if that directory is
    # removed, or if the path is relative.
    INSTALL="$ac_install_sh"
  fi
fi

echo "$ac_t""$INSTALL" 1>&6

# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'

test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'

test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'


#--------------------------------------------------------------------
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------

echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
echo "configure:954: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`

if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  cat > conftestmake <<\EOF

all:
	@echo 'ac_maketemp="${MAKE}"'
EOF
# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
if test -n "$ac_maketemp"; then

  eval ac_cv_prog_make_${ac_make}_set=yes
else

  eval ac_cv_prog_make_${ac_make}_set=no
fi

rm -f conftestmake
fi
if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then

  echo "$ac_t""yes" 1>&6
  SET_MAKE=
else

  echo "$ac_t""no" 1>&6
  SET_MAKE="MAKE=${MAKE-make}"
fi


#--------------------------------------------------------------------
# Find ranlib
#--------------------------------------------------------------------


# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:988: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  if test -n "$RANLIB"; then
  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
  ac_dummy="$PATH"
  for ac_dir in $ac_dummy; do


    test -z "$ac_dir" && ac_dir=.

    if test -f $ac_dir/$ac_word; then
      ac_cv_prog_RANLIB="ranlib"

      break
    fi
  done

  IFS="$ac_save_ifs"
  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
fi
fi
RANLIB="$ac_cv_prog_RANLIB"
if test -n "$RANLIB"; then

  echo "$ac_t""$RANLIB" 1>&6
else






































  echo "$ac_t""no" 1>&6


















fi


#--------------------------------------------------------------------
# This macro performs additional compiler tests.
#--------------------------------------------------------------------

echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6


echo "configure:1021: checking for Cygwin environment" >&5


if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else

  cat > conftest.$ac_ext <<EOF
#line 1026 "configure"




#include "confdefs.h"




















int main() {

#ifndef __CYGWIN__
#define __CYGWIN__ __CYGWIN32__

#endif
return __CYGWIN__;
; return 0; }
EOF
if { (eval echo configure:1037: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
  rm -rf conftest*
  ac_cv_cygwin=yes
else
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5
  rm -rf conftest*
  ac_cv_cygwin=no

fi
rm -f conftest*
rm -f conftest*
fi



















echo "$ac_t""$ac_cv_cygwin" 1>&6



CYGWIN=

test "$ac_cv_cygwin" = yes && CYGWIN=yes

#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------

echo $ac_n "checking for object suffix""... $ac_c" 1>&6
echo "configure:1059: checking for object suffix" >&5
if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  rm -f conftest*
echo 'int i = 1;' > conftest.$ac_ext
if { (eval echo configure:1065: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
  for ac_file in conftest.*; do
    case $ac_file in
    *.c) ;;
    *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;;
    esac
  done
else
  { echo "configure: error: installation or configuration problem; compiler does not work" 1>&2; exit 1; }
fi
rm -f conftest*
fi

echo "$ac_t""$ac_cv_objext" 1>&6
OBJEXT=$ac_cv_objext
ac_objext=$ac_cv_objext

echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6
echo "configure:1083: checking for mingw32 environment" >&5
if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  cat > conftest.$ac_ext <<EOF
#line 1088 "configure"
#include "confdefs.h"

int main() {
return __MINGW32__;
; return 0; }
EOF
if { (eval echo configure:1095: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
  rm -rf conftest*
  ac_cv_mingw32=yes
else
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5
  rm -rf conftest*
  ac_cv_mingw32=no
fi
rm -f conftest*
rm -f conftest*
fi

echo "$ac_t""$ac_cv_mingw32" 1>&6
MINGW32=
test "$ac_cv_mingw32" = yes && MINGW32=yes


echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
echo "configure:1114: checking for executable suffix" >&5
if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  if test "$CYGWIN" = yes || test "$MINGW32" = yes; then
  ac_cv_exeext=.exe
else
  rm -f conftest*
  echo 'int main () { return 0; }' > conftest.$ac_ext
  ac_cv_exeext=
  if { (eval echo configure:1124: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
    for file in conftest.*; do
      case $file in
      *.c | *.C | *.o | *.obj) ;;
      *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
      esac
    done
  else
    { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; }
  fi
  rm -f conftest*
  test x"${ac_cv_exeext}" = x && ac_cv_exeext=no
fi
fi

EXEEXT=""
test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext}
echo "$ac_t""${ac_cv_exeext}" 1>&6
ac_exeext=$EXEEXT


#--------------------------------------------------------------------
# "cygpath" is used on windows to generate native path names for include
# files.
# These variables should only be used with the compiler and linker since
# they generate native path names.







|

|



|
|






|
|
<
|
















>
>
>
>
>
>
|
|
|
|
|
|




|
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
|
|
>
|
>


|
|
>
|

>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
|
|
|
|
|
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


<

|
|
>
>
|
>
|
|
|
|
|
|
>
|
|
|
>
|
>




|




<
<
|




|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
|

>
>
>
|
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
|
|
|
|
|
|
<
|
|
>
|
<
|
>
|
|
|
|
|
|
>
|
>
>
>
|
>
>
>
|
|
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
|
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>

|
<
<
|
|
<
<
<
<
<
|
|

>
>
>
|
>
>
|
|
<
<
<
>
>
>
>
|
|
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
|
>
>
>
|
<
|
|
<
<
|
|
|
|
|
|
|
<
|
>
|
<
>
|
<
<
<
|
>
>
>
>
|
|
>
>
>
>
>
>
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
|
<
<
<
<
|
>
>
|
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>
>
|
>
>
>
|
>

>
>
|
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
|
|
|
|

>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|
|
>

|
>
>
>
|

|













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







>



>

>
|
|

|
|

|
|
>
>
>

|
>
>
>
|
|
|
|
|
|
>
|

|


>
>
>
>

>
>
>
>
>
>
>
>
>
|
|
|
|
<
<
<
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>

|

|
|

|
|


>
|





|








|
|
|
>
|
|

|
>

|
|
|
|
<
>
|
<
>
|
<
>
|

|
>
|


>
|








>
|
|
|
|
|
|




<
|
|
>
>
|
>
|
|
>
|
|
|
>
|
|


|

>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







|
>
>
|
>
>
|
|

>
|
|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
|
|
|
>
|
<
<
<
<
|
|

<
<
<
|
>

|
<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
>
>
>
|
>
|





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282

2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448

2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477


2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604

2605
2606
2607
2608

2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707


2708
2709





2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720



2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755

2756
2757
2758
2759
2760
2761
2762
2763
2764

2765
2766


2767
2768
2769
2770
2771
2772
2773

2774
2775
2776

2777
2778



2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811

2812




2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914

2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149






3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201

3202
3203

3204
3205

3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234

3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363




3364
3365
3366



3367
3368
3369
3370

3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402



















3403

































































3404
3405
3406
3407
3408
3409
3410


#--------------------------------------------------------------------
# We put this here so that you can compile with -DVERSION="1.2" to
# encode the package version directly into the source files.
#--------------------------------------------------------------------

eval cat >>confdefs.h <<_ACEOF
#define VERSION "${VERSION}"
_ACEOF


#--------------------------------------------------------------------
# Check whether --enable-gcc or --disable-gcc was given.  Do this
# before AC_CYGWIN is called so the compiler can
# be fully tested by built-in autoconf tools.
# This macro also calls AC_PROG_CC to set the compiler if --enable-gcc
# was not used.
#--------------------------------------------------------------------


    # Check whether --enable-gcc was given.
if test "${enable_gcc+set}" = set; then :

  enableval=$enable_gcc; ok=$enableval
else
  ok=no
fi

    if test "$ok" = "yes"; then
	CC=gcc
    else
	case "`uname -s`" in
	    *win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)
		CC=cl
	    ;;
	    *)
		CC=${CC-cc}
	    ;;
	esac
    fi
    ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_CC="${ac_tool_prefix}gcc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_CC"; then
  ac_ct_CC=$CC
  # Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CC"; then
  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_ac_ct_CC="gcc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_CC" = x; then
    CC=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CC=$ac_ct_CC
  fi
else
  CC="$ac_cv_prog_CC"
fi

if test -z "$CC"; then
          if test -n "$ac_tool_prefix"; then
    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_CC="${ac_tool_prefix}cc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  fi
fi
if test -z "$CC"; then
  # Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else

  ac_prog_rejected=no
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
       ac_prog_rejected=yes
       continue
     fi
    ac_cv_prog_CC="cc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

if test $ac_prog_rejected = yes; then
  # We found a bogon in the path, so make sure we never use it.
  set dummy $ac_cv_prog_CC
  shift
  if test $# != 0; then
    # We chose a different compiler from the bogus one.
    # However, it has the same basename, so the bogon will be chosen
    # first if we set CC to just the basename; use the full file name.
    shift


    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
  fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$CC"; then
  if test -n "$ac_tool_prefix"; then
  for ac_prog in cl.exe
  do
    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


    test -n "$CC" && break
  done
fi
if test -z "$CC"; then
  ac_ct_CC=$CC
  for ac_prog in cl.exe
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CC"; then
  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_ac_ct_CC="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$ac_ct_CC" && break
done

  if test "x$ac_ct_CC" = x; then
    CC=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CC=$ac_ct_CC
  fi
fi

fi


test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
See \`config.log' for more details" "$LINENO" 5; }

# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5

set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
  { { ac_try="$ac_compiler $ac_option >&5"

case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    sed '10a\
... rest of stderr output deleted ...
         10q' conftest.err >conftest.er1
    cat conftest.er1 >&5
  fi
  rm -f conftest.er1 conftest.err
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
done

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
$as_echo_n "checking whether the C compiler works... " >&6; }
ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`

# The possible output files:
ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"

ac_rmfiles=
for ac_file in $ac_files
do
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
  esac
done
rm -f $ac_rmfiles

if { { ac_try="$ac_link_default"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link_default") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
# in a Makefile.  We should not override ac_cv_exeext if it was cached,
# so that the user can short-circuit this test for compilers unknown to
# Autoconf.
for ac_file in $ac_files ''
do
  test -f "$ac_file" || continue
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
	;;
    [ab].out )
	# We found the default executable, but exeext='' is most
	# certainly right.
	break;;
    *.* )
	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
	then :; else
	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
	fi
	# We set ac_cv_exeext here because the later test for it is not
	# safe: cross compilers may not add the suffix if given an `-o'
	# argument, so we may need to know it at that point already.
	# Even if this section looks crufty: it has the advantage of
	# actually working.
	break;;
    * )
	break;;
  esac
done
test "$ac_cv_exeext" = no && ac_cv_exeext=

else
  ac_file=''
fi
if test -z "$ac_file"; then :


  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }





$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "C compiler cannot create executables
See \`config.log' for more details" "$LINENO" 5; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi



{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
$as_echo_n "checking for C compiler default output file name... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
$as_echo "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext

rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
$as_echo_n "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  # If both `conftest.exe' and `conftest' are `present' (well, observable)
# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
# work properly (i.e., refer to `conftest.exe'), while it won't with
# `rm'.
for ac_file in conftest.exe conftest conftest.*; do
  test -f "$ac_file" || continue
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
	  break;;
    * ) break;;
  esac
done
else

  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
$as_echo "$ac_cv_exeext" >&6; }


rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext


ac_exeext=$EXEEXT
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdio.h>
int
main ()
{

FILE *f = fopen ("conftest.out", "w");
 return ferror (f) || fclose (f) != 0;


  ;
  return 0;



}
_ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run.  If not, either
# the compiler is broken, or we cross compile.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
$as_echo_n "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
  { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
  if { ac_try='./conftest$ac_cv_exeext'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then
    cross_compiling=no
  else
    if test "$cross_compiling" = maybe; then

	cross_compiling=yes




    else
	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details" "$LINENO" 5; }
    fi
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
$as_echo "$cross_compiling" >&6; }

rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
if ${ac_cv_objext+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
rm -f conftest.o conftest.obj
if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  for ac_file in conftest.o conftest.obj conftest.*; do
  test -f "$ac_file" || continue;
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
       break;;
  esac
done
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of object files: cannot compile
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
$as_echo "$ac_cv_objext" >&6; }
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
if ${ac_cv_c_compiler_gnu+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
#ifndef __GNUC__
       choke me
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_compiler_gnu=yes
else
  ac_compiler_gnu=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
$as_echo "$ac_cv_c_compiler_gnu" >&6; }
if test $ac_compiler_gnu = yes; then
  GCC=yes
else
  GCC=
fi
ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
if ${ac_cv_prog_cc_g+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_save_c_werror_flag=$ac_c_werror_flag
   ac_c_werror_flag=yes
   ac_cv_prog_cc_g=no
   CFLAGS="-g"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_g=yes
else
  CFLAGS=""
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

else
  ac_c_werror_flag=$ac_save_c_werror_flag
	 CFLAGS="-g"
	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_g=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_c_werror_flag=$ac_save_c_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
$as_echo "$ac_cv_prog_cc_g" >&6; }
if test "$ac_test_CFLAGS" = set; then
  CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
  if test "$GCC" = yes; then
    CFLAGS="-g -O2"
  else
    CFLAGS="-g"
  fi
else
  if test "$GCC" = yes; then
    CFLAGS="-O2"
  else
    CFLAGS=
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
if ${ac_cv_prog_cc_c89+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_cv_prog_cc_c89=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdarg.h>
#include <stdio.h>
struct stat;
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
static char *e (p, i)
     char **p;
     int i;
{
  return p[i];
}
static char *f (char * (*g) (char **, int), char **p, ...)
{
  char *s;
  va_list v;
  va_start (v,p);
  s = g (p, va_arg (v,int));
  va_end (v);
  return s;
}

/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
   function prototypes and stuff, but not '\xHH' hex character constants.
   These don't provoke an error unfortunately, instead are silently treated
   as 'x'.  The following induces an error, until -std is added to get
   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
   array size at least.  It's necessary to write '\x00'==0 to get something
   that's true only with -std.  */
int osf4_cc_array ['\x00' == 0 ? 1 : -1];

/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
   inside strings and character constants.  */
#define FOO(x) 'x'
int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];

int test (int i, double x);
struct s1 {int (*f) (int a);};
struct s2 {int (*f) (double a);};
int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
int argc;
char **argv;
int
main ()
{
return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
  ;
  return 0;
}
_ACEOF
for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
  CC="$ac_save_CC $ac_arg"
  if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_c89=$ac_arg
fi
rm -f core conftest.err conftest.$ac_objext
  test "x$ac_cv_prog_cc_c89" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC

fi
# AC_CACHE_VAL
case "x$ac_cv_prog_cc_c89" in
  x)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;;
  xno)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;;
  *)
    CC="$CC $ac_cv_prog_cc_c89"
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
esac
if test "x$ac_cv_prog_cc_c89" != xno; then :

fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu


# Find a good install program.  We prefer a C program (faster),
# so one script is as good as another.  But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install
# AmigaOS /C/install, which installs bootblocks on floppy discs
# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# OS/2's system install, which has a completely different semantic
# ./install, which can be erroneously created by make from ./install.sh.
# Reject install programs that cannot install multiple files.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
$as_echo_n "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
if ${ac_cv_path_install+:} false; then :
  $as_echo_n "(cached) " >&6
else
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    # Account for people who put trailing slashes in PATH elements.
case $as_dir/ in #((
  ./ | .// | /[cC]/* | \
  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
  /usr/ucb/* ) ;;
  *)
    # OSF1 and SCO ODT 3.0 have their own names for install.
    # Don't use installbsd from OSF since it installs stuff as root
    # by default.
    for ac_prog in ginstall scoinst install; do
      for ac_exec_ext in '' $ac_executable_extensions; do
	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
	  if test $ac_prog = install &&
	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
	    # AIX install.  It has an incompatible calling convention.
	    :
	  elif test $ac_prog = install &&
	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
	    # program-specific install script used by HP pwplus--don't use.
	    :
	  else
	    rm -rf conftest.one conftest.two conftest.dir
	    echo one > conftest.one
	    echo two > conftest.two
	    mkdir conftest.dir
	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
	      test -s conftest.one && test -s conftest.two &&
	      test -s conftest.dir/conftest.one &&
	      test -s conftest.dir/conftest.two
	    then
	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
	      break 3
	    fi
	  fi






	fi
      done
    done
    ;;
esac

  done
IFS=$as_save_IFS

rm -rf conftest.one conftest.two conftest.dir

fi
  if test "${ac_cv_path_install+set}" = set; then
    INSTALL=$ac_cv_path_install
  else
    # As a last resort, use the slow shell script.  Don't cache a
    # value for INSTALL within a source directory, because that will
    # break other packages using the cache if that directory is
    # removed, or if the value is a relative name.
    INSTALL=$ac_install_sh
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
$as_echo "$INSTALL" >&6; }

# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'

test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'

test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'


#--------------------------------------------------------------------
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
set x ${MAKE-make}
ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat >conftest.make <<\_ACEOF
SHELL = /bin/sh
all:
	@echo '@@@%%%=$(MAKE)=@@@%%%'
_ACEOF
# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
case `${MAKE-make} -f conftest.make 2>/dev/null` in

  *@@@%%%=?*=@@@%%%*)
    eval ac_cv_prog_make_${ac_make}_set=yes;;

  *)
    eval ac_cv_prog_make_${ac_make}_set=no;;

esac
rm -f conftest.make
fi
if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
  SET_MAKE=
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
  SET_MAKE="MAKE=${MAKE-make}"
fi


#--------------------------------------------------------------------
# Find ranlib
#--------------------------------------------------------------------

if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_RANLIB+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$RANLIB"; then
  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else

as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
$as_echo "$RANLIB" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_RANLIB"; then
  ac_ct_RANLIB=$RANLIB
  # Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_RANLIB"; then
  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_ac_ct_RANLIB="ranlib"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
$as_echo "$ac_ct_RANLIB" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_RANLIB" = x; then
    RANLIB=":"
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    RANLIB=$ac_ct_RANLIB
  fi
else
  RANLIB="$ac_cv_prog_RANLIB"
fi


#--------------------------------------------------------------------
# This macro performs additional compiler tests.
#--------------------------------------------------------------------

# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
$as_echo_n "checking build system type... " >&6; }
if ${ac_cv_build+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
test "x$ac_build_alias" = x &&
  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_build
shift
build_cpu=$1
build_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
build_os=$*
IFS=$ac_save_IFS
case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
$as_echo_n "checking host system type... " >&6; }
if ${ac_cv_host+:} false; then :
  $as_echo_n "(cached) " >&6
else




  if test "x$host_alias" = x; then
  ac_cv_host=$ac_cv_build
else



  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
fi


fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
$as_echo "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_host
shift
host_cpu=$1
host_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
host_os=$*
IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac



case $host_os in
  *cygwin* ) CYGWIN=yes;;
	 * ) CYGWIN=no;;
esac


#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------
























































































#--------------------------------------------------------------------
# "cygpath" is used on windows to generate native path names for include
# files.
# These variables should only be used with the compiler and linker since
# they generate native path names.
1178
1179
1180
1181
1182
1183
1184

1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
    # First, look for one uninstalled.
    # the alternative search directory is invoked by --with-tcl
    #

    if test x"${no_tcl}" = x ; then
	# we reset no_tcl in case something fails here
	no_tcl=true

	# Check whether --with-tcl or --without-tcl was given.
if test "${with_tcl+set}" = set; then
  withval="$with_tcl"
  with_tclconfig=${withval}
fi

	echo $ac_n "checking for Tcl configuration""... $ac_c" 1>&6
echo "configure:1193: checking for Tcl configuration" >&5
	if eval "test \"`echo '$''{'ac_cv_c_tclconfig'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  

	    # First check to see if --with-tcl was specified.
	    if test x"${with_tclconfig}" != x ; then
		if test -f "${with_tclconfig}/tclConfig.sh" ; then
		    ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
		else
		    { echo "configure: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" 1>&2; exit 1; }
		fi
	    fi

	    # then check for a private Tcl installation
	    if test x"${ac_cv_c_tclconfig}" = x ; then
		for i in \
			../tcl \







>
|
|
<
|


|
|
|
|

|






|







3440
3441
3442
3443
3444
3445
3446
3447
3448
3449

3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
    # First, look for one uninstalled.
    # the alternative search directory is invoked by --with-tcl
    #

    if test x"${no_tcl}" = x ; then
	# we reset no_tcl in case something fails here
	no_tcl=true

# Check whether --with-tcl was given.
if test "${with_tcl+set}" = set; then :

  withval=$with_tcl; with_tclconfig=${withval}
fi

	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5
$as_echo_n "checking for Tcl configuration... " >&6; }
	if ${ac_cv_c_tclconfig+:} false; then :
  $as_echo_n "(cached) " >&6
else


	    # First check to see if --with-tcl was specified.
	    if test x"${with_tclconfig}" != x ; then
		if test -f "${with_tclconfig}/tclConfig.sh" ; then
		    ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
		else
		    as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5
		fi
	    fi

	    # then check for a private Tcl installation
	    if test x"${ac_cv_c_tclconfig}" = x ; then
		for i in \
			../tcl \
1218
1219
1220
1221
1222
1223
1224

1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251

1252
1253
1254
1255
1256

1257
1258
1259
1260
1261
1262
1263
1264
1265

1266
1267
1268

1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306

1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356

1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
			break
		    fi
		done
	    fi

	    # check in a few common install locations
	    if test x"${ac_cv_c_tclconfig}" = x ; then

		for i in `ls -d ${prefix}/lib 2>/dev/null` \
			`ls -d /usr/lib 2>/dev/null` \
			`ls -d /usr/local/lib 2>/dev/null` ; do
		    if test -f "$i/tclConfig.sh" ; then
			ac_cv_c_tclconfig=`(cd $i; pwd)`
			break
		    fi
		done
	    fi

	    # check in a few other private locations
	    if test x"${ac_cv_c_tclconfig}" = x ; then
		for i in \
			${srcdir}/../tcl \
			`ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do
		    if test -f "$i/unix/tclConfig.sh" ; then
		    ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
		    break
		fi
		done
	    fi
	
fi


	if test x"${ac_cv_c_tclconfig}" = x ; then
	    TCL_BIN_DIR="# no Tcl configs found"

	    echo "configure: warning: Can't find Tcl configuration definitions" 1>&2
	    exit 0
	else
	    no_tcl=
	    TCL_BIN_DIR=${ac_cv_c_tclconfig}

	    echo "$ac_t""found $TCL_BIN_DIR/tclConfig.sh" 1>&6
	fi
    fi


    echo $ac_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh""... $ac_c" 1>&6
echo "configure:1264: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5

    if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then

        echo "$ac_t""loading" 1>&6
	. $TCL_BIN_DIR/tclConfig.sh
    else

        echo "$ac_t""file not found" 1>&6
    fi

    #
    # The eval is required to do the TCL_DBGX substitution in the
    # TCL_LIB_FILE variable
    #

    eval TCL_LIB_FILE=${TCL_LIB_FILE}
    eval TCL_LIB_FLAG=${TCL_LIB_FLAG}

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


#--------------------------------------------------------------------
# __CHANGE__
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after SC_PATH_TCLCONFIG/SC_LOAD_TCLCONFIG
#--------------------------------------------------------------------



    echo $ac_n "checking for Tcl public headers""... $ac_c" 1>&6
echo "configure:1309: checking for Tcl public headers" >&5

    # Check whether --with-tclinclude or --without-tclinclude was given.
if test "${with_tclinclude+set}" = set; then
  withval="$with_tclinclude"
  with_tclinclude=${withval}
fi


    if test x"${with_tclinclude}" != x ; then
	if test -f "${with_tclinclude}/tcl.h" ; then
	    ac_cv_c_tclh=${with_tclinclude}
	else
	    { echo "configure: error: ${with_tclinclude} directory does not contain Tcl public header file tcl.h" 1>&2; exit 1; }
	fi
    else
	if eval "test \"`echo '$''{'ac_cv_c_tclh'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  
	    # Use the value from --with-tclinclude, if it was given

	    if test x"${with_tclinclude}" != x ; then
		ac_cv_c_tclh=${with_tclinclude}
	    else
		# Check in the includedir, if --prefix was specified

		eval "temp_includedir=${includedir}"
		for i in \
			`ls -d ${TCL_PREFIX}/include 2>/dev/null` \
			`ls -d ${temp_includedir} 2>/dev/null` \
			`ls -d ${TCL_BIN_DIR}/../include 2>/dev/null` \
			/usr/local/include /usr/include ; do
		    if test -f "$i/tcl.h" ; then
			ac_cv_c_tclh=$i
			break
		    fi
		done
	    fi
	
fi

    fi

    # Print a message based on how we determined the include path

    if test x"${ac_cv_c_tclh}" = x ; then
	{ echo "configure: error: tcl.h not found.  Please specify its location with --with-tclinclude" 1>&2; exit 1; }
    else

	echo "$ac_t""${ac_cv_c_tclh}" 1>&6
    fi

    # Convert to a native path and substitute into the output files.

    INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}`

    TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\"

    

#SC_PRIVATE_TCL_HEADERS

#--------------------------------------------------------------------
# __CHANGE__
# A few miscellaneous platform-specific items:
#







>
|




















|





>
|




>
|




|
|


>
|


>
|










|
|
|
|
|
|
|
|
|
|
|
|
|
|
|












>
|
|

|
|
<
|







|


|
|

|



















|







|

>
|








|







3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579

3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
			break
		    fi
		done
	    fi

	    # check in a few common install locations
	    if test x"${ac_cv_c_tclconfig}" = x ; then
		for i in `ls -d ${libdir} 2>/dev/null` \
		        `ls -d ${prefix}/lib 2>/dev/null` \
			`ls -d /usr/lib 2>/dev/null` \
			`ls -d /usr/local/lib 2>/dev/null` ; do
		    if test -f "$i/tclConfig.sh" ; then
			ac_cv_c_tclconfig=`(cd $i; pwd)`
			break
		    fi
		done
	    fi

	    # check in a few other private locations
	    if test x"${ac_cv_c_tclconfig}" = x ; then
		for i in \
			${srcdir}/../tcl \
			`ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do
		    if test -f "$i/unix/tclConfig.sh" ; then
		    ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
		    break
		fi
		done
	    fi

fi


	if test x"${ac_cv_c_tclconfig}" = x ; then
	    TCL_BIN_DIR="# no Tcl configs found"
	    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find Tcl configuration definitions" >&5
$as_echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;}
	    exit 0
	else
	    no_tcl=
	    TCL_BIN_DIR=${ac_cv_c_tclconfig}
	    { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
$as_echo "found $TCL_BIN_DIR/tclConfig.sh" >&6; }
	fi
    fi


    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
$as_echo_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; }

    if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5
$as_echo "loading" >&6; }
	. $TCL_BIN_DIR/tclConfig.sh
    else
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: file not found" >&5
$as_echo "file not found" >&6; }
    fi

    #
    # The eval is required to do the TCL_DBGX substitution in the
    # TCL_LIB_FILE variable
    #

    eval TCL_LIB_FILE=${TCL_LIB_FILE}
    eval TCL_LIB_FLAG=${TCL_LIB_FLAG}


















#--------------------------------------------------------------------
# __CHANGE__
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after SC_PATH_TCLCONFIG/SC_LOAD_TCLCONFIG
#--------------------------------------------------------------------


    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5
$as_echo_n "checking for Tcl public headers... " >&6; }


# Check whether --with-tclinclude was given.
if test "${with_tclinclude+set}" = set; then :

  withval=$with_tclinclude; with_tclinclude=${withval}
fi


    if test x"${with_tclinclude}" != x ; then
	if test -f "${with_tclinclude}/tcl.h" ; then
	    ac_cv_c_tclh=${with_tclinclude}
	else
	    as_fn_error $? "${with_tclinclude} directory does not contain Tcl public header file tcl.h" "$LINENO" 5
	fi
    else
	if ${ac_cv_c_tclh+:} false; then :
  $as_echo_n "(cached) " >&6
else

	    # Use the value from --with-tclinclude, if it was given

	    if test x"${with_tclinclude}" != x ; then
		ac_cv_c_tclh=${with_tclinclude}
	    else
		# Check in the includedir, if --prefix was specified

		eval "temp_includedir=${includedir}"
		for i in \
			`ls -d ${TCL_PREFIX}/include 2>/dev/null` \
			`ls -d ${temp_includedir} 2>/dev/null` \
			`ls -d ${TCL_BIN_DIR}/../include 2>/dev/null` \
			/usr/local/include /usr/include ; do
		    if test -f "$i/tcl.h" ; then
			ac_cv_c_tclh=$i
			break
		    fi
		done
	    fi

fi

    fi

    # Print a message based on how we determined the include path

    if test x"${ac_cv_c_tclh}" = x ; then
	as_fn_error $? "tcl.h not found.  Please specify its location with --with-tclinclude" "$LINENO" 5
    else
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5
$as_echo "${ac_cv_c_tclh}" >&6; }
    fi

    # Convert to a native path and substitute into the output files.

    INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}`

    TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\"



#SC_PRIVATE_TCL_HEADERS

#--------------------------------------------------------------------
# __CHANGE__
# A few miscellaneous platform-specific items:
#
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406

1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430

1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447



1448


1449
1450
1451

1452

1453
1454
1455

1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467

1468

1469
1470
1471
1472
1473
1474
1475
1476
1477

1478
1479
1480

1481

1482
1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517

1518
1519
1520

1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
# Define any extra compiler flags in the PACKAGE_CFLAGS variable.
# These will be appended to the current set of compiler flags for
# your system.
#--------------------------------------------------------------------

case "`uname -s`" in
    *win32* | *WIN32* | *CYGWIN_NT*|*CYGWIN_98*|*CYGWIN_95*)
	cat >> confdefs.h <<EOF
#define BUILD_${PACKAGE} 1
EOF

	CLEANFILES="*.lib *.dll *.exp *.ilk *.pdb vc50.pch"
	
    ;;
    *)
	CLEANFILES=
    ;;
esac

#--------------------------------------------------------------------
# Check whether --enable-threads or --disable-threads was given.
# So far only Tcl responds to this one.
#--------------------------------------------------------------------



    echo $ac_n "checking for building with threads""... $ac_c" 1>&6
echo "configure:1409: checking for building with threads" >&5
    # Check whether --enable-threads or --disable-threads was given.
if test "${enable_threads+set}" = set; then
  enableval="$enable_threads"
  tcl_ok=$enableval
else
  tcl_ok=no
fi


    if test "$tcl_ok" = "yes"; then
	TCL_THREADS=1
	cat >> confdefs.h <<\EOF
#define TCL_THREADS 1
EOF

	cat >> confdefs.h <<\EOF
#define _REENTRANT 1
EOF


	case "`uname -s`" in
	    *win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)

		    echo "$ac_t""yes" 1>&6
		;;
	    *)
		echo $ac_n "checking for pthread_mutex_init in -lpthread""... $ac_c" 1>&6
echo "configure:1436: checking for pthread_mutex_init in -lpthread" >&5
ac_lib_var=`echo pthread'_'pthread_mutex_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  ac_save_LIBS="$LIBS"
LIBS="-lpthread  $LIBS"
cat > conftest.$ac_ext <<EOF
#line 1444 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error.  */
/* We use char because int might match the return type of a gcc2
    builtin and then its argument prototype would still apply.  */



char pthread_mutex_init();



int main() {
pthread_mutex_init()

; return 0; }

EOF
if { (eval echo configure:1455: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
  rm -rf conftest*

  eval "ac_cv_lib_$ac_lib_var=yes"
else
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5
  rm -rf conftest*
  eval "ac_cv_lib_$ac_lib_var=no"
fi
rm -f conftest*
LIBS="$ac_save_LIBS"

fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then

  echo "$ac_t""yes" 1>&6

  tcl_ok=yes
else
  echo "$ac_t""no" 1>&6
tcl_ok=no
fi

		if test "$tcl_ok" = "yes"; then
		    # The space is needed
		    THREADS_LIBS=" -lpthread"

		    echo "$ac_t""yes" 1>&6
		else
		    TCL_THREADS=0

		    echo "$ac_t""no" 1>&6

		    echo "configure: warning: "Don t know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile..."" 1>&2
		fi
		;;
	esac
    else
	TCL_THREADS=0

	echo "$ac_t""no (default)" 1>&6
    fi



#--------------------------------------------------------------------
# The statement below defines a collection of symbols related to
# building as a shared library instead of a static library.
#--------------------------------------------------------------------


    echo $ac_n "checking how to build libraries""... $ac_c" 1>&6
echo "configure:1501: checking how to build libraries" >&5
    # Check whether --enable-shared or --disable-shared was given.
if test "${enable_shared+set}" = set; then
  enableval="$enable_shared"
  tcl_ok=$enableval
else
  tcl_ok=yes
fi


    if test "${enable_shared+set}" = set; then
	enableval="$enable_shared"
	tcl_ok=$enableval
    else
	tcl_ok=yes
    fi

    if test "$tcl_ok" = "yes" ; then

	echo "$ac_t""shared" 1>&6
	SHARED_BUILD=1
    else

	echo "$ac_t""static" 1>&6
	SHARED_BUILD=0
	cat >> confdefs.h <<\EOF
#define STATIC_BUILD 1
EOF

    fi


#--------------------------------------------------------------------
# This macro figures out what flags to use with the compiler/linker
# when building shared/static debug/optimized objects.  This information







|

|


|












>
|
|
|
|
<
|







<
|
<

<
|
<




>
|


|
|
|
<
|

|

|
|
|
|
|
|
>
>
>
|
>
>
|
<
|
>
|
>
|
<
<
>
|

<
<
<
|

|
|
|

<
>
|
>


<
|





>
|


>
|
>
|





>
|










|
|
|
|
<
|













>
|


>
|

<
|
<







3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679

3680
3681
3682
3683
3684
3685
3686
3687

3688

3689

3690

3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701

3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718

3719
3720
3721
3722
3723


3724
3725
3726



3727
3728
3729
3730
3731
3732

3733
3734
3735
3736
3737

3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772

3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793

3794

3795
3796
3797
3798
3799
3800
3801
# Define any extra compiler flags in the PACKAGE_CFLAGS variable.
# These will be appended to the current set of compiler flags for
# your system.
#--------------------------------------------------------------------

case "`uname -s`" in
    *win32* | *WIN32* | *CYGWIN_NT*|*CYGWIN_98*|*CYGWIN_95*)
	cat >>confdefs.h <<_ACEOF
#define BUILD_${PACKAGE} 1
_ACEOF

	CLEANFILES="*.lib *.dll *.exp *.ilk *.pdb vc50.pch"

    ;;
    *)
	CLEANFILES=
    ;;
esac

#--------------------------------------------------------------------
# Check whether --enable-threads or --disable-threads was given.
# So far only Tcl responds to this one.
#--------------------------------------------------------------------



    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5
$as_echo_n "checking for building with threads... " >&6; }
    # Check whether --enable-threads was given.
if test "${enable_threads+set}" = set; then :

  enableval=$enable_threads; tcl_ok=$enableval
else
  tcl_ok=no
fi


    if test "$tcl_ok" = "yes"; then
	TCL_THREADS=1

	$as_echo "#define TCL_THREADS 1" >>confdefs.h



	$as_echo "#define _REENTRANT 1" >>confdefs.h



	case "`uname -s`" in
	    *win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)
		    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
		;;
	    *)
		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5
$as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; }
if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then :

  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-lpthread  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char pthread_mutex_init ();
int
main ()
{

return pthread_mutex_init ();
  ;
  return 0;
}
_ACEOF


if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_pthread_pthread_mutex_init=yes
else



  ac_cv_lib_pthread_pthread_mutex_init=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi

{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5
$as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; }
if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes; then :
  tcl_ok=yes
else

  tcl_ok=no
fi

		if test "$tcl_ok" = "yes"; then
		    # The space is needed
		    THREADS_LIBS=" -lpthread"
		    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
		else
		    TCL_THREADS=0
		    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
		    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Don t know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...\"" >&5
$as_echo "$as_me: WARNING: \"Don t know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...\"" >&2;}
		fi
		;;
	esac
    else
	TCL_THREADS=0
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no (default)" >&5
$as_echo "no (default)" >&6; }
    fi



#--------------------------------------------------------------------
# The statement below defines a collection of symbols related to
# building as a shared library instead of a static library.
#--------------------------------------------------------------------


    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5
$as_echo_n "checking how to build libraries... " >&6; }
    # Check whether --enable-shared was given.
if test "${enable_shared+set}" = set; then :

  enableval=$enable_shared; tcl_ok=$enableval
else
  tcl_ok=yes
fi


    if test "${enable_shared+set}" = set; then
	enableval="$enable_shared"
	tcl_ok=$enableval
    else
	tcl_ok=yes
    fi

    if test "$tcl_ok" = "yes" ; then
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: shared" >&5
$as_echo "shared" >&6; }
	SHARED_BUILD=1
    else
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5
$as_echo "static" >&6; }
	SHARED_BUILD=0

	$as_echo "#define STATIC_BUILD 1" >>confdefs.h


    fi


#--------------------------------------------------------------------
# This macro figures out what flags to use with the compiler/linker
# when building shared/static debug/optimized objects.  This information
1548
1549
1550
1551
1552
1553
1554

1555
1556

1557



1558
1559
1560

1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623

1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635

1636

1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653





1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666








1667
1668















1669
1670



1671











































1672

1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683

1684
1685


1686




1687
1688

1689
1690



1691


1692

1693






1694





1695
1696




1697


















1698
1699


1700
1701
1702
1703
1704

1705
1706








1707
1708
1709

1710
1711





1712





1713













1714







1715
1716

1717








1718
1719
1720



1721








1722



1723

1724

1725



1726

1727
1728
1729


1730
1731


1732

1733
1734

1735









1736



1737





1738
1739


1740
1741



1742
1743

1744
1745
1746
1747
1748
1749

1750


1751

1752





1753

1754





1755
1756
1757


































1758


1759



1760



1761

























1762
1763
1764
1765
1766

1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807

1808
1809
1810
1811
1812
1813

1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875



#--------------------------------------------------------------------
# Find out where we should get the crypt() function
#--------------------------------------------------------------------


echo $ac_n "checking for crypt""... $ac_c" 1>&6
echo "configure:1557: checking for crypt" >&5

if eval "test \"`echo '$''{'ac_cv_func_crypt'+set}'`\" = set"; then



  echo $ac_n "(cached) $ac_c" 1>&6
else
  cat > conftest.$ac_ext <<EOF

#line 1562 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
    which can conflict with char crypt(); below.  */
#include <assert.h>
/* Override any gcc2 internal prototype to avoid an error.  */
/* We use char because int might match the return type of a gcc2
    builtin and then its argument prototype would still apply.  */
char crypt();

int main() {

/* The GNU C library defines this for functions which it implements
    to always fail with ENOSYS.  Some functions are actually named
    something starting with __ and the normal name is an alias.  */
#if defined (__stub_crypt) || defined (__stub___crypt)
choke me
#else
crypt();
#endif

; return 0; }
EOF
if { (eval echo configure:1585: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
  rm -rf conftest*
  eval "ac_cv_func_crypt=yes"
else
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5
  rm -rf conftest*
  eval "ac_cv_func_crypt=no"
fi
rm -f conftest*
fi

if eval "test \"`echo '$ac_cv_func_'crypt`\" = yes"; then
  echo "$ac_t""yes" 1>&6
  :
else
  echo "$ac_t""no" 1>&6

    echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
echo "configure:1604: checking for crypt in -lcrypt" >&5
ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  ac_save_LIBS="$LIBS"
LIBS="-lcrypt  $LIBS"
cat > conftest.$ac_ext <<EOF
#line 1612 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error.  */
/* We use char because int might match the return type of a gcc2
    builtin and then its argument prototype would still apply.  */
char crypt();

int main() {
crypt()
; return 0; }
EOF
if { (eval echo configure:1623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
  rm -rf conftest*

  eval "ac_cv_lib_$ac_lib_var=yes"
else
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5
  rm -rf conftest*
  eval "ac_cv_lib_$ac_lib_var=no"
fi
rm -f conftest*
LIBS="$ac_save_LIBS"

fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then

  echo "$ac_t""yes" 1>&6

  CRYPT_LIB=-lcrypt
else
  echo "$ac_t""no" 1>&6
CRYPT_OBJS=cryptLib.${OBJEXT}
fi


fi




#--------------------------------------------------------------------
# Find out if we have the sys/resource.h header file for building
# the limit extension
#--------------------------------------------------------------------






echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
echo "configure:1656: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
  CPP=
fi
if test -z "$CPP"; then
if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
    # This must be in double quotes, not single quotes, because CPP may get
  # substituted into the Makefile and "${CC-cc}" will confuse make.
  CPP="${CC-cc} -E"








  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp.















  cat > conftest.$ac_ext <<EOF
#line 1671 "configure"



#include "confdefs.h"











































#include <assert.h>

Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1677: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
  :
else
  echo "$ac_err" >&5
  echo "configure: failed program was:" >&5
  cat conftest.$ac_ext >&5

  rm -rf conftest*
  CPP="${CC-cc} -E -traditional-cpp"


  cat > conftest.$ac_ext <<EOF




#line 1688 "configure"
#include "confdefs.h"

#include <assert.h>
Syntax Error



EOF


ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"

{ (eval echo configure:1694: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }






ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`





if test -z "$ac_err"; then
  :




else


















  echo "$ac_err" >&5
  echo "configure: failed program was:" >&5


  cat conftest.$ac_ext >&5
  rm -rf conftest*
  CPP="${CC-cc} -nologo -E"
  cat > conftest.$ac_ext <<EOF
#line 1705 "configure"

#include "confdefs.h"
#include <assert.h>








Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"

{ (eval echo configure:1711: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`





if test -z "$ac_err"; then





  :













else







  echo "$ac_err" >&5
  echo "configure: failed program was:" >&5

  cat conftest.$ac_ext >&5








  rm -rf conftest*
  CPP=/lib/cpp
fi



rm -f conftest*








fi



rm -f conftest*

fi

rm -f conftest*



  ac_cv_prog_CPP="$CPP"

fi
  CPP="$ac_cv_prog_CPP"
else


  ac_cv_prog_CPP="$CPP"
fi


echo "$ac_t""$CPP" 1>&6


ac_safe=`echo "sys/resource.h" | sed 'y%./+-%__p_%'`

echo $ac_n "checking for sys/resource.h""... $ac_c" 1>&6









echo "configure:1737: checking for sys/resource.h" >&5



if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then





  echo $ac_n "(cached) $ac_c" 1>&6
else


  cat > conftest.$ac_ext <<EOF
#line 1742 "configure"



#include "confdefs.h"
#include <sys/resource.h>

EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1747: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
  rm -rf conftest*

  eval "ac_cv_header_$ac_safe=yes"


else

  echo "$ac_err" >&5





  echo "configure: failed program was:" >&5

  cat conftest.$ac_ext >&5





  rm -rf conftest*
  eval "ac_cv_header_$ac_safe=no"
fi


































rm -f conftest*


fi



if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then



  echo "$ac_t""yes" 1>&6

























  BUILD_LIMIT=1
else
  echo "$ac_t""no" 1>&6
BUILD_LIMIT=0
fi



if test "${BUILD_LIMIT}" = 1 ; then
    LIMIT_EXTENSION='$(limit_LIB_FILE)'
else
    LIMIT_EXTENSION=''
fi




#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols 
# option.
#--------------------------------------------------------------------


    case "`uname -s`" in
	*win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)
	    tcl_dbgx=d
	;;
	*)
	    tcl_dbgx=g
	;;
    esac

    echo $ac_n "checking for build with symbols""... $ac_c" 1>&6
echo "configure:1795: checking for build with symbols" >&5
    # Check whether --enable-symbols or --disable-symbols was given.
if test "${enable_symbols+set}" = set; then
  enableval="$enable_symbols"
  tcl_ok=$enableval
else
  tcl_ok=no
fi

    if test "$tcl_ok" = "yes"; then
	CFLAGS_DEFAULT="${CFLAGS_DEBUG}"
	LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}"
	DBGX=${tcl_dbgx}
	TCL_DBGX=${tcl_dbgx}

	echo "$ac_t""yes" 1>&6
    else
	CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}"
	LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
	DBGX=""
	TCL_DBGX=""

	echo "$ac_t""no" 1>&6
    fi

    
    
    


if test "${SHARED_BUILD}" = "1" ; then
    CFLAGS='${CFLAGS_DEFAULT} ${CFLAGS_WARNING} ${SHLIB_CFLAGS}'
else
    CFLAGS='${CFLAGS_DEFAULT} ${CFLAGS_WARNING}'
fi

#--------------------------------------------------------------------
# Everyone should be linking against the Tcl stub library.  If you
# can't for some reason, remove this definition.  If you aren't using
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.
#--------------------------------------------------------------------

cat >> confdefs.h <<\EOF
#define USE_TCL_STUBS 1
EOF


#--------------------------------------------------------------------
# This macro generates a line to use when building a library.  It
# depends on values set by the SC_ENABLE_SHARED, SC_ENABLE_SYMBOLS,
# and SC_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------


    case "`uname -s`" in
	*win32* | *WIN32* | *CYGWIN_NT* |*CYGWIN_98*|*CYGWIN_95*)
	    if test "${CC-cc}" = "cl"; then
		MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(${PACKAGE}_LIB_OBJECTS) "
		MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS} \$(LDFLAGS) -out:\$@ \$(${PACKAGE}_LIB_OBJECTS) "
	    fi
	    ;;
	*)
	    MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(${PACKAGE}_LIB_OBJECTS)"
	    MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(${PACKAGE}_LIB_OBJECTS) \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS}"
	    ;;
    esac

    if test "${SHARED_BUILD}" = "1" ; then
	MAKE_LIB=${MAKE_SHARED_LIB}
    else
	MAKE_LIB=${MAKE_STATIC_LIB}
    fi

    
    
    


#--------------------------------------------------------------------
# eval these two values to dereference the ${DBGX} variable.
#--------------------------------------------------------------------

eval "SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}"







>
|
|
>
|
>
>
>
|

|
>
|
|
|
<
<
|
|
|
<
|
<
|
<
<
<
<
<
<
<

|
<
<
<
<
<
<
<
<
<
<
|
<
|
|
|
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
|
<
<
>
|

<
<
<
|

|
|
|

<
>
|
>


<
|













>
>
>
>
>
|
|





|
|

|
|
<
>
>
>
>
>
>
>
>

|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
|
<
<
<
|
|

<
|
|
>
|
|
>
>
|
>
>
>
>
|
|
>
|
|
>
>
>
|
>
>
|
>
|
>
>
>
>
>
>
|
>
>
>
>
>
|
|
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
|
|
<
|
|
>
|
<
>
>
>
>
>
>
>
>
|
<
|
>
|
<
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|
|
>
|
>
>
>
>
>
>
>
>
|
<
|
>
>
>
|
>
>
>
>
>
>
>
>
|
>
>
>
|
>
|
>
|
>
>
>
|
>
|
<

>
>
|
|
>
>
|
>

|
>
|
>
>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
|

>
>
|
|
>
>
>
|
|
>
|
|
<
<
|
|
>
|
>
>
|
>
|
>
>
>
>
>
|
>
|
>
>
>
>
>
|
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>

>
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


<
|

>












|













|
|
|
|
<
|









>
|





>
|


|
|
|















<
|
<












|
|



|
|









|
|
|







3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838


3839
3840
3841

3842

3843







3844
3845










3846

3847
3848
3849




3850












3851


3852



3853


3854
3855
3856



3857
3858
3859
3860
3861
3862

3863
3864
3865
3866
3867

3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898

3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976



3977
3978
3979

3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048

4049
4050
4051
4052

4053
4054
4055
4056
4057
4058
4059
4060
4061

4062
4063
4064

4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110

4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138

4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184


4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282

4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315

4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354

4355

4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393



#--------------------------------------------------------------------
# Find out where we should get the crypt() function
#--------------------------------------------------------------------

ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
if test "x$ac_cv_func_crypt" = xyes; then :

else

    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
$as_echo_n "checking for crypt in -lcrypt... " >&6; }
if ${ac_cv_lib_crypt_crypt+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_check_lib_save_LIBS=$LIBS
LIBS="-lcrypt  $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */



/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */

#ifdef __cplusplus

extern "C"







#endif
char crypt ();










int

main ()
{
return crypt ();




  ;












  return 0;


}



_ACEOF


if ac_fn_c_try_link "$LINENO"; then :
  ac_cv_lib_crypt_crypt=yes
else



  ac_cv_lib_crypt_crypt=no
fi
rm -f core conftest.err conftest.$ac_objext \
    conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi

{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
  CRYPT_LIB=-lcrypt
else

  CRYPT_OBJS=cryptLib.${OBJEXT}
fi


fi




#--------------------------------------------------------------------
# Find out if we have the sys/resource.h header file for building
# the limit extension
#--------------------------------------------------------------------

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
$as_echo_n "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
  CPP=
fi
if test -z "$CPP"; then
  if ${ac_cv_prog_CPP+:} false; then :
  $as_echo_n "(cached) " >&6
else
      # Double quotes because CPP needs to be expanded
    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"

    do
      ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
  # <limits.h> exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
		     Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.i conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.i conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
  break
fi

    done
    ac_cv_prog_CPP=$CPP

fi
  CPP=$ac_cv_prog_CPP
else
  ac_cv_prog_CPP=$CPP
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
$as_echo "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
  # <limits.h> exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
		     Syntax error
_ACEOF



if ac_fn_c_try_cpp "$LINENO"; then :

else

  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.i conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.i conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :

else
  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details" "$LINENO" 5; }
fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
if ${ac_cv_path_GREP+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$GREP"; then
  ac_path_GREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in grep ggrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
      as_fn_executable_p "$ac_path_GREP" || continue
# Check for GNU ac_path_GREP and select it if it is found.
  # Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
*GNU*)
  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"

    cp "conftest.in" "conftest.nl"
    $as_echo 'GREP' >> "conftest.nl"
    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break

    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_GREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_GREP="$ac_path_GREP"
      ac_path_GREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done

  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac


      $ac_path_GREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_GREP"; then
    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi
else
  ac_cv_path_GREP=$GREP
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
$as_echo "$ac_cv_path_GREP" >&6; }
 GREP="$ac_cv_path_GREP"


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
if ${ac_cv_path_EGREP+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
   then ac_cv_path_EGREP="$GREP -E"
   else
     if test -z "$EGREP"; then
  ac_path_EGREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in egrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
      as_fn_executable_p "$ac_path_EGREP" || continue
# Check for GNU ac_path_EGREP and select it if it is found.
  # Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
*GNU*)
  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"

  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo 'EGREP' >> "conftest.nl"
    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_EGREP="$ac_path_EGREP"
      ac_path_EGREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_EGREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_EGREP"; then
    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi

else
  ac_cv_path_EGREP=$EGREP
fi

   fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
$as_echo "$ac_cv_path_EGREP" >&6; }
 EGREP="$ac_cv_path_EGREP"


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
if ${ac_cv_header_stdc+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_header_stdc=yes
else
  ac_cv_header_stdc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext

if test $ac_cv_header_stdc = yes; then
  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <string.h>

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |


  $EGREP "memchr" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdlib.h>

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "free" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
  if test "$cross_compiling" = yes; then :
  :
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <ctype.h>
#include <stdlib.h>
#if ((' ' & 0x0FF) == 0x020)
# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#else
# define ISLOWER(c) \
		   (('a' <= (c) && (c) <= 'i') \
		     || ('j' <= (c) && (c) <= 'r') \
		     || ('s' <= (c) && (c) <= 'z'))
# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
#endif

#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int
main ()
{
  int i;
  for (i = 0; i < 256; i++)
    if (XOR (islower (i), ISLOWER (i))
	|| toupper (i) != TOUPPER (i))
      return 2;
  return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :

else
  ac_cv_header_stdc=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
  conftest.$ac_objext conftest.beam conftest.$ac_ext
fi

fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
$as_echo "$ac_cv_header_stdc" >&6; }
if test $ac_cv_header_stdc = yes; then

$as_echo "#define STDC_HEADERS 1" >>confdefs.h

fi

# On IRIX 5.3, sys/types and inttypes.h are conflicting.
for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
		  inttypes.h stdint.h unistd.h
do :
  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
  cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF

fi

done


ac_fn_c_check_header_mongrel "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_resource_h" = xyes; then :
  BUILD_LIMIT=1
else

  BUILD_LIMIT=0
fi



if test "${BUILD_LIMIT}" = 1 ; then
    LIMIT_EXTENSION='$(limit_LIB_FILE)'
else
    LIMIT_EXTENSION=''
fi




#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols
# option.
#--------------------------------------------------------------------


    case "`uname -s`" in
	*win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*)
	    tcl_dbgx=d
	;;
	*)
	    tcl_dbgx=g
	;;
    esac

    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5
$as_echo_n "checking for build with symbols... " >&6; }
    # Check whether --enable-symbols was given.
if test "${enable_symbols+set}" = set; then :

  enableval=$enable_symbols; tcl_ok=$enableval
else
  tcl_ok=no
fi

    if test "$tcl_ok" = "yes"; then
	CFLAGS_DEFAULT="${CFLAGS_DEBUG}"
	LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}"
	DBGX=${tcl_dbgx}
	TCL_DBGX=${tcl_dbgx}
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
    else
	CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}"
	LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
	DBGX=""
	TCL_DBGX=""
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
    fi






if test "${SHARED_BUILD}" = "1" ; then
    CFLAGS='${CFLAGS_DEFAULT} ${CFLAGS_WARNING} ${SHLIB_CFLAGS}'
else
    CFLAGS='${CFLAGS_DEFAULT} ${CFLAGS_WARNING}'
fi

#--------------------------------------------------------------------
# Everyone should be linking against the Tcl stub library.  If you
# can't for some reason, remove this definition.  If you aren't using
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.
#--------------------------------------------------------------------


$as_echo "#define USE_TCL_STUBS 1" >>confdefs.h



#--------------------------------------------------------------------
# This macro generates a line to use when building a library.  It
# depends on values set by the SC_ENABLE_SHARED, SC_ENABLE_SYMBOLS,
# and SC_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------


    case "`uname -s`" in
	*win32* | *WIN32* | *CYGWIN_NT* |*CYGWIN_98*|*CYGWIN_95*)
	    if test "${CC-cc}" = "cl"; then
		MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(\$@_OBJECTS) "
		MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS} \$(LDFLAGS) -out:\$@ \$(\$@_OBJECTS) "
	    fi
	    ;;
	*)
	    MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(\$@_OBJECTS)"
	    MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(\$@_OBJECTS) \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS}"
	    ;;
    esac

    if test "${SHARED_BUILD}" = "1" ; then
	MAKE_LIB=${MAKE_SHARED_LIB}
    else
	MAKE_LIB=${MAKE_STATIC_LIB}
    fi






#--------------------------------------------------------------------
# eval these two values to dereference the ${DBGX} variable.
#--------------------------------------------------------------------

eval "SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}"
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959

1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970

1971
1972
1973
1974

1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986




1987

1988
1989
1990
1991
1992

















1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005










2006






2007
2008
2009
2010

2011


2012



2013

2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036











2037



2038



2039
2040
2041
2042










2043
2044













2045

2046
2047
2048
2049












2050



2051
2052


2053

2054

2055



2056


2057



2058






2059
2060
2061
2062
























2063












2064








2065
2066













2067



2068

2069
2070
2071
2072
2073
2074
2075
2076
2077
2078

















2079




















2080








2081
2082




2083


2084



2085



2086

2087

























2088







2089
2090
2091
2092

2093
2094
2095

2096


2097
2098






2099


2100


2101


2102

2103
2104


















2105






2106












2107
2108
2109
2110

2111
2112



















2113
2114
2115

2116


2117

2118
2119
2120
2121
2122
2123
2124
2125
























2126

2127







2128
2129







2130
2131









2132


2133
2134


2135
2136




2137

2138







2139





2140


2141

2142



2143
2144
2145
2146



2147

2148





2149

2150









2151


2152

2153


2154
2155
2156
2157
2158
2159



2160


2161


2162
2163


















2164
2165

2166
2167
2168
2169
2170
2171

2172
2173


















2174



2175


2176



2177

2178




2179
2180










2181









2182

2183

2184

2185







2186



2187
2188







2189





2190


2191

2192





2193


2194


2195



2196




2197
2198




2199
2200
2201
2202
2203
2204
2205
2206
2207
2208


2209
2210



















2211
2212

2213

2214
2215
2216





























2217












2218






2219

















2220


2221
2222

2223
2224
2225
2226


2227
2228
2229


2230







2231







2232






2233


2234
2235


















2236

2237



2238
2239

2240




2241
2242
2243







2244





2245












2246






2247
























2248
2249
2250
2251
2252

2253

2254



2255




2256
2257

2258



2259
2260







2261
2262
2263




2264
2265

2266


2267















2268












2269

2270
2271




2272





2273


2274

2275




2276


2277

2278
2279







2280







2281
2282
2283

2284

2285
2286
2287
2288

2289


2290
2291
























2292
# file during the install process.  Don't run the TCLSH_PROG through
# ${CYGPATH} because it's being used directly by make.
# Require that we use a tclsh shell version 8.2 or later since earlier
# versions have bugs in the pkg_mkIndex routine.
#--------------------------------------------------------------------


    echo $ac_n "checking for tclsh""... $ac_c" 1>&6
echo "configure:1937: checking for tclsh" >&5

    if eval "test \"`echo '$''{'ac_cv_path_tclsh'+set}'`\" = set"; then
  echo $ac_n "(cached) $ac_c" 1>&6
else
  
	search_path=`echo ${exec_prefix}/bin:${prefix}/bin:${TCL_BIN_DIR}:${TCL_BIN_DIR}/../bin:${PATH} | sed -e 's/:/ /g'`
	for dir in $search_path ; do
	    for j in `ls -r $dir/tclsh[8-9]*${EXEEXT} 2> /dev/null` \
		    `ls -r $dir/tclsh*${EXEEXT} 2> /dev/null` ; do
		if test x"$ac_cv_path_tclsh" = x ; then
		    if test -f "$j" ; then
			ac_cv_path_tclsh=$j
			break
		    fi
		fi
	    done
	done
    
fi


    if test -f "$ac_cv_path_tclsh" ; then
	TCLSH_PROG=$ac_cv_path_tclsh

	echo "$ac_t""$TCLSH_PROG" 1>&6
    else
	{ echo "configure: error: No tclsh found in PATH:  $search_path" 1>&2; exit 1; }
    fi
    


#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
#--------------------------------------------------------------------


trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure

# scripts and configure runs.  It is not useful on other systems.
# If it contains results you don't want to keep, you may remove or edit it.
#
# By default, configure uses ./config.cache as the cache file,
# creating it if it does not exist already.  You can give configure
# the --cache-file=FILE option to use a different cache file; that is
# what configure does when it calls configure scripts in
# subdirectories, so they share the cache.
# Giving --cache-file=/dev/null disables caching, for debugging configure.
# config.status only pays attention to the cache file if you give it the
# --recheck option to rerun configure.
#




EOF

# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, don't put newlines in cache variables' values.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.

















(set) 2>&1 |
  case `(ac_space=' '; set | grep ac_space) 2>&1` in
  *ac_space=\ *)
    # `set' does not quote correctly, so add quotes (double-quote substitution
    # turns \\\\ into \\, and sed turns \\ into \).
    sed -n \
      -e "s/'/'\\\\''/g" \
      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
    ;;
  *)
    # `set' quotes correctly as required by POSIX, so do not add quotes.
    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
    ;;










  esac >> confcache






if cmp -s $cache_file confcache; then
  :
else
  if test -w $cache_file; then

    echo "updating cache $cache_file"


    cat confcache > $cache_file



  else

    echo "not updating unwritable cache $cache_file"
  fi
fi
rm -f confcache

trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15

test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'

# Any assignment to VPATH causes Sun make to only execute
# the first set of double-colon rules, so remove it if not needed.
# If there is a colon in the path, we need to keep it.
if test "x$srcdir" = x.; then
  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
fi

trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15

# Transform confdefs.h into DEFS.
# Protect against shell expansion while executing Makefile rules.
# Protect against Makefile macro expansion.











cat > conftest.defs <<\EOF



s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g



s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
s%\[%\\&%g
s%\]%\\&%g
s%\$%$$%g










EOF
DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`













rm -f conftest.defs



# Without the "./", some shells look in PATH for config.status.
: ${CONFIG_STATUS=./config.status}
















echo creating $CONFIG_STATUS
rm -f $CONFIG_STATUS


cat > $CONFIG_STATUS <<EOF

#! /bin/sh

# Generated automatically by configure.



# Run this file to recreate the current configuration.


# This directory was configured as follows,



# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:






#
# $0 $ac_configure_args
#
# Compiler output produced by configure, useful for debugging
























# configure, is in ./config.log if it exists.





















ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
for ac_option













do



  case "\$ac_option" in

  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
    echo "$CONFIG_STATUS generated by autoconf version 2.13"
    exit 0 ;;
  -help | --help | --hel | --he | --h)
    echo "\$ac_cs_usage"; exit 0 ;;
  *) echo "\$ac_cs_usage"; exit 1 ;;
  esac

















done





























ac_given_srcdir=$srcdir
ac_given_INSTALL="$INSTALL"







trap 'rm -fr `echo "Makefile \



	crypt_pkgIndex.tcl \



	limit_pkgIndex.tcl" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15

EOF

























cat >> $CONFIG_STATUS <<EOF








# Protect against being on the right side of a sed subst in config.status.
sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
 s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF

$ac_vpsub
$extrasub
s%@SHELL@%$SHELL%g

s%@CFLAGS@%$CFLAGS%g


s%@CPPFLAGS@%$CPPFLAGS%g
s%@CXXFLAGS@%$CXXFLAGS%g






s%@FFLAGS@%$FFLAGS%g


s%@DEFS@%$DEFS%g


s%@LDFLAGS@%$LDFLAGS%g


s%@LIBS@%$LIBS%g

s%@exec_prefix@%$exec_prefix%g
s%@prefix@%$prefix%g


















s%@program_transform_name@%$program_transform_name%g






s%@bindir@%$bindir%g












s%@sbindir@%$sbindir%g
s%@libexecdir@%$libexecdir%g
s%@datadir@%$datadir%g
s%@sysconfdir@%$sysconfdir%g

s%@sharedstatedir@%$sharedstatedir%g
s%@localstatedir@%$localstatedir%g



















s%@libdir@%$libdir%g
s%@includedir@%$includedir%g
s%@oldincludedir@%$oldincludedir%g

s%@infodir@%$infodir%g


s%@mandir@%$mandir%g

s%@CONFIGDIR@%$CONFIGDIR%g
s%@PACKAGE@%$PACKAGE%g
s%@SERVER_ROOT@%$SERVER_ROOT%g
s%@VERSION@%$VERSION%g
s%@RELEASE@%$RELEASE%g
s%@WIN_VERSION@%$WIN_VERSION%g
s%@CRYPT_PACKAGE@%$CRYPT_PACKAGE%g
s%@CRYPT_VERSION@%$CRYPT_VERSION%g
























s%@WIN_CRYPT_VERSION@%$WIN_CRYPT_VERSION%g

s%@LIMIT_PACKAGE@%$LIMIT_PACKAGE%g







s%@LIMIT_VERSION@%$LIMIT_VERSION%g
s%@WIN_LIMIT_VERSION@%$WIN_LIMIT_VERSION%g







s%@TCL_VERSION@%$TCL_VERSION%g
s%@TCLLIB_VERSION@%$TCLLIB_VERSION%g









s%@THREAD_VERSION@%$THREAD_VERSION%g


s%@CC@%$CC%g
s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g


s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
s%@INSTALL_DATA@%$INSTALL_DATA%g




s%@SET_MAKE@%$SET_MAKE%g

s%@RANLIB@%$RANLIB%g







s%@OBJEXT@%$OBJEXT%g





s%@EXEEXT@%$EXEEXT%g


s%@CYGPATH@%$CYGPATH%g

s%@RELPATH@%$RELPATH%g



s%@TCL_DBGX@%$TCL_DBGX%g
s%@TCL_BIN_DIR@%$TCL_BIN_DIR%g
s%@TCL_SRC_DIR@%$TCL_SRC_DIR%g
s%@TCL_LIB_FILE@%$TCL_LIB_FILE%g



s%@TCL_LIBS@%$TCL_LIBS%g

s%@TCL_DEFS@%$TCL_DEFS%g





s%@TCL_SHLIB_LD_LIBS@%$TCL_SHLIB_LD_LIBS%g

s%@TCL_EXTRA_CFLAGS@%$TCL_EXTRA_CFLAGS%g









s%@TCL_LD_FLAGS@%$TCL_LD_FLAGS%g


s%@TCL_STUB_LIB_FILE@%$TCL_STUB_LIB_FILE%g

s%@TCL_LIB_SPEC@%$TCL_LIB_SPEC%g


s%@TCL_BUILD_LIB_SPEC@%$TCL_BUILD_LIB_SPEC%g
s%@TCL_STUB_LIB_SPEC@%$TCL_STUB_LIB_SPEC%g
s%@TCL_BUILD_STUB_LIB_SPEC@%$TCL_BUILD_STUB_LIB_SPEC%g
s%@TCL_INCLUDES@%$TCL_INCLUDES%g
s%@CLEANFILES@%$CLEANFILES%g
s%@CFLAGS_DEBUG@%$CFLAGS_DEBUG%g



s%@CFLAGS_OPTIMIZE@%$CFLAGS_OPTIMIZE%g


s%@STLIB_LD@%$STLIB_LD%g


s%@SHLIB_LD@%$SHLIB_LD%g
s%@SHLIB_CFLAGS@%$SHLIB_CFLAGS%g


















s%@SHLIB_LDFLAGS@%$SHLIB_LDFLAGS%g
s%@CRYPT_OBJS@%$CRYPT_OBJS%g

s%@CPP@%$CPP%g
s%@LIMIT_EXTENSION@%$LIMIT_EXTENSION%g
s%@BUILD_LIMIT@%$BUILD_LIMIT%g
s%@CFLAGS_DEFAULT@%$CFLAGS_DEFAULT%g
s%@LDFLAGS_DEFAULT@%$LDFLAGS_DEFAULT%g
s%@MAKE_LIB@%$MAKE_LIB%g

s%@MAKE_SHARED_LIB@%$MAKE_SHARED_LIB%g
s%@MAKE_STATIC_LIB@%$MAKE_STATIC_LIB%g


















s%@SHARED_BUILD@%$SHARED_BUILD%g



s%@limit_LIB_FILE@%$limit_LIB_FILE%g


s%@crypt_LIB_FILE@%$crypt_LIB_FILE%g



s%@SHLIB_LD_LIBS@%$SHLIB_LD_LIBS%g

s%@TCLSH_PROG@%$TCLSH_PROG%g





CEOF










EOF











cat >> $CONFIG_STATUS <<\EOF



# Split the substitutions into bite-sized pieces for seds with







# small command number limits, like on Digital OSF/1 and HP-UX.



ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
ac_file=1 # Number of current file.







ac_beg=1 # First line for current file.





ac_end=$ac_max_sed_cmds # Line after last line for current file.


ac_more_lines=:

ac_sed_cmds=""





while $ac_more_lines; do


  if test $ac_beg -gt 1; then


    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file



  else




    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
  fi




  if test ! -s conftest.s$ac_file; then
    ac_more_lines=false
    rm -f conftest.s$ac_file
  else
    if test -z "$ac_sed_cmds"; then
      ac_sed_cmds="sed -f conftest.s$ac_file"
    else
      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
    fi
    ac_file=`expr $ac_file + 1`


    ac_beg=$ac_end
    ac_end=`expr $ac_end + $ac_max_sed_cmds`



















  fi
done

if test -z "$ac_sed_cmds"; then

  ac_sed_cmds=cat
fi
EOF










































cat >> $CONFIG_STATUS <<EOF
























CONFIG_FILES=\${CONFIG_FILES-"Makefile \


	crypt_pkgIndex.tcl \
	limit_pkgIndex.tcl"}

EOF
cat >> $CONFIG_STATUS <<\EOF
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".


  case "$ac_file" in
  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;


  *) ac_file_in="${ac_file}.in" ;;







  esac














  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.



  # Remove last slash and all that follows it.  Not all systems have dirname.


















  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`

  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then



    # The file is in a subdirectory.
    test ! -d "$ac_dir" && mkdir "$ac_dir"

    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"




    # A "../" for each directory in $ac_dir_suffix.
    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
  else







    ac_dir_suffix= ac_dots=





  fi



















  case "$ac_given_srcdir" in
























  .)  srcdir=.
      if test -z "$ac_dots"; then top_srcdir=.
      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
  *) # Relative path.

    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"

    top_srcdir="$ac_dots$ac_given_srcdir" ;;



  esac





  case "$ac_given_INSTALL" in

  [/$]*) INSTALL="$ac_given_INSTALL" ;;



  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
  esac








  echo creating "$ac_file"
  rm -f "$ac_file"




  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
  case "$ac_file" in

  *Makefile*) ac_comsub="1i\\


# $configure_input" ;;















  *) ac_comsub= ;;












  esac


  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`




  sed -e "$ac_comsub





s%@configure_input@%$configure_input%g


s%@srcdir@%$srcdir%g

s%@top_srcdir@%$top_srcdir%g




s%@INSTALL@%$INSTALL%g


" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file

fi; done
rm -f conftest.s*















EOF
cat >> $CONFIG_STATUS <<EOF


EOF

cat >> $CONFIG_STATUS <<\EOF

exit 0
EOF

chmod +x $CONFIG_STATUS


rm -fr confdefs* $ac_clean_files
test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
































|
|

|
|

|












|





>
|

|

|






>
|
|


>
|
|

<
<
<
<
<
<
|
|

>
>
>
>
|
>


|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|
<
|
|
>
|
>
>
|
>
>
>

>
|




<
<




<
<
<
<
<
<
<
<
<



>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
>
|
|
|
|
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>


|
|
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
|
|
>
>
|
>
|
>
|
>
>
>
|
>
>
|
>
>
>
|
>
>
>
>
>
>
|
<
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
|
>
|
<
<
<
<
|
<
<
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
>
>
|
>
>
>
|
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|
<
|
<
>
|
|
<
>
|
>
>
|
|
>
>
>
>
>
>
|
>
>
|
>
>
|
>
>
|
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>
<
>
>
|
>
|
<
<
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
<
>
|
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
|
>
>
|
<
>
>
|
|
>
>
>
>
|
>
|
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
|
>
|
>
>
>
|
<
|
|
>
>
>
|
>
|
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
|
>
>
|
>
|
>
>
|
|
|
|
|
|
>
>
>
|
>
>
|
>
>
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
|
|
<
|
|
<
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
|
>
>
>
|
>
|
>
>
>
>

|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>

>
|
>

>
|
>
>
>
>
>
>
>
|
>
>
>
|
|
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
|
>
|
>
>
>
>
>
|
>
>
|
>
>
|
>
>
>
|
>
>
>
>
|
|
>
>
>
>
|
|
|
|
|
|
|
|
|
|
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
|
>
|
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
<
>
|
|
|
<
>
>
|
<
|
>
>
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|
>
>

|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
|
|
>
|
>
>
>
>
|
|
|
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
>
|
>
|
>
>
>
|
>
>
>
>

|
>
|
>
>
>
|
|
>
>
>
>
>
>
>

|
|
>
>
>
>
|
|
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>

<
>
>
>
>
|
>
>
>
>
>
|
>
>
|
>
|
>
>
>
>
|
>
>
|
>
|
|
>
>
>
>
>
>
>

>
>
>
>
>
>
>
|
|

>
|
>
|

|
|
>
|
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498






4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560

4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577


4578
4579
4580
4581









4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681

4682

4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750




4751



4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853

4854

4855
4856
4857

4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950

4951
4952
4953
4954
4955


4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984

4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017

5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051

5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100

5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123

5124
5125

5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290

5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362

5363
5364
5365
5366

5367
5368
5369

5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571

5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
# file during the install process.  Don't run the TCLSH_PROG through
# ${CYGPATH} because it's being used directly by make.
# Require that we use a tclsh shell version 8.2 or later since earlier
# versions have bugs in the pkg_mkIndex routine.
#--------------------------------------------------------------------


    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5
$as_echo_n "checking for tclsh... " >&6; }

    if ${ac_cv_path_tclsh+:} false; then :
  $as_echo_n "(cached) " >&6
else

	search_path=`echo ${exec_prefix}/bin:${prefix}/bin:${TCL_BIN_DIR}:${TCL_BIN_DIR}/../bin:${PATH} | sed -e 's/:/ /g'`
	for dir in $search_path ; do
	    for j in `ls -r $dir/tclsh[8-9]*${EXEEXT} 2> /dev/null` \
		    `ls -r $dir/tclsh*${EXEEXT} 2> /dev/null` ; do
		if test x"$ac_cv_path_tclsh" = x ; then
		    if test -f "$j" ; then
			ac_cv_path_tclsh=$j
			break
		    fi
		fi
	    done
	done

fi


    if test -f "$ac_cv_path_tclsh" ; then
	TCLSH_PROG=$ac_cv_path_tclsh
	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TCLSH_PROG" >&5
$as_echo "$TCLSH_PROG" >&6; }
    else
	as_fn_error $? "No tclsh found in PATH:  $search_path" "$LINENO" 5
    fi



#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
#--------------------------------------------------------------------

ac_config_files="$ac_config_files Makefile crypt_pkgIndex.tcl limit_pkgIndex.tcl"

cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# scripts and configure runs, see configure's option --config-cache.
# It is not useful on other systems.  If it contains results you don't
# want to keep, you may remove or edit it.
#






# config.status only pays attention to the cache file if you give it
# the --recheck option to rerun configure.
#
# `ac_cv_env_foo' variables (set or unset) will be overridden when
# loading this file, other *unset* `ac_cv_foo' will be assigned the
# following values.

_ACEOF

# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, we kill variables containing newlines.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
(
  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
    eval ac_val=\$$ac_var
    case $ac_val in #(
    *${as_nl}*)
      case $ac_var in #(
      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      esac
      case $ac_var in #(
      _ | IFS | as_nl) ;; #(
      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
      *) { eval $ac_var=; unset $ac_var;} ;;
      esac ;;
    esac
  done

  (set) 2>&1 |
    case $as_nl`(ac_space=' '; set) 2>&1` in #(
    *${as_nl}ac_space=\ *)
      # `set' does not quote correctly, so add quotes: double-quote
      # substitution turns \\\\ into \\, and sed turns \\ into \.
      sed -n \
	"s/'/'\\\\''/g;
	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
      ;; #(
    *)
      # `set' quotes correctly as required by POSIX, so do not add quotes.
      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
      ;;
    esac |
    sort
) |
  sed '
     /^ac_cv_env_/b end
     t clear
     :clear
     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
     t end
     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
     :end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
  if test -w "$cache_file"; then
    if test "x$cache_file" != "x/dev/null"; then
      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
$as_echo "$as_me: updating cache $cache_file" >&6;}
      if test ! -f "$cache_file" || test -h "$cache_file"; then
	cat confcache >"$cache_file"

      else
        case $cache_file in #(
        */* | ?:*)
	  mv -f confcache "$cache_file"$$ &&
	  mv -f "$cache_file"$$ "$cache_file" ;; #(
        *)
	  mv -f confcache "$cache_file" ;;
	esac
      fi
    fi
  else
    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
  fi
fi
rm -f confcache



test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'










# Transform confdefs.h into DEFS.
# Protect against shell expansion while executing Makefile rules.
# Protect against Makefile macro expansion.
#
# If the first sed substitution is executed (which looks for macros that
# take arguments), then branch to the quote section.  Otherwise,
# look for a macro that doesn't take arguments.
ac_script='
:mline
/\\$/{
 N
 s,\\\n,,
 b mline
}
t clear
:clear
s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
t quote
s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
t quote
b any
:quote
s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
s/\[/\\&/g
s/\]/\\&/g
s/\$/$$/g
H
:any
${
	g
	s/^\n//
	s/\n/ /g
	p
}
'
DEFS=`sed -n "$ac_script" confdefs.h`


ac_libobjs=
ac_ltlibobjs=
U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
  # 1. Remove the extension, and $U if already installed.
  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
  #    will be set to the directory where LIBOBJS objects are built.
  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
done
LIBOBJS=$ac_libobjs

LTLIBOBJS=$ac_ltlibobjs



: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
as_write_fail=0
cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
#! $SHELL
# Generated by $as_me.
# Run this file to recreate the current configuration.
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.

debug=false
ac_cs_recheck=false
ac_cs_silent=false

SHELL=\${CONFIG_SHELL-$SHELL}
export SHELL
_ASEOF
cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##

# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi




as_nl='
'
export as_nl
# Printing a long string crashes Solaris 7 /usr/bin/printf.
as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='print -r --'
  as_echo_n='print -rn --'
elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='printf %s\n'
  as_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
    as_echo_n='/usr/ucb/echo -n'
  else
    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    as_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$as_nl"*)
	expr "X$arg" : "X\\(.*\\)$as_nl";
	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
    '
    export as_echo_n_body
    as_echo_n='sh -c $as_echo_n_body as_echo'
  fi
  export as_echo_body
  as_echo='sh -c $as_echo_body as_echo'
fi

# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
  PATH_SEPARATOR=:
  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
      PATH_SEPARATOR=';'
  }
fi


# IFS
# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent editors from complaining about space-tab.
# (If _AS_PATH_WALK were called with IFS unset, it would disable word
# splitting by setting IFS to empty value.)
IFS=" ""	$as_nl"

# Find who we are.  Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
  *[\\/]* ) as_myself=$0 ;;
  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
  done
IFS=$as_save_IFS





     ;;



esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
  as_myself=$0
fi
if test ! -f "$as_myself"; then
  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
  exit 1
fi

# Unset variables that we do not need and which cause bugs (e.g. in
# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
# suppresses any "Segmentation fault" message there.  '((' could
# trigger a bug in pdksh 5.2.14.
for as_var in BASH_ENV ENV MAIL MAILPATH
do eval test x\${$as_var+set} = xset \
  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
done
PS1='$ '
PS2='> '
PS4='+ '

# NLS nuisances.
LC_ALL=C
export LC_ALL
LANGUAGE=C
export LANGUAGE

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH


# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
  as_status=$1; test $as_status -eq 0 && as_status=1
  if test "$4"; then
    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
  fi
  $as_echo "$as_me: error: $2" >&2
  as_fn_exit $as_status
} # as_fn_error


# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
  return $1
} # as_fn_set_status

# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
  set +e
  as_fn_set_status $1
  exit $1
} # as_fn_exit

# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
  { eval $1=; unset $1;}
}
as_unset=as_fn_unset
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
  eval 'as_fn_append ()
  {
    eval $1+=\$2
  }'
else
  as_fn_append ()
  {
    eval $1=\$$1\$2
  }
fi # as_fn_append

# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
  eval 'as_fn_arith ()
  {

    as_val=$(( $* ))

  }'
else
  as_fn_arith ()

  {
    as_val=`expr "$@" || test $? -eq 1`
  }
fi # as_fn_arith


if expr a : '\(a\)' >/dev/null 2>&1 &&
   test "X`expr 00001 : '.*\(...\)'`" = X001; then
  as_expr=expr
else
  as_expr=false
fi

if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
  as_basename=basename
else
  as_basename=false
fi

if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
  as_dirname=dirname
else
  as_dirname=false
fi

as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
	 X"$0" : 'X\(//\)$' \| \
	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$0" |
    sed '/^.*\/\([^/][^/]*\)\/*$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`

# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits

ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
  case `echo 'xy\c'` in
  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
  xy)  ECHO_C='\c';;
  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
       ECHO_T='	';;
  esac;;
*)
  ECHO_N='-n';;
esac

rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
  rm -f conf$$.dir/conf$$.file
else
  rm -f conf$$.dir
  mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
  if ln -s conf$$.file conf$$ 2>/dev/null; then
    as_ln_s='ln -s'
    # ... but there are two gotchas:
    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
    # In both cases, we have to default to `cp -pR'.
    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
      as_ln_s='cp -pR'
  elif ln conf$$.file conf$$ 2>/dev/null; then
    as_ln_s=ln
  else
    as_ln_s='cp -pR'
  fi
else
  as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null


# as_fn_mkdir_p

# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{



  case $as_dir in #(
  -*) as_dir=./$as_dir;;
  esac
  test -d "$as_dir" || eval $as_mkdir_p || {
    as_dirs=
    while :; do
      case $as_dir in #(
      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
      *) as_qdir=$as_dir;;
      esac
      as_dirs="'$as_qdir' $as_dirs"
      as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_dir" : 'X\(//\)[^/]' \| \
	 X"$as_dir" : 'X\(//\)$' \| \
	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_dir" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }

	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
      test -d "$as_dir" && break
    done
    test -z "$as_dirs" || eval "mkdir $as_dirs"
  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"


} # as_fn_mkdir_p
if mkdir -p . 2>/dev/null; then
  as_mkdir_p='mkdir -p "$as_dir"'
else
  test -d ./-p && rmdir ./-p
  as_mkdir_p=false
fi


# as_fn_executable_p FILE
# -----------------------
# Test if FILE is an executable regular file.
as_fn_executable_p ()
{
  test -f "$1" && test -x "$1"
} # as_fn_executable_p
as_test_x='test -x'
as_executable_p=as_fn_executable_p

# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"


# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"


exec 6>&1
## ----------------------------------- ##
## Main body of $CONFIG_STATUS script. ##
## ----------------------------------- ##
_ASEOF
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by $as_me, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@

on `(hostname || uname -n) 2>/dev/null | sed 1q`
"

_ACEOF

case $ac_config_files in *"
"*) set x $ac_config_files; shift; ac_config_files=$*;;
esac




cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# Files that config.status was made for.
config_files="$ac_config_files"

_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
ac_cs_usage="\
\`$as_me' instantiates files and other configuration actions
from templates according to the current configuration.  Unless the files
and actions are specified as TAGs, all are instantiated by default.

Usage: $0 [OPTION]... [TAG]...

  -h, --help       print this help, then exit
  -V, --version    print version number and configuration settings, then exit
      --config     print configuration, then exit
  -q, --quiet, --silent
                   do not print progress messages
  -d, --debug      don't remove temporary files
      --recheck    update $as_me by reconfiguring in the same conditions
      --file=FILE[:TEMPLATE]
                   instantiate the configuration file FILE

Configuration files:
$config_files

Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
config.status
configured by $0, generated by GNU Autoconf 2.69,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

ac_pwd='$ac_pwd'
srcdir='$srcdir'
INSTALL='$INSTALL'
test -n "\$AWK" || AWK=awk
_ACEOF


cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# The default lists apply if the user does not specify any file.
ac_need_defaults=:
while test $# != 0
do
  case $1 in
  --*=?*)
    ac_option=`expr "X$1" : 'X\([^=]*\)='`
    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
    ac_shift=:
    ;;
  --*=)
    ac_option=`expr "X$1" : 'X\([^=]*\)='`
    ac_optarg=
    ac_shift=:
    ;;
  *)
    ac_option=$1
    ac_optarg=$2
    ac_shift=shift
    ;;
  esac


  case $ac_option in
  # Handling of the options.

  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
    ac_cs_recheck=: ;;
  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
    $as_echo "$ac_cs_version"; exit ;;
  --config | --confi | --conf | --con | --co | --c )
    $as_echo "$ac_cs_config"; exit ;;
  --debug | --debu | --deb | --de | --d | -d )
    debug=: ;;
  --file | --fil | --fi | --f )
    $ac_shift
    case $ac_optarg in
    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
    '') as_fn_error $? "missing file argument" ;;
    esac
    as_fn_append CONFIG_FILES " '$ac_optarg'"
    ac_need_defaults=false;;
  --he | --h |  --help | --hel | -h )
    $as_echo "$ac_cs_usage"; exit ;;
  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil | --si | --s)
    ac_cs_silent=: ;;

  # This is an error.
  -*) as_fn_error $? "unrecognized option: \`$1'
Try \`$0 --help' for more information." ;;

  *) as_fn_append ac_config_targets " $1"
     ac_need_defaults=false ;;

  esac
  shift
done

ac_configure_extra_args=

if $ac_cs_silent; then
  exec 6>/dev/null
  ac_configure_extra_args="$ac_configure_extra_args --silent"
fi

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
  shift
  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
  CONFIG_SHELL='$SHELL'
  export CONFIG_SHELL
  exec "\$@"
fi

_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
exec 5>>config.log
{
  echo
  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
  $as_echo "$ac_log"
} >&5

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1

# Handling of arguments.
for ac_config_target in $ac_config_targets
do
  case $ac_config_target in
    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
    "crypt_pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES crypt_pkgIndex.tcl" ;;
    "limit_pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES limit_pkgIndex.tcl" ;;

  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
  esac
done


# If the user did not use the arguments to specify the items to instantiate,
# then the envvar interface is used.  Set only those that are not.
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
fi

# Have a temporary directory for convenience.  Make it in the build tree
# simply because there is no reason against having it here, and in addition,
# creating and moving files from /tmp can sometimes cause problems.
# Hook for its removal unless debugging.
# Note that there is a small window in which the directory will not be cleaned:
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
  tmp= ac_tmp=
  trap 'exit_status=$?
  : "${ac_tmp:=$tmp}"
  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
' 0
  trap 'as_fn_exit 1' 1 2 13 15
}
# Create a (secure) tmp directory for tmp files.

{
  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
  test -d "$tmp"
}  ||
{
  tmp=./conf$$-$RANDOM
  (umask 077 && mkdir "$tmp")
} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
ac_tmp=$tmp

# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
# This happens for instance with `./config.status config.h'.
if test -n "$CONFIG_FILES"; then


ac_cr=`echo X | tr X '\015'`
# On cygwin, bash can eat \r inside `` if the user requested igncr.
# But we know of no other shell where ac_cr would be empty at this
# point, so we can use a bashism as a fallback.
if test "x$ac_cr" = x; then
  eval ac_cr=\$\'\\r\'
fi
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
  ac_cs_awk_cr='\\r'
else
  ac_cs_awk_cr=$ac_cr
fi

echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
_ACEOF


{
  echo "cat >conf$$subs.awk <<_ACEOF" &&
  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
  echo "_ACEOF"
} >conf$$subs.sh ||
  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
  . ./conf$$subs.sh ||
    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5

  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
  if test $ac_delim_n = $ac_delim_num; then
    break
  elif $ac_last_try; then
    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
  else
    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
  fi
done
rm -f conf$$subs.sh

cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&

_ACEOF
sed -n '
h
s/^/S["/; s/!.*/"]=/
p
g
s/^[^!]*!//
:repl
t repl
s/'"$ac_delim"'$//
t delim
:nl
h
s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
n
b repl
:more1
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t nl
:delim
h
s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p
b
:more2
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t delim
' <conf$$subs.awk | sed '
/^[^""]/{
  N
  s/\n//
}
' >>$CONFIG_STATUS || ac_write_fail=1
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
  for (key in S) S_is_set[key] = 1
  FS = ""

}
{
  line = $ 0
  nfields = split(line, field, "@")
  substed = 0
  len = length(field[1])
  for (i = 2; i < nfields; i++) {
    key = field[i]
    keylen = length(key)
    if (S_is_set[key]) {
      value = S[key]
      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
      len += length(value) + length(field[++i])
      substed = 1
    } else
      len += 1 + keylen
  }

  print line
}


_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then

  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
  cat

fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
_ACEOF

# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
# trailing colons and then remove the whole line if VPATH becomes empty
# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
h
s///
s/^/:/
s/[	 ]*$/:/
s/:\$(srcdir):/:/g
s/:\${srcdir}:/:/g
s/:@srcdir@:/:/g
s/^:*//
s/:*$//
x
s/\(=[	 ]*\).*/\1/
G
s/\n//
s/^[^=]*=[	 ]*$//
}'
fi

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
fi # test -n "$CONFIG_FILES"


eval set X "  :F $CONFIG_FILES      "
shift
for ac_tag
do
  case $ac_tag in
  :[FHLC]) ac_mode=$ac_tag; continue;;
  esac
  case $ac_mode$ac_tag in
  :[FHL]*:*);;
  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
  :[FH]-) ac_tag=-:-;;
  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
  esac
  ac_save_IFS=$IFS
  IFS=:
  set x $ac_tag
  IFS=$ac_save_IFS
  shift
  ac_file=$1
  shift

  case $ac_mode in
  :L) ac_source=$1;;
  :[FH])
    ac_file_inputs=
    for ac_f
    do
      case $ac_f in
      -) ac_f="$ac_tmp/stdin";;
      *) # Look for the file first in the build tree, then in the source tree
	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
	 # because $ac_f cannot contain `:'.
	 test -f "$ac_f" ||
	   case $ac_f in
	   [\\/$]*) false;;
	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
	   esac ||
	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
      esac
      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
      as_fn_append ac_file_inputs " '$ac_f'"
    done

    # Let's still pretend it is `configure' which instantiates (i.e., don't
    # use $as_me), people would be surprised to read:
    #    /* config.h.  Generated by config.status.  */
    configure_input='Generated from '`
	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
	`' by configure.'
    if test x"$ac_file" != x-; then
      configure_input="$ac_file.  $configure_input"
      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
$as_echo "$as_me: creating $ac_file" >&6;}
    fi
    # Neutralize special characters interpreted by sed in replacement strings.
    case $configure_input in #(
    *\&* | *\|* | *\\* )
       ac_sed_conf_input=`$as_echo "$configure_input" |
       sed 's/[\\\\&|]/\\\\&/g'`;; #(
    *) ac_sed_conf_input=$configure_input;;
    esac

    case $ac_tag in
    *:-:* | *:-) cat >"$ac_tmp/stdin" \
      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
    esac
    ;;
  esac

  ac_dir=`$as_dirname -- "$ac_file" ||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$ac_file" : 'X\(//\)[^/]' \| \
	 X"$ac_file" : 'X\(//\)$' \| \
	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$ac_file" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  as_dir="$ac_dir"; as_fn_mkdir_p
  ac_builddir=.

case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
  # A ".." for each directory in $ac_dir_suffix.
  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
  case $ac_top_builddir_sub in
  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
  esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix

case $srcdir in
  .)  # We are building in place.
    ac_srcdir=.
    ac_top_srcdir=$ac_top_builddir_sub
    ac_abs_top_srcdir=$ac_pwd ;;
  [\\/]* | ?:[\\/]* )  # Absolute name.
    ac_srcdir=$srcdir$ac_dir_suffix;
    ac_top_srcdir=$srcdir
    ac_abs_top_srcdir=$srcdir ;;
  *) # Relative name.
    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
    ac_top_srcdir=$ac_top_build_prefix$srcdir
    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix


  case $ac_mode in
  :F)
  #
  # CONFIG_FILE
  #

  case $INSTALL in
  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
  esac
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# If the template does not know about datarootdir, expand it.
# FIXME: This hack should be removed a few years after 2.60.
ac_datarootdir_hack=; ac_datarootdir_seen=
ac_sed_dataroot='
/datarootdir/ {
  p
  q
}
/@datadir@/p
/@docdir@/p
/@infodir@/p
/@localedir@/p
/@mandir@/p'
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
  ac_datarootdir_hack='
  s&@datadir@&$datadir&g
  s&@docdir@&$docdir&g
  s&@infodir@&$infodir&g
  s&@localedir@&$localedir&g
  s&@mandir@&$mandir&g
  s&\\\${datarootdir}&$datarootdir&g' ;;
esac
_ACEOF


# Neutralize VPATH when `$srcdir' = `.'.
# Shell code in configure.ac might set extrasub.
# FIXME: do we really want to maintain this feature?
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_sed_extra="$ac_vpsub
$extrasub
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
:t
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
s|@configure_input@|$ac_sed_conf_input|;t t
s&@top_builddir@&$ac_top_builddir_sub&;t t
s&@top_build_prefix@&$ac_top_build_prefix&;t t
s&@srcdir@&$ac_srcdir&;t t
s&@abs_srcdir@&$ac_abs_srcdir&;t t
s&@top_srcdir@&$ac_top_srcdir&;t t
s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
s&@builddir@&$ac_builddir&;t t
s&@abs_builddir@&$ac_abs_builddir&;t t
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
"
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5

test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
      "$ac_tmp/out"`; test -z "$ac_out"; } &&
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined.  Please make sure it is defined" >&5
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined.  Please make sure it is defined" >&2;}

  rm -f "$ac_tmp/stdin"
  case $ac_file in
  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
  esac \
  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
 ;;



  esac

done # for ac_tag


as_fn_exit 0
_ACEOF
ac_clean_files=$ac_clean_files_save

test $ac_write_fail = 0 ||
  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5


# configure is writing to config.log, and then calls config.status.
# config.status does its own redirection, appending to config.log.
# Unfortunately, on DOS this fails, as config.log is still kept open
# by configure, so config.status won't be able to write to it; its
# output is simply discarded.  So we exec the FD to /dev/null,
# effectively closing config.log, so it can be properly (re)opened and
# appended to by config.status.  When coming back to configure, we
# need to make the FD available again.
if test "$no_create" != yes; then
  ac_cs_success=:
  ac_config_status_args=
  test "$silent" = yes &&
    ac_config_status_args="$ac_config_status_args --quiet"
  exec 5>/dev/null
  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
  exec 5>>config.log
  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
  # would make configure fail if this is the last instruction.
  $ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi

Changes to configure.in.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# required for constructing the library name on systems that don't like
# dots in library names (Windows).  The VERSION variable is used on the
# other systems.
#--------------------------------------------------------------------

PACKAGE=tclhttpd

MAJOR_VERSION=3
MINOR_VERSION=5
PATCHLEVEL=".1"
RELEASE=`grep Release: ${srcdir}/${PACKAGE}.spec | sed -e 's/Release: *//'`

VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
WIN_VERSION=`echo ${VERSION} | sed -e 's/\.//g'`

TCL_VERSION=8.4.5
TCLLIB_VERSION=1.4
THREAD_VERSION=2.6

# We build two minor packages for the crypt and limit C extensions

CRYPT_PACKAGE=crypt
CRYPT_VERSION="1.0"
WIN_CRYPT_VERSION=`echo ${CRYPT_VERSION} | sed -e 's/\.//g'`







|
|
|






|
|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# required for constructing the library name on systems that don't like
# dots in library names (Windows).  The VERSION variable is used on the
# other systems.
#--------------------------------------------------------------------

PACKAGE=tclhttpd

MAJOR_VERSION=4
MINOR_VERSION=0
PATCHLEVEL=".0"
RELEASE=`grep Release: ${srcdir}/${PACKAGE}.spec | sed -e 's/Release: *//'`

VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
WIN_VERSION=`echo ${VERSION} | sed -e 's/\.//g'`

TCL_VERSION=8.6.4
TCLLIB_VERSION=1.6
THREAD_VERSION=2.6

# We build two minor packages for the crypt and limit C extensions

CRYPT_PACKAGE=crypt
CRYPT_VERSION="1.0"
WIN_CRYPT_VERSION=`echo ${CRYPT_VERSION} | sed -e 's/\.//g'`

Changes to debian/changelog.







1
2
3
4
5
6
7






tclhttpd (3.5.1-1) unstable; urgency=low
  * change version for release

 -- Colin McCormack <[email protected]>  Thu, 27 May 2004 10:06:02 +1000

tclhttpd (3.5.0-2) unstable; urgency=low

>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
tclhttpd (4.0.0) unstable; urgency=low

  * Change version for release

  -- Sean Woods <[email protected]> Sat, Mar 28 2015 04:44:11 EDT 

tclhttpd (3.5.1-1) unstable; urgency=low
  * change version for release

 -- Colin McCormack <[email protected]>  Thu, 27 May 2004 10:06:02 +1000

tclhttpd (3.5.0-2) unstable; urgency=low

Changes to debian/rules.

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/make -f
# -*- makefile -*-
# debian/rules with debhelper for tclhttpd

export VERSION=3.5.1
export BUILD=$(CURDIR)/debian/tclhttpd/

# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1

# This has to be exported to make some magic below work.
export DH_OPTIONS




|







1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/make -f
# -*- makefile -*-
# debian/rules with debhelper for tclhttpd

export VERSION=4.0.0
export BUILD=$(CURDIR)/debian/tclhttpd/

# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1

# This has to be exported to make some magic below work.
export DH_OPTIONS

Added htdocs/bootdemo/index.html.





























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Meta, title, CSS, favicons, etc. -->
    <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Bootstrap, a sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.">
<meta name="keywords" content="HTML, CSS, JS, JavaScript, framework, bootstrap, front-end, frontend, web development">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">

<title>
  
    Components &middot; Bootstrap
  
</title>

<!-- Bootstrap core CSS -->

<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">


  <!-- Optional Bootstrap Theme -->

  <link href="data:text/css;charset=utf-8," data-href="/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet" id="bs-theme-stylesheet">



<!-- Documentation extras -->

<link href="../assets/css/docs.min.css" rel="stylesheet">

<!--[if lt IE 9]><script src="../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="../assets/js/ie-emulation-modes-warning.js"></script>

<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->

<!-- Favicons -->
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="icon" href="/favicon.ico">

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
  ga('create', 'UA-146052-10', 'getbootstrap.com');
  ga('send', 'pageview');
</script>

  </head>
  <body>
    <a id="skippy" class="sr-only sr-only-focusable" href="#content"><div class="container"><span class="skiplink-text">Skip to main content</span></div></a>

    <!-- Docs master nav -->
    <header class="navbar navbar-static-top bs-docs-nav" id="top" role="banner">
  <div class="container">
    <div class="navbar-header">
      <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a href="../" class="navbar-brand">Bootstrap</a>
    </div>
    <nav class="collapse navbar-collapse bs-navbar-collapse">
      <ul class="nav navbar-nav">
        <li>
          <a href="../getting-started/">Getting started</a>
        </li>
        <li>
          <a href="../css/">CSS</a>
        </li>
        <li class="active">
          <a href="../components/">Components</a>
        </li>
        <li>
          <a href="../javascript/">JavaScript</a>
        </li>
        <li>
          <a href="../customize/">Customize</a>
        </li>
      </ul>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="http://expo.getbootstrap.com" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Expo');">Expo</a></li>
        <li><a href="http://blog.getbootstrap.com" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Blog');">Blog</a></li>
      </ul>
    </nav>
  </div>
</header>


    <!-- Docs page layout -->
    <div class="bs-docs-header" id="content" tabindex="-1">
      <div class="container">
        <h1>Components</h1>
        <p>Over a dozen reusable components built to provide iconography, dropdowns, input groups, navigation, alerts, and much more.</p>
        <div id="carbonads-container"><div class="carbonad"><div id="azcarbon"></div><script>var z = document.createElement("script"); z.async = true; z.src = "http://engine.carbonads.com/z/32341/azcarbon_2_1_0_HORIZ"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(z, s);</script></div></div>

      </div>
    </div>

    <div class="container bs-docs-container">

      <div class="row">
        <div class="col-md-9" role="main">
          <div class="bs-docs-section">
  <h1 id="glyphicons" class="page-header">Glyphicons</h1>

  <h2 id="glyphicons-glyphs">Available glyphs</h2>
  <p>Includes over 250 glyphs in font format from the Glyphicon Halflings set. <a href="http://glyphicons.com/">Glyphicons</a> Halflings are normally not available for free, but their creator has made them available for Bootstrap free of cost. As a thank you, we only ask that you include a link back to <a href="http://glyphicons.com/">Glyphicons</a> whenever possible.</p>
  <div class="bs-glyphicons">
    <ul class="bs-glyphicons-list">
      
        <li>
          <span class="glyphicon glyphicon-asterisk" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-asterisk</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-plus</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-euro" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-euro</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-eur" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-eur</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-minus" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-minus</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-cloud" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-cloud</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-envelope" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-envelope</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-pencil</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-glass" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-glass</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-music" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-music</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-search</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-heart" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-heart</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-star" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-star</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-star-empty" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-star-empty</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-user</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-film" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-film</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-th-large" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-th-large</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-th" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-th</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-th-list</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ok</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-remove</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-zoom-in</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-zoom-out" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-zoom-out</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-off" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-off</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-signal" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-signal</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-cog</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-trash</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-home" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-home</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-file" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-file</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-time" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-time</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-road" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-road</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-download-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-download-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-download" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-download</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-upload" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-upload</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-inbox" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-inbox</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-play-circle" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-play-circle</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-repeat" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-repeat</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-refresh</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-list-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-lock" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-lock</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-flag" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-flag</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-headphones" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-headphones</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-volume-off" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-volume-off</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-volume-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-volume-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-volume-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-volume-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-qrcode" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-qrcode</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-barcode" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-barcode</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tag" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tag</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tags" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tags</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-book" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-book</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bookmark" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bookmark</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-print" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-print</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-camera" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-camera</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-font" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-font</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bold" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bold</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-italic" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-italic</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-text-height" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-text-height</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-text-width" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-text-width</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-align-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-align-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-align-center" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-align-center</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-align-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-align-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-align-justify" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-align-justify</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-list" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-list</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-indent-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-indent-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-indent-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-indent-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-facetime-video</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-picture" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-picture</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-map-marker" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-map-marker</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-adjust" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-adjust</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tint" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tint</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-edit</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-share" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-share</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-check" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-check</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-move" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-move</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-step-backward" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-step-backward</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-fast-backward" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-fast-backward</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-backward" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-backward</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-play" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-play</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-pause" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-pause</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-stop" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-stop</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-forward" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-forward</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-fast-forward" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-fast-forward</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-step-forward" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-step-forward</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-eject" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-eject</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-chevron-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-chevron-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-plus-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-minus-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-minus-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-remove-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ok-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-question-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-info-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-screenshot" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-screenshot</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-remove-circle</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ok-circle</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ban-circle" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ban-circle</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-arrow-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-arrow-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-arrow-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-arrow-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-share-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-resize-full</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-resize-small" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-resize-small</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-exclamation-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-gift" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-gift</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-leaf" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-leaf</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-fire" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-fire</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-eye-open</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-eye-close" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-eye-close</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-warning-sign</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-plane" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-plane</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-calendar" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-calendar</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-random" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-random</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-comment" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-comment</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-magnet" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-magnet</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-chevron-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-chevron-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-retweet" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-retweet</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-shopping-cart</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-folder-close" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-folder-close</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-folder-open</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-resize-vertical" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-resize-vertical</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-resize-horizontal" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-resize-horizontal</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hdd" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hdd</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bullhorn" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bullhorn</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bell" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bell</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-certificate" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-certificate</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-thumbs-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-thumbs-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-thumbs-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hand-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hand-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hand-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hand-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hand-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hand-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hand-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hand-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-circle-arrow-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-circle-arrow-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-circle-arrow-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-circle-arrow-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-circle-arrow-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-circle-arrow-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-circle-arrow-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-circle-arrow-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-globe" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-globe</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-wrench</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tasks" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tasks</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-filter" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-filter</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-briefcase" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-briefcase</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-fullscreen" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-fullscreen</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-dashboard" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-dashboard</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-paperclip" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-paperclip</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-heart-empty" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-heart-empty</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-link" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-link</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-phone" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-phone</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-pushpin" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-pushpin</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-usd" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-usd</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-gbp" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-gbp</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort-by-alphabet" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort-by-alphabet</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort-by-alphabet-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort-by-alphabet-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort-by-order" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort-by-order</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort-by-order-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort-by-order-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort-by-attributes" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort-by-attributes</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sort-by-attributes-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sort-by-attributes-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-unchecked" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-unchecked</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-expand" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-expand</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-collapse-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-collapse-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-collapse-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-collapse-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-log-in" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-log-in</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-flash" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-flash</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-log-out" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-log-out</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-new-window</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-record</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-save" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-save</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-open" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-open</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-saved" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-saved</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-import" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-import</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-export" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-export</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-send" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-send</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-floppy-disk</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-floppy-saved" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-floppy-saved</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-floppy-remove" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-floppy-remove</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-floppy-save</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-floppy-open" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-floppy-open</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-credit-card" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-credit-card</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-transfer" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-transfer</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-cutlery" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-cutlery</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-header" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-header</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-compressed" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-compressed</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-earphone" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-earphone</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-phone-alt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-phone-alt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tower" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tower</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-stats" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-stats</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sd-video" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sd-video</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hd-video" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hd-video</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-subtitles" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-subtitles</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sound-stereo" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sound-stereo</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sound-dolby" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sound-dolby</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sound-5-1" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sound-5-1</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sound-6-1" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sound-6-1</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sound-7-1" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sound-7-1</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-copyright-mark" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-copyright-mark</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-registration-mark" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-registration-mark</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-cloud-download</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-cloud-upload</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tree-conifer" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tree-conifer</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tree-deciduous" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tree-deciduous</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-cd" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-cd</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-save-file" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-save-file</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-open-file" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-open-file</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-level-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-level-up</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-copy" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-copy</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-paste" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-paste</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-alert</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-equalizer" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-equalizer</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-king" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-king</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-queen" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-queen</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-pawn" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-pawn</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bishop" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bishop</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-knight" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-knight</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-baby-formula" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-baby-formula</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-tent" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-tent</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-blackboard" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-blackboard</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bed" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bed</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-apple" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-apple</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-erase" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-erase</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-hourglass" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-hourglass</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-lamp" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-lamp</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-duplicate</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-piggy-bank" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-piggy-bank</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-scissors" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-scissors</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-bitcoin" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-bitcoin</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-btc" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-btc</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-xbt" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-xbt</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-yen" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-yen</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-jpy" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-jpy</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ruble" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ruble</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-rub" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-rub</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-scale" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-scale</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ice-lolly" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ice-lolly</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-ice-lolly-tasted" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-ice-lolly-tasted</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-education" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-education</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-option-horizontal" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-option-horizontal</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-option-vertical" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-option-vertical</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-menu-hamburger</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-modal-window" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-modal-window</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-oil" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-oil</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-grain" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-grain</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-sunglasses" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-sunglasses</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-text-size" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-text-size</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-text-color" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-text-color</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-text-background" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-text-background</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-object-align-top" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-object-align-top</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-object-align-bottom" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-object-align-bottom</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-object-align-horizontal" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-object-align-horizontal</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-object-align-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-object-align-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-object-align-vertical" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-object-align-vertical</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-object-align-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-object-align-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-triangle-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-triangle-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-triangle-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-triangle-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-triangle-bottom</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-triangle-top" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-triangle-top</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-console" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-console</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-superscript" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-superscript</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-subscript" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-subscript</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-menu-left" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-menu-left</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-menu-right" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-menu-right</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-menu-down" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-menu-down</span>
        </li>
      
        <li>
          <span class="glyphicon glyphicon-menu-up" aria-hidden="true"></span>
          <span class="glyphicon-class">glyphicon glyphicon-menu-up</span>
        </li>
      
    </ul>
  </div>


  <h2 id="glyphicons-how-to-use">How to use</h2>
  <p>For performance reasons, all icons require a base class and individual icon class. To use, place the following code just about anywhere. Be sure to leave a space between the icon and text for proper padding.</p>
  <div class="bs-callout bs-callout-danger" id="callout-glyphicons-dont-mix">
    <h4>Don't mix with other components</h4>
    <p>Icon classes cannot be directly combined with other components. They should not be used along with other classes on the same element. Instead, add a nested <code>&lt;span&gt;</code> and apply the icon classes to the <code>&lt;span&gt;</code>.</p>
  </div>
  <div class="bs-callout bs-callout-danger" id="callout-glyphicons-empty-only">
    <h4>Only for use on empty elements</h4>
    <p>Icon classes should only be used on elements that contain no text content and have no child elements.</p>
  </div>
  <div class="bs-callout bs-callout-info" id="callout-glyphicons-location">
    <h4>Changing the icon font location</h4>
    <p>Bootstrap assumes icon font files will be located in the <code>../fonts/</code> directory, relative to the compiled CSS files. Moving or renaming those font files means updating the CSS in one of three ways:</p>
    <ul>
      <li>Change the <code>@icon-font-path</code> and/or <code>@icon-font-name</code> variables in the source Less files.</li>
      <li>Utilize the <a href="http://lesscss.org/usage/#command-line-usage-relative-urls">relative URLs option</a> provided by the Less compiler.</li>
      <li>Change the <code>url()</code> paths in the compiled CSS.</li>
    </ul>
    <p>Use whatever option best suits your specific development setup.</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-glyphicons-accessibility">
    <h4>Accessible icons</h4>
    <p>Modern versions of assistive technologies will announce CSS generated content, as well as specific Unicode characters. To avoid unintended and confusing output in screen readers (particularly when icons are used purely for decoration), we hide them with the <code>aria-hidden="true"</code> attribute.</p>
    <p>If you're using an icon to convey meaning (rather than only as a decorative element), ensure that this meaning is also conveyed to assistive technologies � for instance, include additional content, visually hidden with the <code>.sr-only</code> class.</p>
    <p>If you're creating controls with no other text (such as a <code>&lt;button&gt;</code> that only contains an icon), you should always provide alternative content to identify the purpose of the control, so that it will make sense to users of assistive technologies. In this case, you could add an <code>aria-label</code> attribute on the control itself.</p>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-search"</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;&lt;/span&gt;</span></code></pre></div>


  <h2 id="glyphicons-examples">Examples</h2>
  <p>Use them in buttons, button groups for a toolbar, navigation, or prepended form inputs.</p>
  <div class="bs-example" data-example-id="glyphicons-general">
    <div class="btn-toolbar" role="toolbar">
      <div class="btn-group">
        <button type="button" class="btn btn-default" aria-label="Left Align"><span class="glyphicon glyphicon-align-left" aria-hidden="true"></span></button>
        <button type="button" class="btn btn-default" aria-label="Center Align"><span class="glyphicon glyphicon-align-center" aria-hidden="true"></span></button>
        <button type="button" class="btn btn-default" aria-label="Right Align"><span class="glyphicon glyphicon-align-right" aria-hidden="true"></span></button>
        <button type="button" class="btn btn-default" aria-label="Justify"><span class="glyphicon glyphicon-align-justify" aria-hidden="true"></span></button>
      </div>
    </div>
    <div class="btn-toolbar" role="toolbar">
      <button type="button" class="btn btn-default btn-lg"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star</button>
      <button type="button" class="btn btn-default"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star</button>
      <button type="button" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star</button>
      <button type="button" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star</button>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span> <span class="na">aria-label=</span><span class="s">"Left Align"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-align-left"</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;/button&gt;</span>

<span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default btn-lg"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-star"</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;&lt;/span&gt;</span> Star
<span class="nt">&lt;/button&gt;</span></code></pre></div>
  <p>An icon used in an <a href="#alerts">alert</a> to convey that it's an error message, with additional <code>.sr-only</code> text to convey this hint to users of assistive technologies.</p>
  <div class="bs-example" data-example-id="glyphicons-accessibility">
    <div class="alert alert-danger" role="alert">
      <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
      <span class="sr-only">Error:</span>
      Enter a valid email address
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-danger"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-exclamation-sign"</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>Error:<span class="nt">&lt;/span&gt;</span>
  Enter a valid email address
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="dropdowns" class="page-header">Dropdowns</h1>

  <p class="lead">Toggleable, contextual menu for displaying lists of links. Made interactive with the <a href="../javascript/#dropdowns">dropdown JavaScript plugin</a>.</p>

  <h2 id="dropdowns-example">Example</h2>
  <p>Wrap the dropdown's trigger and the dropdown menu within <code>.dropdown</code>, or another element that declares <code>position: relative;</code>. Then add the menu's HTML. Dropdown menus can be changed to expand upwards (instead of downwards) by adding <code>.dropup</code> to the parent.</p>
  <div class="bs-example" data-example-id="static-dropdown">
    <div class="dropdown clearfix">
      <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
        Dropdown
        <span class="caret"></span>
      </button>
      <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
      </ul>
    </div>
    <div class="dropup clearfix">
      <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu2" data-toggle="dropdown" aria-expanded="true">
        Dropdown
        <span class="caret"></span>
      </button>
      <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu2">
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
      </ul>
    </div>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">id=</span><span class="s">"dropdownMenu1"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"true"</span><span class="nt">&gt;</span>
    Dropdown
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dropdownMenu1"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"dropup"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">id=</span><span class="s">"dropdownMenu2"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"true"</span><span class="nt">&gt;</span>
    Dropdown
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dropdownMenu2"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="dropdowns-alignment">Alignment</h2>
  <p>By default, a dropdown menu is automatically positioned 100% from the top and along the left side of its parent. Add <code>.dropdown-menu-right</code> to a <code>.dropdown-menu</code> to right align the dropdown menu.</p>
  <div class="bs-callout bs-callout-warning" id="callout-dropdown-positioning">
    <h4>May require additional positioning</h4>
    <p>Dropdowns are automatically positioned via CSS within the normal flow of the document. This means dropdowns may be cropped by parents with certain <code>overflow</code> properties or appear out of bounds of the viewport. Address these issues on your own as they arise.</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-dropdown-pull-right">
    <h4>Deprecated <code>.pull-right</code> alignment</h4>
    <p>As of v3.1.0, we've deprecated <code>.pull-right</code> on dropdown menus. To right-align a menu, use <code>.dropdown-menu-right</code>. Right-aligned nav components in the navbar use a mixin version of this class to automatically align the menu. To override it, use <code>.dropdown-menu-left</code>.</p>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu dropdown-menu-right"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dLabel"</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>

  <h2 id="dropdowns-headers">Headers</h2>
  <p>Add a header to label sections of actions in any dropdown menu.</p>
  <div class="bs-example">
    <div class="dropdown clearfix">
      <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu3" data-toggle="dropdown" aria-expanded="true">
        Dropdown
        <span class="caret"></span>
      </button>
      <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu3">
        <li role="presentation" class="dropdown-header">Dropdown header</li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
        <li role="presentation" class="dropdown-header">Dropdown header</li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
      </ul>
    </div>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dropdownMenu3"</span><span class="nt">&gt;</span>
  ...
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"dropdown-header"</span><span class="nt">&gt;</span>Dropdown header<span class="nt">&lt;/li&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>

  <h2 id="dropdowns-divider">Divider</h2>
  <p>Add a divider to separate series of links in a dropdown menu.</p>
  <div class="bs-example">
    <div class="dropdown clearfix">
      <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenuDivider" data-toggle="dropdown" aria-expanded="true">
        Dropdown
        <span class="caret"></span>
      </button>
      <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenuDivider">
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
        <li role="presentation" class="divider"></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
      </ul>
    </div>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dropdownMenuDivider"</span><span class="nt">&gt;</span>
  ...
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>

  <h2 id="dropdowns-disabled">Disabled menu items</h2>
  <p>Add <code>.disabled</code> to a <code>&lt;li&gt;</code> in the dropdown to disable the link.</p>
  <div class="bs-example">
    <div class="dropdown clearfix">
      <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu4" data-toggle="dropdown" aria-expanded="true">
        Dropdown
        <span class="caret"></span>
      </button>
      <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu4">
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Regular link</a></li>
        <li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Disabled link</a></li>
        <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another link</a></li>
      </ul>
    </div>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span> <span class="na">aria-labelledby=</span><span class="s">"dropdownMenu4"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Regular link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"disabled"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Disabled link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">role=</span><span class="s">"menuitem"</span> <span class="na">tabindex=</span><span class="s">"-1"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="btn-groups" class="page-header">Button groups</h1>

  <p class="lead">Group a series of buttons together on a single line with the button group. Add on optional JavaScript radio and checkbox style behavior with <a href="../javascript/#buttons">our buttons plugin</a>.</p>

  <div class="bs-callout bs-callout-warning" id="callout-btn-group-tooltips">
    <h4>Tooltips &amp; popovers in button groups require special setting</h4>
    <p>When using tooltips or popovers on elements within a <code>.btn-group</code>, you'll have to specify the option <code>container: 'body'</code> to avoid unwanted side effects (such as the element growing wider and/or losing its rounded corners when the tooltip or popover is triggered).</p>
  </div>

  <div class="bs-callout bs-callout-warning" id="callout-btn-group-accessibility">
    <h4>Ensure correct <code>role</code> and provide a label</h4>
    <p>In order for assistive technologies � such as screen readers � to convey that a series of buttons is grouped, an appropriate <code>role</code> attribute needs to be provided. For button groups, this would be <code>role="group"</code>, while toolbars should have a <code>role="toolbar"</code>.</p>
    <p>One exception are groups which only contain a single control (for instance the <a href="#btn-groups-justified">justified button groups</a> with <code>&lt;button&gt;</code> elements) or a dropdown.</p>
    <p>In addition, groups and toolbars should be given an explicit label, as most assistive technologies will otherwise not announce them, despite the presence of the correct <code>role</code> attribute. In the examples provided here, we use <code>aria-label</code>, but alternatives such as <code>aria-labelledby</code> can also be used.</p>
  </div>

  <h2 id="btn-groups-single">Basic example</h2>
  <p>Wrap a series of buttons with <code>.btn</code> in <code>.btn-group</code>.</p>
  <div class="bs-example" data-example-id="simple-button-group">
    <div class="btn-group" role="group" aria-label="Basic example">
      <button type="button" class="btn btn-default">Left</button>
      <button type="button" class="btn btn-default">Middle</button>
      <button type="button" class="btn btn-default">Right</button>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Left<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Middle<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Right<span class="nt">&lt;/button&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-groups-toolbar">Button toolbar</h2>
  <p>Combine sets of <code>&lt;div class="btn-group"&gt;</code> into a <code>&lt;div class="btn-toolbar"&gt;</code> for more complex components.</p>
  <div class="bs-example" data-example-id="simple-button-toolbar">
    <div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
      <div class="btn-group" role="group" aria-label="First group">
        <button type="button" class="btn btn-default">1</button>
        <button type="button" class="btn btn-default">2</button>
        <button type="button" class="btn btn-default">3</button>
        <button type="button" class="btn btn-default">4</button>
      </div>
      <div class="btn-group" role="group" aria-label="Second group">
        <button type="button" class="btn btn-default">5</button>
        <button type="button" class="btn btn-default">6</button>
        <button type="button" class="btn btn-default">7</button>
      </div>
      <div class="btn-group" role="group" aria-label="Third group">
        <button type="button" class="btn btn-default">8</button>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-toolbar"</span> <span class="na">role=</span><span class="s">"toolbar"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-groups-sizing">Sizing</h2>
  <p>Instead of applying button sizing classes to every button in a group, just add <code>.btn-group-*</code> to each <code>.btn-group</code>, including when nesting multiple groups.</p>
  <div class="bs-example" data-example-id="button-group-sizing">
    <div class="btn-group btn-group-lg" role="group" aria-label="Large button group">
      <button type="button" class="btn btn-default">Left</button>
      <button type="button" class="btn btn-default">Middle</button>
      <button type="button" class="btn btn-default">Right</button>
    </div>
    <br>
    <div class="btn-group" role="group" aria-label="Default button group">
      <button type="button" class="btn btn-default">Left</button>
      <button type="button" class="btn btn-default">Middle</button>
      <button type="button" class="btn btn-default">Right</button>
    </div>
    <br>
    <div class="btn-group btn-group-sm" role="group" aria-label="Small button group">
      <button type="button" class="btn btn-default">Left</button>
      <button type="button" class="btn btn-default">Middle</button>
      <button type="button" class="btn btn-default">Right</button>
    </div>
    <br>
    <div class="btn-group btn-group-xs" role="group" aria-label="Extra-small button group">
      <button type="button" class="btn btn-default">Left</button>
      <button type="button" class="btn btn-default">Middle</button>
      <button type="button" class="btn btn-default">Right</button>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group btn-group-lg"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group btn-group-sm"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group btn-group-xs"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-groups-nested">Nesting</h2>
  <p>Place a <code>.btn-group</code> within another <code>.btn-group</code> when you want dropdown menus mixed with a series of buttons.</p>
  <div class="bs-example" data-example-id="button-group-nesting">
    <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
      <button type="button" class="btn btn-default">1</button>
      <button type="button" class="btn btn-default">2</button>

      <div class="btn-group" role="group">
        <button id="btnGroupDrop1" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          Dropdown
          <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu" aria-labelledby="btnGroupDrop1">
          <li><a href="#">Dropdown link</a></li>
          <li><a href="#">Dropdown link</a></li>
        </ul>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>1<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>2<span class="nt">&lt;/button&gt;</span>

  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
      Dropdown
      <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;/button&gt;</span>
    <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Dropdown link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
      <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Dropdown link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;/ul&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-groups-vertical">Vertical variation</h2>
  <p>Make a set of buttons appear vertically stacked rather than horizontally. <strong class="text-danger">Split button dropdowns are not supported here.</strong></p>
  <div class="bs-example" data-example-id="vertical-button-group">
    <div class="btn-group-vertical" role="group" aria-label="Vertical button group">
      <button type="button" class="btn btn-default">Button</button>
      <button type="button" class="btn btn-default">Button</button>
      <div class="btn-group" role="group">
        <button id="btnGroupVerticalDrop1" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          Dropdown
          <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu" aria-labelledby="btnGroupVerticalDrop1">
          <li><a href="#">Dropdown link</a></li>
          <li><a href="#">Dropdown link</a></li>
        </ul>
      </div>
      <button type="button" class="btn btn-default">Button</button>
      <button type="button" class="btn btn-default">Button</button>
      <div class="btn-group" role="group">
        <button id="btnGroupVerticalDrop2" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          Dropdown
          <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu" aria-labelledby="btnGroupVerticalDrop2">
          <li><a href="#">Dropdown link</a></li>
          <li><a href="#">Dropdown link</a></li>
        </ul>
      </div>
      <div class="btn-group" role="group">
        <button id="btnGroupVerticalDrop3" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          Dropdown
          <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu" aria-labelledby="btnGroupVerticalDrop3">
          <li><a href="#">Dropdown link</a></li>
          <li><a href="#">Dropdown link</a></li>
        </ul>
      </div>
      <div class="btn-group" role="group">
        <button id="btnGroupVerticalDrop4" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          Dropdown
          <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu" aria-labelledby="btnGroupVerticalDrop4">
          <li><a href="#">Dropdown link</a></li>
          <li><a href="#">Dropdown link</a></li>
        </ul>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group-vertical"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-groups-justified">Justified button groups</h2>
  <p>Make a group of buttons stretch at equal sizes to span the entire width of its parent. Also works with button dropdowns within the button group.</p>

  <div class="bs-callout bs-callout-warning" id="callout-btn-group-justified-dbl-border">
    <h4>Handling borders</h4>
    <p>Due to the specific HTML and CSS used to justify buttons (namely <code>display: table-cell</code>), the borders between them are doubled. In regular button groups, <code>margin-left: -1px</code> is used to stack the borders instead of removing them. However, <code>margin</code> doesn't work with <code>display: table-cell</code>. As a result, depending on your customizations to Bootstrap, you may wish to remove or re-color the borders.</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-btn-group-ie8-border">
    <h4>IE8 and borders</h4>
    <p>Internet Explorer 8 doesn't render borders on buttons in a justified button group, whether it's on <code>&lt;a&gt;</code> or <code>&lt;button&gt;</code> elements. To get around that, wrap each button in another <code>.btn-group</code>.</p>
    <p>See <a href="https://github.com/twbs/bootstrap/issues/12476">#12476</a> for more information.</p>
  </div>

  <h4>With <code>&lt;a&gt;</code> elements</h4>
  <p>Just wrap a series of <code>.btn</code>s in <code>.btn-group.btn-group-justified</code>.</p>
  <div class="bs-example" data-example-id="simple-justified-button-group">
    <div class="btn-group btn-group-justified" role="group" aria-label="Justified button group">
      <a href="#" class="btn btn-default" role="button">Left</a>
      <a href="#" class="btn btn-default" role="button">Middle</a>
      <a href="#" class="btn btn-default" role="button">Right</a>
    </div>
    <br>
    <div class="btn-group btn-group-justified" role="group" aria-label="Justified button group with nested dropdown">
      <a href="#" class="btn btn-default" role="button">Left</a>
      <a href="#" class="btn btn-default" role="button">Middle</a>
      <div class="btn-group" role="group">
        <a href="#" class="btn btn-default dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
          Dropdown <span class="caret"></span>
        </a>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group btn-group-justified"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-warning" id="callout-btn-group-anchor-btn">
    <h4>Links acting as buttons</h4>
    <p>If the <code>&lt;a&gt;</code> elements are used to act as buttons � triggering in-page functionality, rather than navigating to another document or section within the current page � they should also be given an appropriate <code>role="button"</code>.</p>
  </div>

  <h4>With <code>&lt;button&gt;</code> elements</h4>
  <p>To use justified button groups with <code>&lt;button&gt;</code> elements, <strong class="text-danger">you must wrap each button in a button group</strong>. Most browsers don't properly apply our CSS for justification to <code>&lt;button&gt;</code> elements, but since we support button dropdowns, we can work around that.</p>
  <div class="bs-example" data-example-id="button-tag-button-group-justified">
    <div class="btn-group btn-group-justified" role="group" aria-label="Justified button group">
      <div class="btn-group" role="group">
        <button type="button" class="btn btn-default">Left</button>
      </div>
      <div class="btn-group" role="group">
        <button type="button" class="btn btn-default">Middle</button>
      </div>
      <div class="btn-group" role="group">
        <button type="button" class="btn btn-default">Right</button>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group btn-group-justified"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Left<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Middle<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span> <span class="na">role=</span><span class="s">"group"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Right<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="btn-dropdowns" class="page-header">Button dropdowns</h1>

  <p class="lead">Use any button to trigger a dropdown menu by placing it within a <code>.btn-group</code> and providing the proper menu markup.</p>

  <div class="bs-callout bs-callout-danger" id="callout-btndropdown-dependency">
    <h4>Plugin dependency</h4>
    <p>Button dropdowns require the <a href="../javascript/#dropdowns">dropdown plugin</a> to be included in your version of Bootstrap.</p>
  </div>

  <h2 id="btn-dropdowns-single">Single button dropdowns</h2>
  <p>Turn a button into a dropdown toggle with some basic markup changes.</p>
  <div class="bs-example" data-example-id="single-button-dropdown">
    <div class="btn-group">
      <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Default <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Primary <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Success <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Info <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-warning dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Warning <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Danger <span class="caret"></span></button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="c">&lt;!-- Single button --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
    Action <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-dropdowns-split">Split button dropdowns</h2>
  <p>Similarly, create split button dropdowns with the same markup changes, only with a separate button.</p>
  <div class="bs-example" data-example-id="split-button-dropdown">
    <div class="btn-group">
      <button type="button" class="btn btn-default">Default</button>
      <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
        <span class="caret"></span>
        <span class="sr-only">Toggle Dropdown</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-primary">Primary</button>
      <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
        <span class="caret"></span>
        <span class="sr-only">Toggle Dropdown</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-success">Success</button>
      <button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
        <span class="caret"></span>
        <span class="sr-only">Toggle Dropdown</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-info">Info</button>
      <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
        <span class="caret"></span>
        <span class="sr-only">Toggle Dropdown</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-warning">Warning</button>
      <button type="button" class="btn btn-warning dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
        <span class="caret"></span>
        <span class="sr-only">Toggle Dropdown</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
    <div class="btn-group">
      <button type="button" class="btn btn-danger">Danger</button>
      <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
        <span class="caret"></span>
        <span class="sr-only">Toggle Dropdown</span>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
      </ul>
    </div><!-- /btn-group -->
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="c">&lt;!-- Split button --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-danger"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-danger dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>Toggle Dropdown<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-dropdowns-sizing">Sizing</h2>
  <p>Button dropdowns work with buttons of all sizes.</p>
  <div class="bs-example" data-example-id="button-dropdown-sizing">
    <div class="btn-toolbar" role="toolbar">
      <div class="btn-group">
        <button class="btn btn-default btn-lg dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
          Large button <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </div><!-- /btn-group -->
    </div><!-- /btn-toolbar -->
    <div class="btn-toolbar" role="toolbar">
      <div class="btn-group">
        <button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
          Small button <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </div><!-- /btn-group -->
    </div><!-- /btn-toolbar -->
    <div class="btn-toolbar" role="toolbar">
      <div class="btn-group">
        <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
          Extra small button <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </div><!-- /btn-group -->
    </div><!-- /btn-toolbar -->
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="c">&lt;!-- Large button group --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default btn-lg dropdown-toggle"</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
    Large button <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="c">&lt;!-- Small button group --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default btn-sm dropdown-toggle"</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
    Small button <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="c">&lt;!-- Extra small button group --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default btn-xs dropdown-toggle"</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
    Extra small button <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="btn-dropdowns-dropup">Dropup variation</h2>
  <p>Trigger dropdown menus above elements by adding <code>.dropup</code> to the parent.</p>
  <div class="bs-example" data-example-id="button-dropdown-dropup">
    <div class="btn-toolbar" role="toolbar">
      <div class="btn-group dropup">
        <button type="button" class="btn btn-default">Dropup</button>
        <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          <span class="caret"></span>
          <span class="sr-only">Toggle Dropdown</span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </div><!-- /btn-group -->
      <div class="btn-group dropup">
        <button type="button" class="btn btn-primary">Right dropup</button>
        <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          <span class="caret"></span>
          <span class="sr-only">Toggle Dropdown</span>
        </button>
        <ul class="dropdown-menu dropdown-menu-right" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </div><!-- /btn-group -->
    </div>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"btn-group dropup"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Dropup<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>Toggle Dropdown<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- Dropdown menu links --&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="input-groups" class="page-header">Input groups</h1>

  <p class="lead">Extend form controls by adding text or buttons before, after, or on both sides of any text-based <code>&lt;input&gt;</code>. Use <code>.input-group</code> with an <code>.input-group-addon</code> to prepend or append elements to a single <code>.form-control</code>.</p>

  <div class="bs-callout bs-callout-danger" id="callout-inputgroup-text-input-only">
    <h4>Textual <code>&lt;input&gt;</code>s only</h4>
    <p>Avoid using <code>&lt;select&gt;</code> elements here as they cannot be fully styled in WebKit browsers.</p>
    <p>Avoid using <code>&lt;textarea&gt;</code> elements here as their <code>rows</code> attribute will not be respected in some cases.</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-inputgroup-container-body">
    <h4>Tooltips &amp; popovers in input groups require special setting</h4>
    <p>When using tooltips or popovers on elements within an <code>.input-group</code>, you'll have to specify the option <code>container: 'body'</code> to avoid unwanted side effects (such as the element growing wider and/or losing its rounded corners when the tooltip or popover is triggered).</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-inputgroup-dont-mix">
    <h4>Don't mix with other components</h4>
    <p>Do not mix form groups or grid column classes directly with input groups. Instead, nest the input group inside of the form group or grid-related element.</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-inputgroup-form-labels">
    <h4>Always add labels</h4>
    <p>Screen readers will have trouble with your forms if you don't include a label for every input. For these input groups, ensure that any additional label or functionality is conveyed to assistive technologies.</p>
    <p>The exact technique to be used (<code>&lt;label&gt;</code> elements hidden using the <code>.sr-only</code> class, or use of the <code>aria-label</code>, <code>aria-labelledby</code>, <code>aria-describedby</code>, <code>title</code> or <code>placeholder</code> attribute) and what additional information will need to be conveyed will vary depending on the exact type of interface widget you're implementing. The examples in this section provide a few suggested, case-specific approaches.</p>
  </div>

  <h2 id="input-groups-basic">Basic example</h2>
  <p>Place one add-on or button on either side of an input. You may also place one on both sides of an input.</p>
  <p><strong class="text-danger">We do not support multiple add-ons on a single side.</strong></p>
  <p><strong class="text-danger">We do not support multiple form-controls in a single input group.</strong></p>
  <form class="bs-example bs-example-form" data-example-id="simple-input-groups">
    <div class="input-group">
      <span class="input-group-addon" id="basic-addon1">@</span>
      <input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1">
    </div>
    <br>
    <div class="input-group">
      <input type="text" class="form-control" placeholder="Recipient's username" aria-describedby="basic-addon2">
      <span class="input-group-addon" id="basic-addon2">@example.com</span>
    </div>
    <br>
    <div class="input-group">
      <span class="input-group-addon">$</span>
      <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
      <span class="input-group-addon">.00</span>
    </div>
  </form>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span> <span class="na">id=</span><span class="s">"basic-addon1"</span><span class="nt">&gt;</span>@<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Username"</span> <span class="na">aria-describedby=</span><span class="s">"basic-addon1"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Recipient's username"</span> <span class="na">aria-describedby=</span><span class="s">"basic-addon2"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span> <span class="na">id=</span><span class="s">"basic-addon2"</span><span class="nt">&gt;</span>@example.com<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">&gt;</span>$<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"Amount (to the nearest dollar)"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">&gt;</span>.00<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="input-groups-sizing">Sizing</h2>
  <p>Add the relative form sizing classes to the <code>.input-group</code> itself and contents within will automatically resize�no need for repeating the form control size classes on each element.</p>
  <form class="bs-example bs-example-form" data-example-id="input-group-sizing">
    <div class="input-group input-group-lg">
      <span class="input-group-addon" id="sizing-addon1">@</span>
      <input type="text" class="form-control" placeholder="Username" aria-describedby="sizing-addon1">
    </div>
    <br>
    <div class="input-group">
      <span class="input-group-addon" id="sizing-addon2">@</span>
      <input type="text" class="form-control" placeholder="Username" aria-describedby="sizing-addon2">
    </div>
    <br>
    <div class="input-group input-group-sm">
      <span class="input-group-addon" id="sizing-addon3">@</span>
      <input type="text" class="form-control" placeholder="Username" aria-describedby="sizing-addon3">
    </div>
  </form>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group input-group-lg"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span> <span class="na">id=</span><span class="s">"sizing-addon1"</span><span class="nt">&gt;</span>@<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Username"</span> <span class="na">aria-describedby=</span><span class="s">"sizing-addon1"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span> <span class="na">id=</span><span class="s">"sizing-addon2"</span><span class="nt">&gt;</span>@<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Username"</span> <span class="na">aria-describedby=</span><span class="s">"sizing-addon2"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group input-group-sm"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span> <span class="na">id=</span><span class="s">"sizing-addon3"</span><span class="nt">&gt;</span>@<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Username"</span> <span class="na">aria-describedby=</span><span class="s">"sizing-addon3"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>


  <h2 id="input-groups-checkboxes-radios">Checkboxes and radio addons</h2>
  <p>Place any checkbox or radio option within an input group's addon instead of text.</p>
  <form class="bs-example bs-example-form" data-example-id="input-group-with-checkbox-radio">
    <div class="row">
      <div class="col-lg-6">
        <div class="input-group">
          <span class="input-group-addon">
            <input type="checkbox" aria-label="Checkbox for following text input">
          </span>
          <input type="text" class="form-control" aria-label="Text input with checkbox">
        </div><!-- /input-group -->
      </div><!-- /.col-lg-6 -->
      <div class="col-lg-6">
        <div class="input-group">
          <span class="input-group-addon">
            <input type="radio" aria-label="Radio button for following text input">
          </span>
          <input type="text" class="form-control" aria-label="Text input with radio button">
        </div><!-- /input-group -->
      </div><!-- /.col-lg-6 -->
    </div><!-- /.row -->
  </form>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-lg-6"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"checkbox"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /input-group --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.col-lg-6 --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-lg-6"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"radio"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /input-group --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.col-lg-6 --&gt;</span>
<span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.row --&gt;</span></code></pre></div>


  <h2 id="input-groups-buttons">Button addons</h2>
  <p>Buttons in input groups are a bit different and require one extra level of nesting. Instead of <code>.input-group-addon</code>, you'll need to use <code>.input-group-btn</code> to wrap the buttons. This is required due to default browser styles that cannot be overridden.</p>
  <form class="bs-example bs-example-form" data-example-id="input-group-with-button">
    <div class="row">
      <div class="col-lg-6">
        <div class="input-group">
          <span class="input-group-btn">
            <button class="btn btn-default" type="button">Go!</button>
          </span>
          <input type="text" class="form-control" placeholder="Search for...">
        </div><!-- /input-group -->
      </div><!-- /.col-lg-6 -->
      <div class="col-lg-6">
        <div class="input-group">
          <input type="text" class="form-control" placeholder="Search for...">
          <span class="input-group-btn">
            <button class="btn btn-default" type="button">Go!</button>
          </span>
        </div><!-- /input-group -->
      </div><!-- /.col-lg-6 -->
    </div><!-- /.row -->
  </form>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-lg-6"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-btn"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default"</span> <span class="na">type=</span><span class="s">"button"</span><span class="nt">&gt;</span>Go!<span class="nt">&lt;/button&gt;</span>
      <span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Search for..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /input-group --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.col-lg-6 --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-lg-6"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Search for..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"input-group-btn"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-default"</span> <span class="na">type=</span><span class="s">"button"</span><span class="nt">&gt;</span>Go!<span class="nt">&lt;/button&gt;</span>
      <span class="nt">&lt;/span&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /input-group --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.col-lg-6 --&gt;</span>
<span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.row --&gt;</span></code></pre></div>

  <h2 id="input-groups-buttons-dropdowns">Buttons with dropdowns</h2>
  <p></p>
  <form class="bs-example bs-example-form" data-example-id="input-group-dropdowns">
    <div class="row">
      <div class="col-lg-6">
        <div class="input-group">
          <div class="input-group-btn">
            <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Action <span class="caret"></span></button>
            <ul class="dropdown-menu" role="menu">
              <li><a href="#">Action</a></li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li><a href="#">Separated link</a></li>
            </ul>
          </div><!-- /btn-group -->
          <input type="text" class="form-control" aria-label="Text input with dropdown button">
        </div><!-- /input-group -->
      </div><!-- /.col-lg-6 -->
      <div class="col-lg-6">
        <div class="input-group">
          <input type="text" class="form-control" aria-label="Text input with dropdown button">
          <div class="input-group-btn">
            <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Action <span class="caret"></span></button>
            <ul class="dropdown-menu dropdown-menu-right" role="menu">
              <li><a href="#">Action</a></li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li><a href="#">Separated link</a></li>
            </ul>
          </div><!-- /btn-group -->
        </div><!-- /input-group -->
      </div><!-- /.col-lg-6 -->
    </div><!-- /.row -->
  </form>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-lg-6"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-btn"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>Action <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;&lt;/button&gt;</span>
        <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
        <span class="nt">&lt;/ul&gt;</span>
      <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /btn-group --&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /input-group --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.col-lg-6 --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-lg-6"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-btn"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>Action <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;&lt;/button&gt;</span>
        <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu dropdown-menu-right"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
        <span class="nt">&lt;/ul&gt;</span>
      <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /btn-group --&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /input-group --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.col-lg-6 --&gt;</span>
<span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.row --&gt;</span></code></pre></div>

  <h2 id="input-groups-buttons-segmented">Segmented buttons</h2>
  <form class="bs-example bs-example-form" data-example-id="input-group-segmented-buttons">
    <div class="row">
      <div class="col-lg-6">
        <div class="input-group">
          <div class="input-group-btn">
            <button type="button" class="btn btn-default">Action</button>
            <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
              <span class="caret"></span>
              <span class="sr-only">Toggle Dropdown</span>
            </button>
            <ul class="dropdown-menu" role="menu">
              <li><a href="#">Action</a></li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li><a href="#">Separated link</a></li>
            </ul>
          </div>
          <input type="text" class="form-control" aria-label="Text input with segmented button dropdown">
        </div><!-- /.input-group -->
      </div><!-- /.col-lg-6 -->
      <div class="col-lg-6">
        <div class="input-group">
          <input type="text" class="form-control" aria-label="Text input with segmented button dropdown">
          <div class="input-group-btn">
            <button type="button" class="btn btn-default">Action</button>
            <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
              <span class="caret"></span>
              <span class="sr-only">Toggle Dropdown</span>
            </button>
            <ul class="dropdown-menu dropdown-menu-right" role="menu">
              <li><a href="#">Action</a></li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li><a href="#">Separated link</a></li>
            </ul>
          </div>
        </div><!-- /.input-group -->
      </div><!-- /.col-lg-6 -->
    </div><!-- /.row -->
  </form>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-btn"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- Button and dropdown menu --&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">aria-label=</span><span class="s">"..."</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"input-group-btn"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- Button and dropdown menu --&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="nav" class="page-header">Navs</h1>

  <p class="lead">Navs available in Bootstrap have shared markup, starting with the base <code>.nav</code> class, as well as shared states. Swap modifier classes to switch between each style.</p>

  <div class="bs-callout bs-callout-info" id="callout-navs-tabs-plugin">
    <h4>Using navs for tab panels requires JavaScript tabs plugin</h4>
    <p>For tabs with tabbable areas, you must use the <a href="../javascript/#tabs">tabs JavaScript plugin</a>. The markup will also require additional <code>role</code> and ARIA attributes � see the plugin's <a href="../javascript/#tabs-usage">example markup</a> for further details.</p>
  </div>

  <div class="bs-callout bs-callout-warning" id="callout-navs-accessibility">
    <h4>Make navs used as navigation accessible</h4>
    <p>If you are using navs to provide a navigation bar, be sure to add a <code>role="navigation"</code> to the most logical parent container of the <code>&lt;ul&gt;</code>, or wrap a <code>&lt;nav&gt;</code> element around the whole navigation. Do not add the role to the <code>&lt;ul&gt;</code> itself, as this would prevent it from being announced as an actual list by assistive technologies.</p>
  </div>

  <h2 id="nav-tabs">Tabs</h2>
  <p>Note the <code>.nav-tabs</code> class requires the <code>.nav</code> base class.</p>
  <div class="bs-example" data-example-id="simple-nav-tabs">
    <ul class="nav nav-tabs">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages</a></li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-tabs"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Home<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Profile<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Messages<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>


  <h2 id="nav-pills">Pills</h2>
  <p>Take that same HTML, but use <code>.nav-pills</code> instead:</p>
  <div class="bs-example" data-example-id="simple-nav-pills">
    <ul class="nav nav-pills">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages</a></li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-pills"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Home<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Profile<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Messages<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>
  <p>Pills are also vertically stackable. Just add <code>.nav-stacked</code>.</p>
  <div class="bs-example" data-example-id="simple-nav-stacked">
    <ul class="nav nav-pills nav-stacked nav-pills-stacked-example">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages</a></li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-pills nav-stacked"</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>


  <h2 id="nav-justified">Justified</h2>
  <p>Easily make tabs or pills equal widths of their parent at screens wider than 768px with <code>.nav-justified</code>. On smaller screens, the nav links are stacked.</p>
  <p><strong class="text-danger">Justified navbar nav links are currently not supported.</strong></p>
  <div class="bs-callout bs-callout-warning" id="callout-navs-justified-safari">
    <h4>Safari and responsive justified navs</h4>
    <p>As of v8.0, Safari exhibits a bug in which resizing your browser horizontally causes rendering errors in the justified nav that are cleared upon refreshing. This bug is also shown in the <a href="../examples/justified-nav/">justified nav example</a>.</p>
  </div>
  <div class="bs-example" data-example-id="simple-nav-justified">
    <ul class="nav nav-tabs nav-justified">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages</a></li>
    </ul>
    <br>
    <ul class="nav nav-pills nav-justified">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages</a></li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-tabs nav-justified"</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-pills nav-justified"</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>


  <h2 id="nav-disabled-links">Disabled links</h2>
  <p>For any nav component (tabs or pills), add <code>.disabled</code> for <strong>gray links and no hover effects</strong>.</p>

  <div class="bs-callout bs-callout-warning" id="callout-navs-anchor-disabled">
    <h4>Link functionality not impacted</h4>
    <p>This class will only change the <code>&lt;a&gt;</code>'s appearance, not its functionality. Use custom JavaScript to disable links here.</p>
  </div>

  <div class="bs-example" data-example-id="disabled-nav-link">
    <ul class="nav nav-pills">
      <li role="presentation"><a href="#">Clickable link</a></li>
      <li role="presentation"><a href="#">Clickable link</a></li>
      <li role="presentation" class="disabled"><a href="#">Disabled link</a></li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-pills"</span><span class="nt">&gt;</span>
  ...
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"disabled"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Disabled link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>


  <h2 id="nav-dropdowns">Using dropdowns</h2>
  <p>Add dropdown menus with a little extra HTML and the <a href="../javascript/#dropdowns">dropdowns JavaScript plugin</a>.</p>

  <h3>Tabs with dropdowns</h3>
  <div class="bs-example" data-example-id="nav-tabs-with-dropdown">
    <ul class="nav nav-tabs">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Help</a></li>
      <li role="presentation" class="dropdown">
        <a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-expanded="false">
          Dropdown <span class="caret"></span>
        </a>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-tabs"</span><span class="nt">&gt;</span>
  ...
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">role=</span><span class="s">"button"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
      Dropdown <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
      ...
    <span class="nt">&lt;/ul&gt;</span>
  <span class="nt">&lt;/li&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>

  <h3>Pills with dropdowns</h3>
  <div class="bs-example" data-example-id="nav-pills-with-dropdown">
    <ul class="nav nav-pills">
      <li role="presentation" class="active"><a href="#">Home</a></li>
      <li role="presentation"><a href="#">Help</a></li>
      <li role="presentation" class="dropdown">
        <a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-expanded="false">
          Dropdown <span class="caret"></span>
        </a>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
        </ul>
      </li>
    </ul>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-pills"</span><span class="nt">&gt;</span>
  ...
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">role=</span><span class="s">"button"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>
      Dropdown <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
      ...
    <span class="nt">&lt;/ul&gt;</span>
  <span class="nt">&lt;/li&gt;</span>
  ...
<span class="nt">&lt;/ul&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="navbar" class="page-header">Navbar</h1>

  <h2 id="navbar-default">Default navbar</h2>
  <p>Navbars are responsive meta components that serve as navigation headers for your application or site. They begin collapsed (and are toggleable) in mobile views and become horizontal as the available viewport width increases.</p>
  <p><strong class="text-danger">Justified navbar nav links are currently not supported.</strong></p>

  <div class="bs-callout bs-callout-warning" id="callout-navbar-overflow">
    <h4>Overflowing content</h4>
    <p>Since Bootstrap doesn't know how much space the content in your navbar needs, you might run into issues with content wrapping into a second row. To resolve this, you can:</p>
    <ol type="a">
      <li>Reduce the amount or width of navbar items.</li>
      <li>Hide certain navbar items at certain screen sizes using <a href="../css/#responsive-utilities">responsive utility classes</a>.</li>
      <li>Change the point at which your navbar switches between collapsed and horizontal mode. Customize the <code>@grid-float-breakpoint</code> variable or add your own media query.</li>
    </ol>
  </div>
  <div class="bs-callout bs-callout-danger" id="callout-navbar-js">
    <h4>Requires JavaScript plugin</h4>
    <p>If JavaScript is disabled and the viewport is narrow enough that the navbar collapses, it will be impossible to expand the navbar and view the content within the <code>.navbar-collapse</code>.</p>
    <p>The responsive navbar requires the <a href="../javascript/#collapse">collapse plugin</a> to be included in your version of Bootstrap.</p>
  </div>
  <div class="bs-callout bs-callout-info" id="callout-navbar-breakpoint">
    <h4>Changing the collapsed mobile navbar breakpoint</h4>
    <p>The navbar collapses into its vertical mobile view when the viewport is narrower than <code>@grid-float-breakpoint</code>, and expands into its horizontal non-mobile view when the viewport is at least <code>@grid-float-breakpoint</code> in width. Adjust this variable in the Less source to control when the navbar collapses/expands. The default value is <code>768px</code> (the smallest "small" or "tablet" screen).</p>
  </div>
  <div class="bs-callout bs-callout-warning" id="callout-navbar-role">
    <h4>Make navbars accessible</h4>
    <p>Be sure to use a <code>&lt;nav&gt;</code> element or, if using a more generic element such as a <code>&lt;div&gt;</code>, add a <code>role="navigation"</code> to every navbar to explicitly identify it as a landmark region for users of assistive technologies.</p>
  </div>

  <div class="bs-example" data-example-id="default-navbar">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu" role="menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li class="divider"></li>
                <li><a href="#">Separated link</a></li>
                <li class="divider"></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>
          <form class="navbar-form navbar-left" role="search">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="Search">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
          </form>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu" role="menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li class="divider"></li>
                <li><a href="#">Separated link</a></li>
              </ul>
            </li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"navbar navbar-default"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container-fluid"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- Brand and toggle get grouped for better mobile display --&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"navbar-header"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"navbar-toggle collapsed"</span> <span class="na">data-toggle=</span><span class="s">"collapse"</span> <span class="na">data-target=</span><span class="s">"#bs-example-navbar-collapse-1"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>Toggle navigation<span class="nt">&lt;/span&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"icon-bar"</span><span class="nt">&gt;&lt;/span&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"icon-bar"</span><span class="nt">&gt;&lt;/span&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"icon-bar"</span><span class="nt">&gt;&lt;/span&gt;</span>
      <span class="nt">&lt;/button&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"navbar-brand"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Brand<span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/div&gt;</span>

    <span class="c">&lt;!-- Collect the nav links, forms, and other content for toggling --&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"collapse navbar-collapse"</span> <span class="na">id=</span><span class="s">"bs-example-navbar-collapse-1"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav navbar-nav"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Link <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>(current)<span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
        <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">role=</span><span class="s">"button"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>Dropdown <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;&lt;/a&gt;</span>
          <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>One more separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
      <span class="nt">&lt;/ul&gt;</span>
      <span class="nt">&lt;form</span> <span class="na">class=</span><span class="s">"navbar-form navbar-left"</span> <span class="na">role=</span><span class="s">"search"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Search"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Submit<span class="nt">&lt;/button&gt;</span>
      <span class="nt">&lt;/form&gt;</span>
      <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav navbar-nav navbar-right"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"dropdown"</span><span class="nt">&gt;</span>
          <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"dropdown-toggle"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">role=</span><span class="s">"button"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span><span class="nt">&gt;</span>Dropdown <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"caret"</span><span class="nt">&gt;&lt;/span&gt;&lt;/a&gt;</span>
          <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"dropdown-menu"</span> <span class="na">role=</span><span class="s">"menu"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Another action<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Something else here<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"divider"</span><span class="nt">&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Separated link<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
          <span class="nt">&lt;/ul&gt;</span>
        <span class="nt">&lt;/li&gt;</span>
      <span class="nt">&lt;/ul&gt;</span>
    <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.navbar-collapse --&gt;</span>
  <span class="nt">&lt;/div&gt;</span><span class="c">&lt;!-- /.container-fluid --&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>


  <h2 id="navbar-brand-image">Brand image</h2>
  <p>Replace the navbar brand with your own image by swapping the text for an <code>&lt;img&gt;</code>. Since the <code>.navbar-brand</code> has its own padding and height, you may need to override some CSS depending on your image.</p>
  <div class="bs-example" data-example-id="navbar-with-image-brand">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <a class="navbar-brand" href="#">
            <img alt="Brand" width="20" height="20" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAA81BMVEX///9VPnxWPXxWPXxWPXxWPXxWPXxWPXz///9hSYT6+vuFc6BXPn37+vz8+/z9/f2LeqWMe6aOfqiTg6uXiK5bQ4BZQX9iS4VdRYFdRYJfSINuWI5vWY9xXJF0YJR3Y5Z4ZZd5ZZd6Z5h9apq0qcW1qsW1q8a6sMqpnLyrn76tocCvpMGwpMJoUoprVYxeRoJjS4abjLGilLemmbrDutDFvdLPx9nX0eDa1OLb1uPd1+Td2OXe2eXh3Ofj3+nk4Orl4evp5u7u7PLv7fPx7/T08vb08/f19Pf29Pj39vn6+fuEcZ9YP35aQn/8/P1ZQH5fR4PINAOdAAAAB3RSTlMAIWWOw/P002ipnAAAAPhJREFUeF6NldWOhEAUBRvtRsfdfd3d3e3/v2ZPmGSWZNPDqScqqaSBSy4CGJbtSi2ubRkiwXRkBo6ZdJIApeEwoWMIS1JYwuZCW7hc6ApJkgrr+T/eW1V9uKXS5I5GXAjW2VAV9KFfSfgJpk+w4yXhwoqwl5AIGwp4RPgdK3XNHD2ETYiwe6nUa18f5jYSxle4vulw7/EtoCdzvqkPv3bn7M0eYbc7xFPXzqCrRCgH0Hsm/IjgTSb04W0i7EGjz+xw+wR6oZ1MnJ9TWrtToEx+4QfcZJ5X6tnhw+nhvqebdVhZUJX/oFcKvaTotUcvUnY188ue/n38AunzPPE8yg7bAAAAAElFTkSuQmCC">
          </a>
        </div>
      </div>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"navbar navbar-default"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container-fluid"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"navbar-header"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"navbar-brand"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">alt=</span><span class="s">"Brand"</span> <span class="na">src=</span><span class="s">"..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>


  <h2 id="navbar-forms">Forms</h2>
  <p>Place form content within <code>.navbar-form</code> for proper vertical alignment and collapsed behavior in narrow viewports. Use the alignment options to decide where it resides within the navbar content.</p>
  <p>As a heads up, <code>.navbar-form</code> shares much of its code with <code>.form-inline</code> via mixin. <strong class="text-danger">Some form controls, like input groups, may require fixed widths to be show up properly within a navbar.</strong></p>
  <div class="bs-example" data-example-id="navbar-form">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-2">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-2">
          <form class="navbar-form navbar-left" role="search">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="Search">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
          </form>
        </div>
      </div>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;form</span> <span class="na">class=</span><span class="s">"navbar-form navbar-left"</span> <span class="na">role=</span><span class="s">"search"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="na">placeholder=</span><span class="s">"Search"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"submit"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span><span class="nt">&gt;</span>Submit<span class="nt">&lt;/button&gt;</span>
<span class="nt">&lt;/form&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-warning" id="callout-navbar-mobile-caveats">
    <h4>Mobile device caveats</h4>
    <p>There are some caveats regarding using form controls within fixed elements on mobile devices. <a href="../getting-started/#support-fixed-position-keyboards">See our browser support docs</a> for details.</p>
  </div>

  <div class="bs-callout bs-callout-warning" id="callout-navbar-form-labels">
    <h4>Always add labels</h4>
    <p>Screen readers will have trouble with your forms if you don't include a label for every input. For these inline forms, you can hide the labels using the <code>.sr-only</code> class. There are further alternative methods of providing a label for assistive technologies, such as the <code>aria-label</code>, <code>aria-labelledby</code> or <code>title</code> attribute. If none of these is present, screen readers may resort to using the <code>placeholder</code> attribute, if present, but note that use of <code>placeholder</code> as a replacement for other labelling methods is not advised.</p>
  </div>


  <h2 id="navbar-buttons">Buttons</h2>
  <p>Add the <code>.navbar-btn</code> class to <code>&lt;button&gt;</code> elements not residing in a <code>&lt;form&gt;</code> to vertically center them in the navbar.</p>
  <div class="bs-example" data-example-id="navbar-button">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-3">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-3">
          <button type="button" class="btn btn-default navbar-btn">Sign in</button>
        </div>
      </div>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"btn btn-default navbar-btn"</span><span class="nt">&gt;</span>Sign in<span class="nt">&lt;/button&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-warning" id="callout-navbar-btn-context">
    <h4>Context-specific usage</h4>
    <p>Like the standard <a href="../css/#buttons">button classes</a>, <code>.navbar-btn</code> can be used on <code>&lt;a&gt;</code> and <code>&lt;input&gt;</code> elements. However, neither <code>.navbar-btn</code> nor the standard button classes should be used on <code>&lt;a&gt;</code> elements within <code>.navbar-nav</code>.</p>
  </div>

  <h2 id="navbar-text">Text</h2>
  <p>Wrap strings of text in an element with <code>.navbar-text</code>, usually on a <code>&lt;p&gt;</code> tag for proper leading and color.</p>
  <div class="bs-example" data-example-id="navbar-text">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-4">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-4">
          <p class="navbar-text">Signed in as Mark Otto</p>
        </div>
      </div>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">"navbar-text"</span><span class="nt">&gt;</span>Signed in as Mark Otto<span class="nt">&lt;/p&gt;</span></code></pre></div>


  <h2 id="navbar-links">Non-nav links</h2>
  <p>For folks using standard links that are not within the regular navbar navigation component, use the <code>.navbar-link</code> class to add the proper colors for the default and inverse navbar options.</p>
  <div class="bs-example" data-example-id="navbar-link">
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-5">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-5">
          <p class="navbar-text navbar-right">Signed in as <a href="#" class="navbar-link">Mark Otto</a></p>
        </div>
      </div>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">"navbar-text navbar-right"</span><span class="nt">&gt;</span>Signed in as <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"navbar-link"</span><span class="nt">&gt;</span>Mark Otto<span class="nt">&lt;/a&gt;&lt;/p&gt;</span></code></pre></div>


  <h2 id="navbar-component-alignment">Component alignment</h2>
  <p>Align nav links, forms, buttons, or text, using the <code>.navbar-left</code> or <code>.navbar-right</code> utility classes. Both classes will add a CSS float in the specified direction. For example, to align nav links, put them in a separate <code>&lt;ul&gt;</code> with the respective utility class applied.</p>
  <p>These classes are mixin-ed versions of <code>.pull-left</code> and <code>.pull-right</code>, but they're scoped to media queries for easier handling of navbar components across device sizes.</p>
  <div class="bs-callout bs-callout-warning" id="callout-navbar-right-align">
    <h4>Right aligning multiple components</h4>
    <p>Navbars currently have a limitation with multiple <code>.navbar-right</code> classes. To properly space content, we use negative margin on the last <code>.navbar-right</code> element. When there are multiple elements using that class, these margins don't work as intended.</p>
    <p>We'll revisit this when we can rewrite that component in v4.</p>
  </div>


  <h2 id="navbar-fixed-top">Fixed to top</h2>
  <p>Add <code>.navbar-fixed-top</code> and include a <code>.container</code> or <code>.container-fluid</code> to center and pad navbar content.</p>
  <div class="bs-example bs-navbar-top-example" data-example-id="navbar-fixed-to-top">
    <nav class="navbar navbar-default navbar-fixed-top">
      <!-- We use the fluid option here to avoid overriding the fixed width of a normal container within the narrow content columns. -->
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-6">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>

        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div>
    </nav>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"navbar navbar-default navbar-fixed-top"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-danger" id="callout-navbar-fixed-top-padding">
    <h4>Body padding required</h4>
    <p>The fixed navbar will overlay your other content, unless you add <code>padding</code> to the top of the <code>&lt;body&gt;</code>. Try out your own values or use our snippet below. Tip: By default, the navbar is 50px high.</p>
<div class="highlight"><pre><code class="language-scss" data-lang="scss"><span class="nt">body</span> <span class="p">{</span> <span class="nl">padding-top</span><span class="p">:</span> <span class="m">70px</span><span class="p">;</span> <span class="p">}</span></code></pre></div>
    <p>Make sure to include this <strong>after</strong> the core Bootstrap CSS.</p>
  </div>


  <h2 id="navbar-fixed-bottom">Fixed to bottom</h2>
  <p>Add <code>.navbar-fixed-bottom</code> and include a <code>.container</code> or <code>.container-fluid</code> to center and pad navbar content.</p>
  <div class="bs-example bs-navbar-bottom-example" data-example-id="navbar-fixed-to-bottom">
    <nav class="navbar navbar-default navbar-fixed-bottom">
      <!-- We use the fluid option here to avoid overriding the fixed width of a normal container within the narrow content columns. -->
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-7">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>

        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-7">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div>
    </nav>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"navbar navbar-default navbar-fixed-bottom"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-danger" id="callout-navbar-fixed-bottom-padding">
    <h4>Body padding required</h4>
    <p>The fixed navbar will overlay your other content, unless you add <code>padding</code> to the bottom of the <code>&lt;body&gt;</code>. Try out your own values or use our snippet below. Tip: By default, the navbar is 50px high.</p>
<div class="highlight"><pre><code class="language-scss" data-lang="scss"><span class="nt">body</span> <span class="p">{</span> <span class="nl">padding-bottom</span><span class="p">:</span> <span class="m">70px</span><span class="p">;</span> <span class="p">}</span></code></pre></div>
    <p>Make sure to include this <strong>after</strong> the core Bootstrap CSS.</p>
  </div>


  <h2 id="navbar-static-top">Static top</h2>
  <p>Create a full-width navbar that scrolls away with the page by adding <code>.navbar-static-top</code> and include a <code>.container</code> or <code>.container-fluid</code> to center and pad navbar content.</p>
  <p>Unlike the <code>.navbar-fixed-*</code> classes, you do not need to change any padding on the <code>body</code>.</p>
  <div class="bs-example bs-navbar-top-example" data-example-id="navbar-static-top">
    <nav class="navbar navbar-default navbar-static-top">
      <!-- We use the fluid option here to avoid overriding the fixed width of a normal container within the narrow content columns. -->
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-8">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-8">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div>
    </nav>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"navbar navbar-default navbar-static-top"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>


  <h2 id="navbar-inverted">Inverted navbar</h2>
  <p>Modify the look of the navbar by adding <code>.navbar-inverse</code>.</p>
  <div class="bs-example" data-example-id="inverted-navbar">
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-9">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-9">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
  </div><!-- /example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"navbar navbar-inverse"</span><span class="nt">&gt;</span>
  ...
<span class="nt">&lt;/nav&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="breadcrumbs" class="page-header">Breadcrumbs</h1>

  <p class="lead">Indicate the current page's location within a navigational hierarchy.</p>
  <p>Separators are automatically added in CSS through <code>:before</code> and <code>content</code>.</p>
  <div class="bs-example" data-example-id="simple-breadcrumbs">
    <ol class="breadcrumb">
      <li class="active">Home</li>
    </ol>
    <ol class="breadcrumb">
      <li><a href="#">Home</a></li>
      <li class="active">Library</li>
    </ol>
    <ol class="breadcrumb">
      <li><a href="#">Home</a></li>
      <li><a href="#">Library</a></li>
      <li class="active">Data</li>
    </ol>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ol</span> <span class="na">class=</span><span class="s">"breadcrumb"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Home<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Library<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;</span>Data<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ol&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="pagination" class="page-header">Pagination</h1>

  <p class="lead">Provide pagination links for your site or app with the multi-page pagination component, or the simpler <a href="#pagination-pager">pager alternative</a>.</p>

  <h2 id="pagination-default">Default pagination</h2>
  <p>Simple pagination inspired by Rdio, great for apps and search results. The large block is hard to miss, easily scalable, and provides large click areas.</p>
  <div class="bs-example" data-example-id="simple-pagination">
    <nav>
      <ul class="pagination">
        <li>
          <a href="#" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        <li><a href="#">1</a></li>
        <li><a href="#">2</a></li>
        <li><a href="#">3</a></li>
        <li><a href="#">4</a></li>
        <li><a href="#">5</a></li>
        <li>
          <a href="#" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pagination"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">aria-label=</span><span class="s">"Previous"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;laquo;</span><span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>1<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>2<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>3<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>4<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>5<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">aria-label=</span><span class="s">"Next"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;raquo;</span><span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>

  <h3>Disabled and active states</h3>
  <p>Links are customizable for different circumstances. Use <code>.disabled</code> for unclickable links and <code>.active</code> to indicate the current page.</p>
  <div class="bs-example" data-example-id="disabled-active-pagination">
    <nav>
      <ul class="pagination">
        <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
        <li><a href="#">2</a></li>
        <li><a href="#">3</a></li>
        <li><a href="#">4</a></li>
        <li><a href="#">5</a></li>
        <li><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
     </ul>
   </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pagination"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"disabled"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">aria-label=</span><span class="s">"Previous"</span><span class="nt">&gt;&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;laquo;</span><span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>1 <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>(current)<span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
    ...
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>
  <p>You can optionally swap out active or disabled anchors for <code>&lt;span&gt;</code>, or omit the anchor in the case of the previous/next arrows, to remove click functionality while retaining intended styles.</p>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pagination"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"disabled"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;span&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;laquo;</span><span class="nt">&lt;/span&gt;</span>
      <span class="nt">&lt;/span&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;span&gt;</span>1 <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>(current)<span class="nt">&lt;/span&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
    ...
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>


  <h3>Sizing</h3>
  <p>Fancy larger or smaller pagination? Add <code>.pagination-lg</code> or <code>.pagination-sm</code> for additional sizes.</p>
  <div class="bs-example" data-example-id="pagination-sizing">
    <nav>
      <ul class="pagination pagination-lg">
        <li><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li><a href="#">1</a></li>
        <li><a href="#">2</a></li>
        <li><a href="#">3</a></li>
        <li><a href="#">4</a></li>
        <li><a href="#">5</a></li>
        <li><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
      </ul>
    </nav>
    <nav>
      <ul class="pagination">
        <li><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li><a href="#">1</a></li>
        <li><a href="#">2</a></li>
        <li><a href="#">3</a></li>
        <li><a href="#">4</a></li>
        <li><a href="#">5</a></li>
        <li><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
      </ul>
    </nav>
    <nav>
      <ul class="pagination pagination-sm">
        <li><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li><a href="#">1</a></li>
        <li><a href="#">2</a></li>
        <li><a href="#">3</a></li>
        <li><a href="#">4</a></li>
        <li><a href="#">5</a></li>
        <li><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
      </ul>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;&lt;ul</span> <span class="na">class=</span><span class="s">"pagination pagination-lg"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/ul&gt;&lt;/nav&gt;</span>
<span class="nt">&lt;nav&gt;&lt;ul</span> <span class="na">class=</span><span class="s">"pagination"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/ul&gt;&lt;/nav&gt;</span>
<span class="nt">&lt;nav&gt;&lt;ul</span> <span class="na">class=</span><span class="s">"pagination pagination-sm"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/ul&gt;&lt;/nav&gt;</span></code></pre></div>


  <h2 id="pagination-pager">Pager</h2>
  <p>Quick previous and next links for simple pagination implementations with light markup and styles. It's great for simple sites like blogs or magazines.</p>

  <h3>Default example</h3>
  <p>By default, the pager centers links.</p>
  <div class="bs-example" data-example-id="simple-pager">
    <nav>
      <ul class="pager">
        <li><a href="#">Previous</a></li>
        <li><a href="#">Next</a></li>
      </ul>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pager"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Previous<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Next<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>

  <h3>Aligned links</h3>
  <p>Alternatively, you can align each link to the sides:</p>
  <div class="bs-example" data-example-id="aligned-pager-links">
    <nav>
      <ul class="pager">
        <li class="previous"><a href="#"><span aria-hidden="true">&larr;</span> Older</a></li>
        <li class="next"><a href="#">Newer <span aria-hidden="true">&rarr;</span></a></li>
      </ul>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pager"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"previous"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;larr;</span><span class="nt">&lt;/span&gt;</span> Older<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"next"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Newer <span class="nt">&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;rarr;</span><span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>


  <h3>Optional disabled state</h3>
  <p>Pager links also use the general <code>.disabled</code> utility class from the pagination.</p>
  <div class="bs-example" data-example-id="disabled-pager">
    <nav>
      <ul class="pager">
        <li class="previous disabled"><a href="#"><span aria-hidden="true">&larr;</span> Older</a></li>
        <li class="next"><a href="#">Newer <span aria-hidden="true">&rarr;</span></a></li>
      </ul>
    </nav>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;nav&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pager"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"previous disabled"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;larr;</span><span class="nt">&lt;/span&gt;</span> Older<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"next"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Newer <span class="nt">&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;rarr;</span><span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="labels" class="page-header">Labels</h1>

  <h2>Example</h2>
  <div class="bs-example" data-example-id="labels-in-headings">
    <h1>Example heading <span class="label label-default">New</span></h1>
    <h2>Example heading <span class="label label-default">New</span></h2>
    <h3>Example heading <span class="label label-default">New</span></h3>
    <h4>Example heading <span class="label label-default">New</span></h4>
    <h5>Example heading <span class="label label-default">New</span></h5>
    <h6>Example heading <span class="label label-default">New</span></h6>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;h3&gt;</span>Example heading <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-default"</span><span class="nt">&gt;</span>New<span class="nt">&lt;/span&gt;&lt;/h3&gt;</span></code></pre></div>

  <h2>Available variations</h2>
  <p>Add any of the below mentioned modifier classes to change the appearance of a label.</p>
  <div class="bs-example" data-example-id="label-variants">
    <span class="label label-default">Default</span>
    <span class="label label-primary">Primary</span>
    <span class="label label-success">Success</span>
    <span class="label label-info">Info</span>
    <span class="label label-warning">Warning</span>
    <span class="label label-danger">Danger</span>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-default"</span><span class="nt">&gt;</span>Default<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-primary"</span><span class="nt">&gt;</span>Primary<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-success"</span><span class="nt">&gt;</span>Success<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-info"</span><span class="nt">&gt;</span>Info<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-warning"</span><span class="nt">&gt;</span>Warning<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"label label-danger"</span><span class="nt">&gt;</span>Danger<span class="nt">&lt;/span&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-info" id="callout-labels-inline-block">
    <h4>Have tons of labels?</h4>
    <p>Rendering problems can arise when you have dozens of inline labels within a narrow container, each containing its own <code>inline-block</code> element (like an icon). The way around this is setting <code>display: inline-block;</code>. For context and an example, <a href="https://github.com/twbs/bootstrap/issues/13219">see #13219</a>.</p>
  </div>
</div>

<div class="bs-docs-section">
  <h1 id="badges" class="page-header">Badges</h1>

  <p class="lead">Easily highlight new or unread items by adding a <code>&lt;span class="badge"&gt;</code> to links, Bootstrap navs, and more.</p>

  <div class="bs-example" data-example-id="simple-badges">
    <a href="#">Inbox <span class="badge">42</span></a>
    <br><br>
    <button class="btn btn-primary" type="button">
      Messages <span class="badge">4</span>
    </button>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Inbox <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"badge"</span><span class="nt">&gt;</span>42<span class="nt">&lt;/span&gt;&lt;/a&gt;</span>

<span class="nt">&lt;button</span> <span class="na">class=</span><span class="s">"btn btn-primary"</span> <span class="na">type=</span><span class="s">"button"</span><span class="nt">&gt;</span>
  Messages <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"badge"</span><span class="nt">&gt;</span>4<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/button&gt;</span></code></pre></div>

  <h4>Self collapsing</h4>
  <p>When there are no new or unread items, badges will simply collapse (via CSS's <code>:empty</code> selector) provided no content exists within.</p>

  <div class="bs-callout bs-callout-danger" id="callout-badges-ie8-empty">
    <h4>Cross-browser compatibility</h4>
    <p>Badges won't self collapse in Internet Explorer 8 because it lacks support for the <code>:empty</code> selector.</p>
  </div>

  <h4>Adapts to active nav states</h4>
  <p>Built-in styles are included for placing badges in active states in pill navigations.</p>
  <div class="bs-example" data-example-id="badges-in-pills">
    <ul class="nav nav-pills" role="tablist">
      <li role="presentation" class="active"><a href="#">Home <span class="badge">42</span></a></li>
      <li role="presentation"><a href="#">Profile</a></li>
      <li role="presentation"><a href="#">Messages <span class="badge">3</span></a></li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"nav nav-pills"</span> <span class="na">role=</span><span class="s">"tablist"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span> <span class="na">class=</span><span class="s">"active"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Home <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"badge"</span><span class="nt">&gt;</span>42<span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Profile<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">role=</span><span class="s">"presentation"</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>Messages <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"badge"</span><span class="nt">&gt;</span>3<span class="nt">&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="jumbotron" class="page-header">Jumbotron</h1>

  <p>A lightweight, flexible component that can optionally extend the entire viewport to showcase key content on your site.</p>
  <div class="bs-example" data-example-id="simple-jumbotron">
    <div class="jumbotron">
      <h1>Hello, world!</h1>
      <p>This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
      <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"jumbotron"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;h1&gt;</span>Hello, world!<span class="nt">&lt;/h1&gt;</span>
  <span class="nt">&lt;p&gt;</span>...<span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;p&gt;&lt;a</span> <span class="na">class=</span><span class="s">"btn btn-primary btn-lg"</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">role=</span><span class="s">"button"</span><span class="nt">&gt;</span>Learn more<span class="nt">&lt;/a&gt;&lt;/p&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
  <p>To make the jumbotron full width, and without rounded corners, place it outside all <code>.container</code>s and instead add a <code>.container</code> within.</p>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"jumbotron"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="page-header" class="page-header">Page header</h1>

  <p>A simple shell for an <code>h1</code> to appropriately space out and segment sections of content on a page. It can utilize the <code>h1</code>'s default <code>small</code> element, as well as most other components (with additional styles).</p>
  <div class="bs-example" data-example-id="simple-page-header">
    <div class="page-header">
      <h1>Example page header <small>Subtext for header</small></h1>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"page-header"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;h1&gt;</span>Example page header <span class="nt">&lt;small&gt;</span>Subtext for header<span class="nt">&lt;/small&gt;&lt;/h1&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="thumbnails" class="page-header">Thumbnails</h1>

  <p class="lead">Extend Bootstrap's <a href="../css/#grid">grid system</a> with the thumbnail component to easily display grids of images, videos, text, and more.</p>
  <p>If you're looking for Pinterest-like presentation of thumbnails of varying heights and/or widths, you'll need to use a third-party plugin such as <a href="http://masonry.desandro.com">Masonry</a>, <a href="http://isotope.metafizzy.co">Isotope</a>, or <a href="http://salvattore.com">Salvattore</a>.</p>

  <h2 id="thumbnails-default">Default example</h2>
  <p>By default, Bootstrap's thumbnails are designed to showcase linked images with minimal required markup.</p>
  <div class="bs-example" data-example-id="simple-thumbnails">
    <div class="row">
      <div class="col-xs-6 col-md-3">
        <a href="#" class="thumbnail">
          <img data-src="holder.js/100%x180" alt="Generic placeholder thumbnail">
        </a>
      </div>
      <div class="col-xs-6 col-md-3">
        <a href="#" class="thumbnail">
          <img data-src="holder.js/100%x180" alt="Generic placeholder thumbnail">
        </a>
      </div>
      <div class="col-xs-6 col-md-3">
        <a href="#" class="thumbnail">
          <img data-src="holder.js/100%x180" alt="Generic placeholder thumbnail">
        </a>
      </div>
      <div class="col-xs-6 col-md-3">
        <a href="#" class="thumbnail">
          <img data-src="holder.js/100%x180" alt="Generic placeholder thumbnail">
        </a>
      </div>
    </div>
  </div><!-- /.bs-example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-xs-6 col-md-3"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"thumbnail"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"..."</span> <span class="na">alt=</span><span class="s">"..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  ...
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="thumbnails-custom-content">Custom content</h2>
  <p>With a bit of extra markup, it's possible to add any kind of HTML content like headings, paragraphs, or buttons into thumbnails.</p>
  <div class="bs-example" data-example-id="thumbnails-with-custom-content">
    <div class="row">
      <div class="col-sm-6 col-md-4">
        <div class="thumbnail">
          <img data-src="holder.js/100%x200" alt="Generic placeholder thumbnail">
          <div class="caption">
            <h3>Thumbnail label</h3>
            <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
            <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p>
          </div>
        </div>
      </div>
      <div class="col-sm-6 col-md-4">
        <div class="thumbnail">
          <img data-src="holder.js/100%x200" alt="Generic placeholder thumbnail">
          <div class="caption">
            <h3>Thumbnail label</h3>
            <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
            <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p>
          </div>
        </div>
      </div>
      <div class="col-sm-6 col-md-4">
        <div class="thumbnail">
          <img data-src="holder.js/100%x200" alt="Generic placeholder thumbnail">
          <div class="caption">
            <h3>Thumbnail label</h3>
            <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
            <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p>
          </div>
        </div>
      </div>
    </div>
  </div><!-- /.bs-example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"col-sm-6 col-md-4"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"thumbnail"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"..."</span> <span class="na">alt=</span><span class="s">"..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"caption"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;h3&gt;</span>Thumbnail label<span class="nt">&lt;/h3&gt;</span>
        <span class="nt">&lt;p&gt;</span>...<span class="nt">&lt;/p&gt;</span>
        <span class="nt">&lt;p&gt;&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"btn btn-primary"</span> <span class="na">role=</span><span class="s">"button"</span><span class="nt">&gt;</span>Button<span class="nt">&lt;/a&gt;</span> <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"btn btn-default"</span> <span class="na">role=</span><span class="s">"button"</span><span class="nt">&gt;</span>Button<span class="nt">&lt;/a&gt;&lt;/p&gt;</span>
      <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="alerts" class="page-header">Alerts</h1>

  <p class="lead">Provide contextual feedback messages for typical user actions with the handful of available and flexible alert messages.</p>

  <h2 id="alerts-examples">Examples</h2>
  <p>Wrap any text and an optional dismiss button in <code>.alert</code> and one of the four contextual classes (e.g., <code>.alert-success</code>) for basic alert messages.</p>

  <div class="bs-callout bs-callout-info" id="callout-alerts-no-default">
    <h4>No default class</h4>
    <p>Alerts don't have default classes, only base and modifier classes. A default gray alert doesn't make too much sense, so you're required to specify a type via contextual class. Choose from success, info, warning, or danger.</p>
  </div>

  <div class="bs-example" data-example-id="simple-alerts">
    <div class="alert alert-success" role="alert">
      <strong>Well done!</strong> You successfully read this important alert message.
    </div>
    <div class="alert alert-info" role="alert">
      <strong>Heads up!</strong> This alert needs your attention, but it's not super important.
    </div>
    <div class="alert alert-warning" role="alert">
      <strong>Warning!</strong> Better check yourself, you're not looking too good.
    </div>
    <div class="alert alert-danger" role="alert">
      <strong>Oh snap!</strong> Change a few things up and try submitting again.
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-success"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-info"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-warning"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-danger"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="alerts-dismissible">Dismissible alerts</h2>
  <p>Build on any alert by adding an optional <code>.alert-dismissible</code> and close button.</p>
  <div class="bs-callout bs-callout-info" id="callout-alerts-dismiss-plugin">
    <h4>Requires JavaScript alert plugin</h4>
    <p>For fully functioning, dismissible alerts, you must use the <a href="../javascript/#alerts">alerts JavaScript plugin</a>.</p>
  </div>
  <div class="bs-example" data-example-id="dismissible-alert-css">
    <div class="alert alert-warning alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      <strong>Warning!</strong> Better check yourself, you're not looking too good.
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-warning alert-dismissible"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"button"</span> <span class="na">class=</span><span class="s">"close"</span> <span class="na">data-dismiss=</span><span class="s">"alert"</span> <span class="na">aria-label=</span><span class="s">"Close"</span><span class="nt">&gt;&lt;span</span> <span class="na">aria-hidden=</span><span class="s">"true"</span><span class="nt">&gt;</span><span class="ni">&amp;times;</span><span class="nt">&lt;/span&gt;&lt;/button&gt;</span>
  <span class="nt">&lt;strong&gt;</span>Warning!<span class="nt">&lt;/strong&gt;</span> Better check yourself, you're not looking too good.
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <div class="bs-callout bs-callout-warning" id="callout-alerts-dismiss-use-button">
    <h4>Ensure proper behavior across all devices</h4>
    <p>Be sure to use the <code>&lt;button&gt;</code> element with the <code>data-dismiss="alert"</code> data attribute.</p>
  </div>

  <h2 id="alerts-links">Links in alerts</h2>
  <p>Use the <code>.alert-link</code> utility class to quickly provide matching colored links within any alert.</p>
  <div class="bs-example" data-example-id="alerts-with-links">
    <div class="alert alert-success" role="alert">
      <strong>Well done!</strong> You successfully read <a href="#" class="alert-link">this important alert message</a>.
    </div>
    <div class="alert alert-info" role="alert">
      <strong>Heads up!</strong> This <a href="#" class="alert-link">alert needs your attention</a>, but it's not super important.
    </div>
    <div class="alert alert-warning" role="alert">
      <strong>Warning!</strong> Better check yourself, you're <a href="#" class="alert-link">not looking too good</a>.
    </div>
    <div class="alert alert-danger" role="alert">
      <strong>Oh snap!</strong> <a href="#" class="alert-link">Change a few things up</a> and try submitting again.
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-success"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"alert-link"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-info"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"alert-link"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-warning"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"alert-link"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"alert alert-danger"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"alert-link"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="progress" class="page-header">Progress bars</h1>

  <p class="lead">Provide up-to-date feedback on the progress of a workflow or action with simple yet flexible progress bars.</p>

  <div class="bs-callout bs-callout-danger" id="callout-progress-animation-css3">
    <h4>Cross-browser compatibility</h4>
    <p>Progress bars use CSS3 transitions and animations to achieve some of their effects. These features are not supported in Internet Explorer 9 and below or older versions of Firefox. Opera 12 does not support animations.</p>
  </div>

  <h2 id="progress-basic">Basic example</h2>
  <p>Default progress bar.</p>
  <div class="bs-example" data-example-id="simple-progress-bar">
    <div class="progress">
      <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;">
        <span class="sr-only">60% Complete</span>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"60"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 60%;"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>60% Complete<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="progress-label">With label</h2>
  <p>Remove the <code>&lt;span&gt;</code> with <code>.sr-only</code> class from within the progress bar to show a visible percentage.</p>
  <div class="bs-example" data-example-id="progress-bar-with-label">
    <div class="progress">
      <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;">
        60%
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"60"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 60%;"</span><span class="nt">&gt;</span>
    60%
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
  <p>To ensure that the label text remains legible even for low percentages, consider adding a <code>min-width</code> to the progress bar.</p>
  <div class="bs-example" data-example-id="progress-bar-at-low-percentage">
    <div class="progress">
      <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;">
        0%
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar" role="progressbar" aria-valuenow="2" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em; width: 2%;">
        2%
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"0"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"min-width: 2em;"</span><span class="nt">&gt;</span>
    0%
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"2"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"min-width: 2em; width: 2%;"</span><span class="nt">&gt;</span>
    2%
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>


  <h2 id="progress-alternatives">Contextual alternatives</h2>
  <p>Progress bars use some of the same button and alert classes for consistent styles.</p>
  <div class="bs-example" data-example-id="contextual-progress-bar">
    <div class="progress">
      <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
        <span class="sr-only">40% Complete (success)</span>
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%">
        <span class="sr-only">20% Complete</span>
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%">
        <span class="sr-only">60% Complete (warning)</span>
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%">
        <span class="sr-only">80% Complete (danger)</span>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-success"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"40"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 40%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>40% Complete (success)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-info"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"20"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 20%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>20% Complete<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-warning"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"60"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 60%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>60% Complete (warning)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-danger"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"80"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 80%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>80% Complete (danger)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="progress-striped">Striped</h2>
  <p>Uses a gradient to create a striped effect. Not available in IE9 and below.</p>
  <div class="bs-example" data-example-id="striped-progress-bar">
    <div class="progress">
      <div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
        <span class="sr-only">40% Complete (success)</span>
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%">
        <span class="sr-only">20% Complete</span>
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar progress-bar-warning progress-bar-striped" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%">
        <span class="sr-only">60% Complete (warning)</span>
      </div>
    </div>
    <div class="progress">
      <div class="progress-bar progress-bar-danger progress-bar-striped" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%">
        <span class="sr-only">80% Complete (danger)</span>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-success progress-bar-striped"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"40"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 40%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>40% Complete (success)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-info progress-bar-striped"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"20"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 20%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>20% Complete<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-warning progress-bar-striped"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"60"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 60%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>60% Complete (warning)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-danger progress-bar-striped"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"80"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 80%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>80% Complete (danger)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="progress-animated">Animated</h2>
  <p>Add <code>.active</code> to <code>.progress-bar-striped</code> to animate the stripes right to left. Not available in IE9 and below.</p>
  <div class="bs-example" data-example-id="animated-progress-bar">
    <div class="progress">
      <div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 45%"><span class="sr-only">45% Complete</span></div>
    </div>
    <button type="button" class="btn btn-default bs-docs-activate-animated-progressbar" data-toggle="button" aria-pressed="false" autocomplete="off">Toggle animation</button>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-striped active"</span> <span class="na">role=</span><span class="s">"progressbar"</span> <span class="na">aria-valuenow=</span><span class="s">"45"</span> <span class="na">aria-valuemin=</span><span class="s">"0"</span> <span class="na">aria-valuemax=</span><span class="s">"100"</span> <span class="na">style=</span><span class="s">"width: 45%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>45% Complete<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="progress-stacked">Stacked</h2>
  <p>Place multiple bars into the same <code>.progress</code> to stack them.</p>
  <div class="bs-example" data-example-id="stacked-progress-bar">
    <div class="progress">
      <div class="progress-bar progress-bar-success" style="width: 35%">
        <span class="sr-only">35% Complete (success)</span>
      </div>
      <div class="progress-bar progress-bar-warning progress-bar-striped" style="width: 20%">
        <span class="sr-only">20% Complete (warning)</span>
      </div>
      <div class="progress-bar progress-bar-danger" style="width: 10%">
        <span class="sr-only">10% Complete (danger)</span>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-success"</span> <span class="na">style=</span><span class="s">"width: 35%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>35% Complete (success)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-warning progress-bar-striped"</span> <span class="na">style=</span><span class="s">"width: 20%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>20% Complete (warning)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"progress-bar progress-bar-danger"</span> <span class="na">style=</span><span class="s">"width: 10%"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">&gt;</span>10% Complete (danger)<span class="nt">&lt;/span&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="media" class="page-header">Media object</h1>

  <p class="lead">Abstract object styles for building various types of components (like blog comments, Tweets, etc) that feature a left- or right-aligned image alongside textual content.</p>

  <h2 id="media-default">Default media</h2>
  <p>The default media displays a media object (images, video, audio) to the left or right of a content block.</p>
  <div class="bs-example" data-example-id="default-media">
    <div class="media">
      <div class="media-left">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Media heading</h4>
        Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
      </div>
    </div>
    <div class="media">
      <div class="media-left">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Media heading</h4>
        Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
        <div class="media">
          <div class="media-left">
            <a href="#">
              <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
            </a>
          </div>
          <div class="media-body">
            <h4 class="media-heading">Nested media heading</h4>
            Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
          </div>
        </div>
      </div>
    </div>
    <div class="media">
      <div class="media-body">
        <h4 class="media-heading">Media heading</h4>
        Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.
      </div>
      <div class="media-right">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
    </div>
    <div class="media">
      <div class="media-left">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Media heading</h4>
        Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.
      </div>
      <div class="media-right">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
    </div>
  </div><!-- /.bs-example -->
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media-left"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">class=</span><span class="s">"media-object"</span> <span class="na">src=</span><span class="s">"..."</span> <span class="na">alt=</span><span class="s">"..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media-body"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">class=</span><span class="s">"media-heading"</span><span class="nt">&gt;</span>Media heading<span class="nt">&lt;/h4&gt;</span>
    ...
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <p>The classes <code>.pull-left</code> and <code>.pull-right</code> also exist and were previously used as part of the media component, but are deprecated for that use as of v3.3.0. They are approximately equivalent to <code>.media-left</code> and <code>.media-right</code>, except that <code>.media-right</code> should be placed after the <code>.media-body</code> in the html.</p>
  <h2 id="media-alignment">Media alignment</h2>
  <p>The images or other media can be aligned top, middle, or bottom. The default is top aligned.</p>
  <div class="bs-example" data-example-id="media-alignment">
    <div class="media">
      <div class="media-left">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Top aligned media</h4>
        <p>Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.</p>
        <p>Donec sed odio dui. Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
      </div>
    </div>
    <div class="media">
      <div class="media-left media-middle">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Middle aligned media</h4>
        <p>Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.</p>
        <p>Donec sed odio dui. Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
      </div>
    </div>
    <div class="media">
      <div class="media-left media-bottom">
        <a href="#">
          <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Bottom aligned media</h4>
        <p>Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.</p>
        <p>Donec sed odio dui. Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media-left media-middle"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;img</span> <span class="na">class=</span><span class="s">"media-object"</span> <span class="na">src=</span><span class="s">"..."</span> <span class="na">alt=</span><span class="s">"..."</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media-body"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">class=</span><span class="s">"media-heading"</span><span class="nt">&gt;</span>Middle aligned media<span class="nt">&lt;/h4&gt;</span>
    ...
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="media-list">Media list</h2>
  <p>With a bit of extra markup, you can use media inside list (useful for comment threads or articles lists).</p>
  <div class="bs-example" data-example-id="media-list">
    <ul class="media-list">
      <li class="media">
        <div class="media-left">
          <a href="#">
            <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
          </a>
        </div>
        <div class="media-body">
          <h4 class="media-heading">Media heading</h4>
          <p>Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.</p>
          <!-- Nested media object -->
          <div class="media">
            <div class="media-left">
              <a href="#">
                <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
              </a>
            </div>
            <div class="media-body">
              <h4 class="media-heading">Nested media heading</h4>
              Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.
              <!-- Nested media object -->
              <div class="media">
                <div class="media-left">
                  <a href="#">
                    <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
                  </a>
                </div>
                <div class="media-body">
                  <h4 class="media-heading">Nested media heading</h4>
                  Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.
                </div>
              </div>
            </div>
          </div>
          <!-- Nested media object -->
          <div class="media">
            <div class="media-left">
              <a href="#">
                <img class="media-object" data-src="holder.js/64x64" alt="Generic placeholder image">
              </a>
            </div>
            <div class="media-body">
              <h4 class="media-heading">Nested media heading</h4>
              Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"media-list"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"media"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media-left"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">class=</span><span class="s">"media-object"</span> <span class="na">src=</span><span class="s">"..."</span> <span class="na">alt=</span><span class="s">"..."</span><span class="nt">&gt;</span>
      <span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"media-body"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;h4</span> <span class="na">class=</span><span class="s">"media-heading"</span><span class="nt">&gt;</span>Media heading<span class="nt">&lt;/h4&gt;</span>
      ...
    <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="list-group" class="page-header">List group</h1>

  <p class="lead">List groups are a flexible and powerful component for displaying not only simple lists of elements, but complex ones with custom content.</p>

  <h2 id="list-group-basic">Basic example</h2>
  <p>The most basic list group is simply an unordered list with list items, and the proper classes. Build upon it with the options that follow, or your own CSS as needed.</p>
  <div class="bs-example" data-example-id="simple-list-group">
    <ul class="list-group">
      <li class="list-group-item">Cras justo odio</li>
      <li class="list-group-item">Dapibus ac facilisis in</li>
      <li class="list-group-item">Morbi leo risus</li>
      <li class="list-group-item">Porta ac consectetur ac</li>
      <li class="list-group-item">Vestibulum at eros</li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Cras justo odio<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Dapibus ac facilisis in<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Morbi leo risus<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Porta ac consectetur ac<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Vestibulum at eros<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>

  <h2 id="list-group-badges">Badges</h2>
  <p>Add the badges component to any list group item and it will automatically be positioned on the right.</p>
  <div class="bs-example" data-example-id="list-group-badges">
    <ul class="list-group">
      <li class="list-group-item">
        <span class="badge">14</span>
        Cras justo odio
      </li>
      <li class="list-group-item">
        <span class="badge">2</span>
        Dapibus ac facilisis in
      </li>
      <li class="list-group-item">
        <span class="badge">1</span>
        Morbi leo risus
      </li>
    </ul>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"badge"</span><span class="nt">&gt;</span>14<span class="nt">&lt;/span&gt;</span>
    Cras justo odio
  <span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span></code></pre></div>

  <h2 id="list-group-linked">Linked items</h2>
  <p>Linkify list group items by using anchor tags instead of list items (that also means a parent <code>&lt;div&gt;</code> instead of an <code>&lt;ul&gt;</code>). No need for individual parents around each element.</p>
  <div class="bs-example" data-example-id="list-group-anchors">
    <div class="list-group">
      <a href="#" class="list-group-item active">
        Cras justo odio
      </a>
      <a href="#" class="list-group-item">Dapibus ac facilisis in</a>
      <a href="#" class="list-group-item">Morbi leo risus</a>
      <a href="#" class="list-group-item">Porta ac consectetur ac</a>
      <a href="#" class="list-group-item">Vestibulum at eros</a>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item active"</span><span class="nt">&gt;</span>
    Cras justo odio
  <span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Dapibus ac facilisis in<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Morbi leo risus<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Porta ac consectetur ac<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Vestibulum at eros<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="list-group-disabled">Disabled items</h2>
  <p>Add <code>.disabled</code> to a <code>.list-group-item</code> to gray it out to appear disabled.</p>
  <div class="bs-example" data-example-id="list-group-disabled">
    <div class="list-group">
      <a href="#" class="list-group-item disabled">
        Cras justo odio
      </a>
      <a href="#" class="list-group-item">Dapibus ac facilisis in</a>
      <a href="#" class="list-group-item">Morbi leo risus</a>
      <a href="#" class="list-group-item">Porta ac consectetur ac</a>
      <a href="#" class="list-group-item">Vestibulum at eros</a>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item disabled"</span><span class="nt">&gt;</span>
    Cras justo odio
  <span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Dapibus ac facilisis in<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Morbi leo risus<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Porta ac consectetur ac<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Vestibulum at eros<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="list-group-contextual-classes">Contextual classes</h2>
  <p>Use contextual classes to style list items, default or linked. Also includes <code>.active</code> state.</p>
  <div class="bs-example" data-example-id="list-group-variants">
    <div class="row">
      <div class="col-sm-6">
        <ul class="list-group">
          <li class="list-group-item list-group-item-success">Dapibus ac facilisis in</li>
          <li class="list-group-item list-group-item-info">Cras sit amet nibh libero</li>
          <li class="list-group-item list-group-item-warning">Porta ac consectetur ac</li>
          <li class="list-group-item list-group-item-danger">Vestibulum at eros</li>
        </ul>
      </div>
      <div class="col-sm-6">
        <div class="list-group">
          <a href="#" class="list-group-item list-group-item-success">Dapibus ac facilisis in</a>
          <a href="#" class="list-group-item list-group-item-info">Cras sit amet nibh libero</a>
          <a href="#" class="list-group-item list-group-item-warning">Porta ac consectetur ac</a>
          <a href="#" class="list-group-item list-group-item-danger">Vestibulum at eros</a>
        </div>
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-success"</span><span class="nt">&gt;</span>Dapibus ac facilisis in<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-info"</span><span class="nt">&gt;</span>Cras sit amet nibh libero<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-warning"</span><span class="nt">&gt;</span>Porta ac consectetur ac<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-danger"</span><span class="nt">&gt;</span>Vestibulum at eros<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-success"</span><span class="nt">&gt;</span>Dapibus ac facilisis in<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-info"</span><span class="nt">&gt;</span>Cras sit amet nibh libero<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-warning"</span><span class="nt">&gt;</span>Porta ac consectetur ac<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item list-group-item-danger"</span><span class="nt">&gt;</span>Vestibulum at eros<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="list-group-custom-content">Custom content</h2>
  <p>Add nearly any HTML within, even for linked list groups like the one below.</p>
  <div class="bs-example" data-example-id="list-group-custom-content">
    <div class="list-group">
      <a href="#" class="list-group-item active">
        <h4 class="list-group-item-heading">List group item heading</h4>
        <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
      </a>
      <a href="#" class="list-group-item">
        <h4 class="list-group-item-heading">List group item heading</h4>
        <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
      </a>
      <a href="#" class="list-group-item">
        <h4 class="list-group-item-heading">List group item heading</h4>
        <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>
      </a>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">class=</span><span class="s">"list-group-item active"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h4</span> <span class="na">class=</span><span class="s">"list-group-item-heading"</span><span class="nt">&gt;</span>List group item heading<span class="nt">&lt;/h4&gt;</span>
    <span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">"list-group-item-text"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="panels" class="page-header">Panels</h1>

  <p class="lead">While not always necessary, sometimes you need to put your DOM in a box. For those situations, try the panel component.</p>

  <h2 id="panels-basic">Basic example</h2>
  <p>By default, all the <code>.panel</code> does is apply some basic border and padding to contain some content.</p>
  <div class="bs-example" data-example-id="simple-panel">
    <div class="panel panel-default">
      <div class="panel-body">
        Basic panel example
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-body"</span><span class="nt">&gt;</span>
    Basic panel example
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="panels-heading">Panel with heading</h2>
  <p>Easily add a heading container to your panel with <code>.panel-heading</code>. You may also include any <code>&lt;h1&gt;</code>-<code>&lt;h6&gt;</code> with a <code>.panel-title</code> class to add a pre-styled heading.</p>
  <p>For proper link coloring, be sure to place links in headings within <code>.panel-title</code>.</p>
  <div class="bs-example" data-example-id="panel-with-heading">
    <div class="panel panel-default">
      <div class="panel-heading">Panel heading without title</div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-heading"</span><span class="nt">&gt;</span>Panel heading without title<span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-body"</span><span class="nt">&gt;</span>
    Panel content
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-heading"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;h3</span> <span class="na">class=</span><span class="s">"panel-title"</span><span class="nt">&gt;</span>Panel title<span class="nt">&lt;/h3&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-body"</span><span class="nt">&gt;</span>
    Panel content
  <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="panels-footer">Panel with footer</h2>
  <p>Wrap buttons or secondary text in <code>.panel-footer</code>. Note that panel footers <strong>do not</strong> inherit colors and borders when using contextual variations as they are not meant to be in the foreground.</p>
  <div class="bs-example" data-example-id="panel-with-footer">
    <div class="panel panel-default">
      <div class="panel-body">
        Panel content
      </div>
      <div class="panel-footer">Panel footer</div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-body"</span><span class="nt">&gt;</span>
    Panel content
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-footer"</span><span class="nt">&gt;</span>Panel footer<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="panels-alternatives">Contextual alternatives</h2>
  <p>Like other components, easily make a panel more meaningful to a particular context by adding any of the contextual state classes.</p>
  <div class="bs-example" data-example-id="contextual-panels">
    <div class="panel panel-primary">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-success">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-info">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-warning">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
    <div class="panel panel-danger">
      <div class="panel-heading">
        <h3 class="panel-title">Panel title</h3>
      </div>
      <div class="panel-body">
        Panel content
      </div>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-primary"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-success"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-info"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-warning"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-danger"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <h2 id="panels-tables">With tables</h2>
  <p>Add any non-bordered <code>.table</code> within a panel for a seamless design. If there is a <code>.panel-body</code>, we add an extra border to the top of the table for separation.</p>
  <div class="bs-example" data-example-id="table-within-panel">
    <div class="panel panel-default">
      <!-- Default panel contents -->
      <div class="panel-heading">Panel heading</div>
      <div class="panel-body">
        <p>Some default panel content here. Nulla vitae elit libero, a pharetra augue. Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
      </div>

      <!-- Table -->
      <table class="table">
        <thead>
          <tr>
            <th>#</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Username</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="c">&lt;!-- Default panel contents --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-heading"</span><span class="nt">&gt;</span>Panel heading<span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-body"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;p&gt;</span>...<span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;/div&gt;</span>

  <span class="c">&lt;!-- Table --&gt;</span>
  <span class="nt">&lt;table</span> <span class="na">class=</span><span class="s">"table"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <p>If there is no panel body, the component moves from panel header to table without interruption.</p>
  <div class="bs-example" data-example-id="panel-without-body-with-table">
    <div class="panel panel-default">
      <!-- Default panel contents -->
      <div class="panel-heading">Panel heading</div>

      <!-- Table -->
      <table class="table">
        <thead>
          <tr>
            <th>#</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Username</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="c">&lt;!-- Default panel contents --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-heading"</span><span class="nt">&gt;</span>Panel heading<span class="nt">&lt;/div&gt;</span>

  <span class="c">&lt;!-- Table --&gt;</span>
  <span class="nt">&lt;table</span> <span class="na">class=</span><span class="s">"table"</span><span class="nt">&gt;</span>
    ...
  <span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>


  <h2 id="panels-list-group">With list groups</h2>
  <p>Easily include full-width <a href="#list-group">list groups</a> within any panel.</p>
  <div class="bs-example" data-example-id="panel-with-list-group">
    <div class="panel panel-default">
      <!-- Default panel contents -->
      <div class="panel-heading">Panel heading</div>
      <div class="panel-body">
        <p>Some default panel content here. Nulla vitae elit libero, a pharetra augue. Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
      </div>

      <!-- List group -->
      <ul class="list-group">
        <li class="list-group-item">Cras justo odio</li>
        <li class="list-group-item">Dapibus ac facilisis in</li>
        <li class="list-group-item">Morbi leo risus</li>
        <li class="list-group-item">Porta ac consectetur ac</li>
        <li class="list-group-item">Vestibulum at eros</li>
      </ul>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel panel-default"</span><span class="nt">&gt;</span>
  <span class="c">&lt;!-- Default panel contents --&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-heading"</span><span class="nt">&gt;</span>Panel heading<span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"panel-body"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;p&gt;</span>...<span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;/div&gt;</span>

  <span class="c">&lt;!-- List group --&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"list-group"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Cras justo odio<span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Dapibus ac facilisis in<span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Morbi leo risus<span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Porta ac consectetur ac<span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"list-group-item"</span><span class="nt">&gt;</span>Vestibulum at eros<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="responsive-embed" class="page-header">Responsive embed</h1>

  <p>Allow browsers to determine video or slideshow dimensions based on the width of their containing block by creating an intrinsic ratio that will properly scale on any device.</p>
  <p>Rules are directly applied to <code>&lt;iframe&gt;</code>, <code>&lt;embed&gt;</code>, <code>&lt;video&gt;</code>, and <code>&lt;object&gt;</code> elements; optionally use an explicit descendant class <code>.embed-responsive-item</code> when you want to match the styling for other attributes.</p>
  <p><strong>Pro-Tip!</strong> You don't need to include <code>frameborder="0"</code> in your <code>&lt;iframe&gt;</code>s as we override that for you.</p>
  <div class="bs-example" data-example-id="responsive-embed-16by9-iframe-youtube">
    <div class="embed-responsive embed-responsive-16by9">
      <iframe class="embed-responsive-item" src="//www.youtube.com/embed/zpOULjyy-n8?rel=0" allowfullscreen></iframe>
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="c">&lt;!-- 16:9 aspect ratio --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"embed-responsive embed-responsive-16by9"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;iframe</span> <span class="na">class=</span><span class="s">"embed-responsive-item"</span> <span class="na">src=</span><span class="s">"..."</span><span class="nt">&gt;&lt;/iframe&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="c">&lt;!-- 4:3 aspect ratio --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"embed-responsive embed-responsive-4by3"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;iframe</span> <span class="na">class=</span><span class="s">"embed-responsive-item"</span> <span class="na">src=</span><span class="s">"..."</span><span class="nt">&gt;&lt;/iframe&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>

<div class="bs-docs-section">
  <h1 id="wells" class="page-header">Wells</h1>

  <h2>Default well</h2>
  <p>Use the well as a simple effect on an element to give it an inset effect.</p>
  <div class="bs-example" data-example-id="default-well">
    <div class="well">
      Look, I'm in a well!
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"well"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span></code></pre></div>
  <h2>Optional classes</h2>
  <p>Control padding and rounded corners with two optional modifier classes.</p>
  <div class="bs-example" data-example-id="large-well">
    <div class="well well-lg">
      Look, I'm in a large well!
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"well well-lg"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span></code></pre></div>

  <div class="bs-example" data-example-id="small-well">
    <div class="well well-sm">
      Look, I'm in a small well!
    </div>
  </div>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"well well-sm"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span></code></pre></div>
</div>


        </div>
        
        <div class="col-md-3" role="complementary">
          <nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm">
            <ul class="nav bs-docs-sidenav">
              
                <li>
  <a href="#glyphicons">Glyphicons</a>
  <ul class="nav">
    <li><a href="#glyphicons-glyphs">Available glyphs</a></li>
    <li><a href="#glyphicons-how-to-use">How to use</a></li>
    <li><a href="#glyphicons-examples">Examples</a></li>
  </ul>
</li>
<li>
  <a href="#dropdowns">Dropdowns</a>
  <ul class="nav">
    <li><a href="#dropdowns-example">Example</a></li>
    <li><a href="#dropdowns-alignment">Alignment</a></li>
    <li><a href="#dropdowns-headers">Headers</a></li>
    <li><a href="#dropdowns-divider">Divider</a></li>
    <li><a href="#dropdowns-disabled">Disabled menu items</a></li>
  </ul>
</li>
<li>
  <a href="#btn-groups">Button groups</a>
  <ul class="nav">
    <li><a href="#btn-groups-single">Basic example</a></li>
    <li><a href="#btn-groups-toolbar">Button toolbar</a></li>
    <li><a href="#btn-groups-sizing">Sizing</a></li>
    <li><a href="#btn-groups-nested">Nesting</a></li>
    <li><a href="#btn-groups-vertical">Vertical variation</a></li>
    <li><a href="#btn-groups-justified">Justified button groups</a></li>
  </ul>
</li>
<li>
  <a href="#btn-dropdowns">Button dropdowns</a>
  <ul class="nav">
    <li><a href="#btn-dropdowns-single">Single button dropdowns</a></li>
    <li><a href="#btn-dropdowns-split">Split button dropdowns</a></li>
    <li><a href="#btn-dropdowns-sizing">Sizing</a></li>
    <li><a href="#btn-dropdowns-dropup">Dropup variation</a></li>
  </ul>
</li>
<li>
  <a href="#input-groups">Input groups</a>
  <ul class="nav">
    <li><a href="#input-groups-basic">Basic example</a></li>
    <li><a href="#input-groups-sizing">Sizing</a></li>
    <li><a href="#input-groups-checkboxes-radios">Checkbox and radios addons</a></li>
    <li><a href="#input-groups-buttons">Button addons</a></li>
    <li><a href="#input-groups-buttons-dropdowns">Buttons with dropdowns</a></li>
    <li><a href="#input-groups-buttons-segmented">Segmented buttons</a></li>
  </ul>
</li>
<li>
  <a href="#nav">Navs</a>
  <ul class="nav">
    <li><a href="#nav-tabs">Tabs</a></li>
    <li><a href="#nav-pills">Pills</a></li>
    <li><a href="#nav-justified">Justified</a></li>
    <li><a href="#nav-disabled-links">Disabled links</a></li>
    <li><a href="#nav-dropdowns">Using dropdowns</a></li>
  </ul>
</li>
<li>
  <a href="#navbar">Navbar</a>
  <ul class="nav">
    <li><a href="#navbar-default">Default navbar</a></li>
    <li><a href="#navbar-brand-image">Brand image</a></li>
    <li><a href="#navbar-forms">Forms</a></li>
    <li><a href="#navbar-buttons">Buttons</a></li>
    <li><a href="#navbar-text">Text</a></li>
    <li><a href="#navbar-links">Non-nav links</a></li>
    <li><a href="#navbar-component-alignment">Component alignment</a></li>
    <li><a href="#navbar-fixed-top">Fixed to top</a></li>
    <li><a href="#navbar-fixed-bottom">Fixed to bottom</a></li>
    <li><a href="#navbar-static-top">Static top</a></li>
    <li><a href="#navbar-inverted">Inverted navbar</a></li>
  </ul>
</li>
<li><a href="#breadcrumbs">Breadcrumbs</a></li>
<li>
  <a href="#pagination">Pagination</a>
  <ul class="nav">
    <li><a href="#pagination-default">Default pagination</a></li>
    <li><a href="#pagination-pager">Pager</a></li>
  </ul>
</li>
<li><a href="#labels">Labels</a></li>
<li><a href="#badges">Badges</a></li>
<li><a href="#jumbotron">Jumbotron</a></li>
<li><a href="#page-header">Page header</a></li>
<li>
  <a href="#thumbnails">Thumbnails</a>
  <ul class="nav">
    <li><a href="#thumbnails-default">Default example</a></li>
    <li><a href="#thumbnails-custom-content">Custom content</a></li>
  </ul>
</li>
<li>
  <a href="#alerts">Alerts</a>
  <ul class="nav">
    <li><a href="#alerts-examples">Examples</a></li>
    <li><a href="#alerts-dismissible">Dismissible alerts</a></li>
    <li><a href="#alerts-links">Links in alerts</a></li>
  </ul>
</li>
<li>
  <a href="#progress">Progress bars</a>
  <ul class="nav">
    <li><a href="#progress-basic">Basic example</a></li>
    <li><a href="#progress-label">With label</a></li>
    <li><a href="#progress-alternatives">Contextual alternatives</a></li>
    <li><a href="#progress-striped">Striped</a></li>
    <li><a href="#progress-animated">Animated</a></li>
    <li><a href="#progress-stacked">Stacked</a></li>
  </ul>
</li>
<li>
  <a href="#media">Media object</a>
  <ul class="nav">
    <li><a href="#media-default">Default media</a></li>
    <li><a href="#media-list">Media list</a></li>
  </ul>
</li>
<li>
  <a href="#list-group">List group</a>
  <ul class="nav">
    <li><a href="#list-group-basic">Basic example</a></li>
    <li><a href="#list-group-badges">Badges</a></li>
    <li><a href="#list-group-linked">Linked items</a></li>
    <li><a href="#list-group-disabled">Disabled items</a></li>
    <li><a href="#list-group-contextual-classes">Contextual classes</a></li>
    <li><a href="#list-group-custom-content">Custom content</a></li>
  </ul>
</li>
<li>
  <a href="#panels">Panels</a>
  <ul class="nav">
    <li><a href="#panels-basic">Basic example</a></li>
    <li><a href="#panels-heading">Panel with heading</a></li>
    <li><a href="#panels-alternatives">Contextual alternatives</a></li>
    <li><a href="#panels-tables">With tables</a>
    <li><a href="#panels-list-group">With list groups</a>
  </ul>
</li>
<li><a href="#responsive-embed">Responsive embed</a></li>
<li><a href="#wells">Wells</a></li>

              
            </ul>
            <a class="back-to-top" href="#top">
              Back to top
            </a>
            
            <a href="#" class="bs-docs-theme-toggle" role="button">
              Preview theme
            </a>
            
          </nav>
        </div>
        
      </div>
    </div>

    <!-- Footer
================================================== -->
<footer class="bs-docs-footer" role="contentinfo">
  <div class="container">
    <div class="bs-docs-social">
  <ul class="bs-docs-social-buttons">
    <li>
      <iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=twbs&amp;repo=bootstrap&amp;type=watch&amp;count=true" width="100" height="20" title="Star on GitHub"></iframe>
    </li>
    <li>
      <iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=twbs&amp;repo=bootstrap&amp;type=fork&amp;count=true" width="102" height="20" title="Fork on GitHub"></iframe>
    </li>
    <li class="follow-btn">
      <a href="https://twitter.com/getbootstrap" class="twitter-follow-button" data-link-color="#0069D6" data-show-count="true">Follow @getbootstrap</a>
    </li>
    <li class="tweet-btn">
      <a href="https://twitter.com/share" class="twitter-share-button" data-url="http://getbootstrap.com/" data-count="horizontal" data-via="getbootstrap" data-related="mdo:Creator of Bootstrap">Tweet</a>
    </li>
  </ul>
</div>


    <p>Designed and built with all the love in the world by <a href="https://twitter.com/mdo" target="_blank">@mdo</a> and <a href="https://twitter.com/fat" target="_blank">@fat</a>.</p>
    <p>Maintained by the <a href="https://github.com/orgs/twbs/people">core team</a> with the help of <a href="https://github.com/twbs/bootstrap/graphs/contributors">our contributors</a>.</p>
    <p>Code licensed under <a rel="license" href="https://github.com/twbs/bootstrap/blob/master/LICENSE" target="_blank">MIT</a>, documentation under <a rel="license" href="https://creativecommons.org/licenses/by/3.0/" target="_blank">CC BY 3.0</a>.</p>
    <ul class="bs-docs-footer-links text-muted">
      <li>Currently v3.3.4</li>
      <li>&middot;</li>
      <li><a href="https://github.com/twbs/bootstrap">GitHub</a></li>
      <li>&middot;</li>
      <li><a href="../getting-started/#examples">Examples</a></li>
      <li>&middot;</li>
      <li><a href="../2.3.2/">v2.3.2 docs</a></li>
      <li>&middot;</li>
      <li><a href="../about/">About</a></li>
      <li>&middot;</li>
      <li><a href="http://expo.getbootstrap.com">Expo</a></li>
      <li>&middot;</li>
      <li><a href="http://blog.getbootstrap.com">Blog</a></li>
      <li>&middot;</li>
      <li><a href="https://github.com/twbs/bootstrap/issues">Issues</a></li>
      <li>&middot;</li>
      <li><a href="https://github.com/twbs/bootstrap/releases">Releases</a></li>
    </ul>
  </div>
</footer>

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>


  <script src="/bootstrap/dist/js/bootstrap.min.js"></script>



  <script src="../assets/js/docs.min.js"></script>




<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<script src="../assets/js/ie10-viewport-bug-workaround.js"></script>


<script>
  window.twttr = (function (d,s,id) {
    var t, js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return; js=d.createElement(s); js.id=id; js.async=1;
    js.src="https://platform.twitter.com/widgets.js"; fjs.parentNode.insertBefore(js, fjs);
    return window.twttr || (t = { _e: [], ready: function(f){ t._e.push(f) } });
  }(document, "script", "twitter-wjs"));
</script>

<!-- Analytics
================================================== -->
<script>
  var _gauges = _gauges || [];
  (function() {
    var t   = document.createElement('script');
    t.async = true;
    t.id    = 'gauges-tracker';
    t.setAttribute('data-site-id', '4f0dc9fef5a1f55508000013');
    t.src = '//secure.gaug.es/track.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(t, s);
  })();
</script>

  </body>
</html>

Changes to htdocs/index.tml.

100
101
102
103
104
105
106

107
108
109
110
111
112
113
<li><a href="guestbook/newguest.html">Update Guest Book</a>
<li><a HREF="include.shtml">Server includes</a> 
<li><a HREF="forms/">CGI</a>  You probably need to install the Standard Tcl Library for this.
<li><a HREF="map/">Imagemaps</a> 
<li><a HREF="/xyzzy">Sample missing page</a>
<li><a HREF="/debug/raise?message=This+page+raises+errors!">A page that raises an error</a>
<li><a HREF="images">A directory listing page</a>

</ul>

<!-- End Right Column -->
</td></tr>
<!-- End Two Column Format -->
</table>








>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<li><a href="guestbook/newguest.html">Update Guest Book</a>
<li><a HREF="include.shtml">Server includes</a> 
<li><a HREF="forms/">CGI</a>  You probably need to install the Standard Tcl Library for this.
<li><a HREF="map/">Imagemaps</a> 
<li><a HREF="/xyzzy">Sample missing page</a>
<li><a HREF="/debug/raise?message=This+page+raises+errors!">A page that raises an error</a>
<li><a HREF="images">A directory listing page</a>
<li><a HREF="bootdemo/">Bootstrap Demo</a>
</ul>

<!-- End Right Column -->
</td></tr>
<!-- End Two Column Format -->
</table>

Added htdocs/markdown.md.











































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# An exhibit of Markdown

This note demonstrates some of what [Markdown][1] is capable of doing.

*Note: Feel free to play with this page. Unlike regular notes, this doesn't automatically save itself.*

## Basic formatting

Paragraphs can be written like so. A paragraph is the basic block of Markdown. A paragraph is what text will turn into when there is no reason it should become anything else.

Paragraphs must be separated by a blank line. Basic formatting of *italics* and **bold** is supported. This *can be **nested** like* so.

## Lists

### Ordered list

1. Item 1
2. A second item
3. Number 3
4. â…£

*Note: the fourth item uses the Unicode character for [Roman numeral four][2].*

### Unordered list

* An item
* Another item
* Yet another item
* And there's more...

## Paragraph modifiers

### Code block

    Code blocks are very useful for developers and other people who look at code or other things that are written in plain text. As you can see, it uses a fixed-width font.

You can also make `inline code` to add code into other things.

### Quote

> Here is a quote. What this is should be self explanatory. Quotes are automatically indented when they are used.

## Headings

There are six levels of headings. They correspond with the six levels of HTML headings. You've probably noticed them already in the page. Each level down uses one more hash character.

### Headings *can* also contain **formatting**

### They can even contain `inline code`

Of course, demonstrating what headings look like messes up the structure of the page.

I don't recommend using more than three or four levels of headings here, because, when you're smallest heading isn't too small, and you're largest heading isn't too big, and you want each size up to look noticeably larger and more important, there there are only so many sizes that you can use.

## URLs

URLs can be made in a handful of ways:

* A named link to [MarkItDown][3]. The easiest way to do these is to select what you want to make a link and hit `Ctrl+L`.
* Another named link to [MarkItDown](http://www.markitdown.net/)
* Sometimes you just want a URL like <http://www.markitdown.net/>.

## Horizontal rule

A horizontal rule is a line that goes across the middle of the page.

---

It's sometimes handy for breaking things up.

## Images

Markdown can also contain images. I'll need to add something here sometime.

## Finally

There's actually a lot more to Markdown than this. See the official [introduction][4] and [syntax][5] for more information. However, be aware that this is not using the official implementation, and this might work subtly differently in some of the little things.


  [1]: http://daringfireball.net/projects/markdown/
  [2]: http://www.fileformat.info/info/unicode/char/2163/index.htm
  [3]: http://www.markitdown.net/
  [4]: http://daringfireball.net/projects/markdown/basics
  [5]: http://daringfireball.net/projects/markdown/syntax

Deleted lib/MakeIndex.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/tclsh

# First, auto-generate the standard direct-style package index

pkg_mkIndex -verbose -direct . *.tcl
return

file rename -force pkgIndex.tcl pkgIndex.tcl.direct
set in [open pkgIndex.tcl.direct r]
set out [open pkgIndex.tcl w]

# Now generate a new version that hides the sub-packages

puts $out [gets $in]
# Tcl package index file, version 1.1

puts $out "
# This file is generated by the MakeIndex script in the tclhttpd 
# lib directory.  The goal is to not pollute the package namespace
# until you package require httpd
"

# Skip the other comment block.  We know the line for
# httpd comes first.

while {[gets $in line] >= 0} {
    if {[regexp {package ifneeded httpd ([^ ]+)} $line x version]} {
	puts $out "package ifneeded httpd $version \""
	puts $out "\tsource \\\[file join \[list \$dir] httpd.tcl\\\]"
	break
    }
}

# Now reformat the other lines slightly to protect the
# list and file join commands, but let the $dir get expanded

while {[gets $in line] >= 0} {
    regsub -all {[][]} $line {\\&} line
    regsub -all {\$dir} $line {[list &]} line
    puts $out \t$line
}
puts $out "\""
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































Deleted lib/admin.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# URL-based administration

# Copyright
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: admin.tcl,v 1.9 2004/10/22 03:43:06 coldstore Exp $


package provide httpd::admin 1.0

package require httpd::auth	;# AuthVerifyBasic
package require httpd::counter	;# Count Counter_Reset
package require httpd::direct	;# DirectDomain Direct_Url
package require httpd::redirect	;# Redirect_Url
#package require httpd::utils	;# file

proc Admin_Url {dir} {
    Direct_Url $dir Admin
}

proc Admin/redirect {old new} {
    global Doc Httpd
    if {[string length $old] == 0} {
	return "<h1>Redirect URL</h1>\n\
		<form action=redirect method=post>\n\
		OLD: <input type=input name=old><br>\n\
		NEW: <input type=input name=new><br>\n\
		<input type=submit value=\"Redirect URL\"></form>"
    }
    if {[string length $new] == 0} {
	return "<h1>Redirect URL</h1>\n\
		<form action=redirect method=post>\n\
		<input type=hidden name=old value=$old>\n\
		OLD: $old<br>\n\
		NEW: <input type=input name=new><br>\n\
		<input type=submit value=\"Redirect URL\"></form>"
    }
    set server $Httpd(name)
    if {$Httpd(port) != 80} {
	append server :$Httpd(port)
    }
    if {![regexp ^http: $new]} {
	set new http://$server$new
    }

    ####
    # Need password protection for this page
    ####

    return "<h1>Redirect Form Disabled</h1>\n\
	   Redirect_Url $old http:$server$new"

    Redirect_Url $old $new
    if {[info exists Doc(notfound,$old)]} {
	unset Doc(notfound,$old)
    }
    return <h1>ok</h1>
}

proc Admin/reset/counter {name} {
    
if {0} {
    # Ugh - get the socket handle in the DirectDomain procedure
    upvar 1 sock sock
  
    # Need a way to register administrator passwords
    # For now we just allow this to happen.

    if {![AuthVerifyBasic $sock $admin(authfile)]} {
	return "Password Check Failed"
    }
}
    Counter_Reset $name
    return "Reset Counter $name"
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































Deleted lib/auth.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# auth.tcl
#
# Basic authentication
# This module parses .htaccess files and does the Basic Authentication
# protocol.  There is some generality in here to support multiple
# authentication schemes, but in practice only Basic is used right now.
#
# Each .htaccess file is parsed once and the information is kept in a
# Tcl global array named auth$filename, and upvar aliases this to "info".
# "info" contains the info provided by the .htaccess file ( info(htaccessp,..) )
#
# The AuthUserFile and the AuthGroupFile are parsed and stored
# in authentication array auth$filename.
#
# Authentication arrays need not be associated with physical files.
# To create an authentication array:
#	array set auth$pseudo [list mtime 0 user,$u password group,$g group]
#
# Configuration creates an authentication array authdefault, for bootstrapping.
#
# There is also support for ".tclaccess" files in each directory.
# These contain hook code that define password checking procedures
# that apply at that point in the hierarchy.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# Piet Vloet (c) 2001
# Brent Welch (c) 2001
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: auth.tcl,v 1.25 2006/11/09 23:41:41 coldstore Exp $

package provide httpd::auth 2.0

package require base64

package require httpd	;# Httpd_Error Httpd_RequestAuth
package require httpd::config	;# Config
package require httpd::digest	;# Digest_Passwd
package require httpd::log	;# Log
package require httpd::passgen	;# Passgen_Generate Passgen_Salt
package require httpd::utils	;# K Stderr file
package require tclcrypt	;# crypt

set Auth_DigestOnly 0;	# set this to 1 to only use Digest auth

# Crypto packages
if {[catch {package require crypt}] || [catch {crypt foo ba}]} {
    # if we don't have a C library, fall back to pure tcl crypt
    package require tclcrypt
}

# set default user/group files
if {![info exists Config(AuthUserFile)]} {
    set Config(AuthUserFile) default
}
if {![info exists Config(AuthGroupFile)]} {
    set Config(AuthGroupFile) default
}

# Authentication bootstrap.
#
# The /htaccess URL allows admins to create passwords and groups,
# and .htaccess files per directory, however it is necessary to have a
# password to bootstrap this process.
#
# The approach taken is to allow the administrator to give plaintext
# passwords via Config, or (failing that) to generate and Log a random
# password at runtime.  A new random password will be created on each 
# server startup.
#
# Here, we create a default authentication array from Config(Auth)

array set authdefault {mtime -1}
package require httpd::passgen	;# random password generation

# Auth_InitCrypt --
# Attempt to turn on the crypt feature used to store crypted passwords.

proc Auth_InitCrypt {} {
    global authdefault
    global Config

    if {[info exists Config(Auth)]} {
	foreach {var val} $Config(Auth) {
	    if {[string match user,* $var]} {
		# encrypt the password
		set salt [Passgen_Salt]
		set val [crypt $val $salt]
	    }
	    set authdefault($var) $val
	}
    } else {
	# we weren't given an Auth Config - generate a default for webmaster
	# and write it to Stderr
	
	set webmaster_password [Passgen_Generate]
	set salt [Passgen_Salt]
	set authdefault(user,webmaster) [crypt $webmaster_password $salt]
	set authdefault(group,webmaster) webmaster
	set authdefault(user,webmaster@webmaster) [Digest_Passwd webmaster webmaster $webmaster_password]
	# This lets the admin see this important password during startup.
        # It is also displayed by the Tk srvui interface.
	Stderr "User \"webmaster\" default password \"$webmaster_password\""
    }
}

proc Auth_AccessFile {args} {
    Stderr "Auth_AccessFile is obsolete: use Auth_InitCrypt instead"
    Auth_InitCrypt
}

# Auth_Check --
# This looks for access files along the path.
# It returns a "cookie" that is checked by Auth_Verify.
# NOTE: this looks for the lowest (i.e., deepest) access file
# and only returns information about one. Consider changing
# Auth_Check/Auth_Verify to check all files.

proc Auth_Check {sock directory pathlist} {
    global auth
    set cookie {}

    # Make sure we do checks in the root
    if {$pathlist==""} {
	 set pathlist ./
    }

    # Look for the .htaccess files that keep Basic Authtication info
    # or .tclaccess files with a general authorization callback
    set path $directory
    foreach component $pathlist {
        if {![file isdirectory $path]} {
            # Don't bother looking if we are in an "artificial"
            # url domain that isn't mapped to files.
            break
        }
	foreach {name type} {.htaccess Basic .tclaccess Tcl} {
	    set file [file join $path $name]
	    if {[file exists $file]} {
		set cookie [list $type $file]
		# Keep looking for cookie files lower in the directory tree
            }
	}
	set path [file join $path $component]
    }

    # Block access to the access control files themselves.
    # We toss in a block against the .tml files as well,
    # although that isn't strictly clean modularity.
    set tail [file tail $path]
    if {$tail == ".tclaccess" ||
          $tail == ".htaccess" ||
          $tail == ".tml"} {
        set cookie [list Deny $path]
        return $cookie
    }

    return $cookie
}

proc Auth_Verify {sock cookie} {
    if {[llength $cookie] == 0} {
	return 1
    }
    set type [lindex $cookie 0]
    set key [lindex $cookie 1]
    if {$type == "Deny"} {
        return 0
    } else {
        return [AuthVerify$type $sock $key]
    }
}

# Auth_VerifyCallback -- 
#
#       Check for a Basic authorization string, and use a callback
#       to verify the password
#
# Arguments:
#       sock            Handle on the client connection
#       realm           Realm for basic authentication.  This appears
#                       in the password prompt from the browser.
#       callback        Tcl command to check the password.  This gets
#                       as arguments the sock, realm, username and password.
#
# Results:
#                       return 1 or 0, 1 for success.

proc Auth_VerifyCallback {sock realm callback} {
    upvar #0 Httpd$sock data

    if {![info exists data(mime,authorization)]} {
	set ok 0
    } else {
	set parts [split $data(mime,authorization)]
	set type [lindex $parts 0]
	set code [lindex $parts 1]
	if {[string compare $type Basic] != 0} {
	    set user {}
	    set pass {}
	} else {
	    set parts [split [base64::decode $code] :]
	    set user [lindex $parts 0]
	    set pass [lindex $parts 1]
	}
	set ok [eval $callback {$sock $realm $user $pass}]
    }
    if {!$ok} {
	Httpd_RequestAuth $sock Basic $realm
	return 0
    } else {
	set data(auth_type) Basic
	set data(remote_user) $user
	set data(session) $realm,$user
	return 1
    }
}

# AuthVerifyTcl --
#
#       "Tcl" verification uses a .tclaccess file that defines the
#       realm and callback to use to check the password.
#
# Arguments:
#       sock    Handle on the client connection
#       file    Tcl source file that contains set commands for
#               realm and callback
#
# Results:
#       1 for success, 0 for access denied.

proc AuthVerifyTcl {sock file} {
    upvar #0 Httpd$sock data


    # The file contains definitions for the "realm" variable
    # and the "callback" script value.

    set realm Realm
    set callback AuthNullCallback
    catch {source $file}

    return [Auth_VerifyCallback $sock $realm $callback]
}

proc AuthNullCallback {sock realm user pass} {
    upvar #0 Httpd$sock data
    global auth
    if {[info exists auth($realm,$user)]} {
	switch -exact -- $auth($realm,$user) \
	    $pass {
		Stderr "Session: $realm,$user"
		return 1
	    } \
	    PasswordRequired {
		set auth($realm,$user) $pass
		Stderr "Session: $realm,$user"
		return 1
	    } \
	    default {
		return 0
	    }
    } else {
	set auth($realm,$user) PasswordRequired
	return 0
    }
}

# AuthUserOp - see if the user is permitted to perform a requested
# operation (PUT, GET, etc)
# The .htaccess file is searched for the user or a group containing
# the user, to ascertain whether the user could possibly perform
# the op before the proffered credentials are checked.

proc AuthUserOp {sock file op user} {
    upvar #0 auth$file info
    upvar #0 Httpd$sock data

    if {[info exists info(htaccessp,require,$op,group)]} {
	if {![AuthGroupCheck $sock $file \
		  $info(htaccessp,require,$op,group) $user]} {
	    return 0   ;# Not in a required group
	}
    }
    if {[info exists info(htaccessp,require,$op,user)]} {
	if {![AuthUserCheck $sock $file \
		  $info(htaccessp,require,$op,user) $user]} { 
	    return 0   ;# Not the required user
	}
    }
    return 1
}

# AuthVerifyBasic - see if the user is granted access.
# First domain based protection is performed. In the case the
# user is not in the domain user based protection is performed.
# The user must be in a group or mentioned as user. The password
# must match the user's entry.  If neither group nor user are
# required for the operation, then the check passes.

proc AuthVerifyBasic {sock file} {
    upvar #0 auth$file info
    upvar #0 Httpd$sock data

    set user ""

    AuthParseHtaccess $sock $file
    set op $data(proto) ;# GET, POST etc.
    set realm $info(htaccessp,name)

    # check whether the operation is controlled
    if {[info exists info(htaccessp,order,$op)]} {
	if {! [AuthVerifyNet $sock $file $op]} {
	    # it is controlled and network address is excluded
	    Httpd_Error $sock 403
	    return 0
	}
    }
    if {![info exists info(htaccessp,require,$op,group)] &&
	    ![info exists info(htaccessp,require,$op,user)]} {
	# No "require group .." or "require user .." in .htaccess file
	return 1
    }

    set ok 0

    # the operation requires a user or group - check authorization
    if {[info exists data(mime,authorization)]} {
	# client has sent auth data
	set parts [split $data(mime,authorization)]
	set type [lindex $parts 0]

	switch -- [string tolower $type] {
	    digest {
		# unpack the digest request
		Digest_Get $sock $parts

		# check that the proferred user can have access
		set user $data(digest,username)
		set ok [AuthUserOp $sock $file $op $user]

		if {$ok} {
		    # now check the Digest credentials
		    set ok [Digest_Request $sock $realm $file]
		}
	    }
	    basic {
		set code [lindex $parts 1]
		set parts [split [base64::decode $code] :]

		# check that the proferred user can have access
		set user [lindex $parts 0]
		set ok [AuthUserOp $sock $file $op $user]

		if {$ok} {
		    # now check the Basic credentials
		    set pass [lindex $parts 1]
		    set crypt [AuthGetPass $sock $file $user]
		    set salt [string range $crypt 0 1]
		    set crypt2 [crypt $pass $salt]
		    if {[string compare $crypt $crypt2] != 0} {
			set ok 0        ;# Not the right password
		    }
		}
	    }
	    default {
		# this is an unknown auth method - it's not ok, we can't handle it
		set ok 0
	    }
	}
    }

    if {! $ok} {
	# client hasn't sent auth or auth doesn't satisfy
	global Auth_DigestOnly
	if {!$Auth_DigestOnly && ($info(htaccessp,type) == "Basic")} {
	    Httpd_RequestAuth $sock Basic $realm
	} else {
	    # make Digest the default
	    Digest_Challenge $sock $realm $user
	}
    } else {
	# client is permitted and credentials check out
	set data(auth_type) $type
	set data(remote_user) $user
	set data(session) $realm,$user
    }

    return $ok
}

proc AuthUserCheck  {sock file users user } {
    return [expr {[lsearch $users $user] >= 0}]
}

# Parse the AuthGroupFile and find the user in it.
# The information is built up in the array:
#	auth$info(htaccessp,groupfile)
#
# To create an authentication array, unconnected to a physical file:
# array set auth$pseudo [list mtime 0 user,$u password group,$g group]
#
# If the .htaccess file didn't specify a groupfile, it defaults to an authentication
# array authdefault, which contains configured default passwords and groups

proc AuthGroupCheck {sock file groups user} {
    upvar #0 auth$file info
    upvar #0 auth$info(htaccessp,groupfile) group

    if {[catch {file mtime $info(htaccessp,groupfile)} mtime]} {
	set mtime -1	;# the file may not exist
    }

    # Only parse the group file if it has changed
    if {![info exists group(mtime)] || ($mtime > $group(mtime))} {
	catch {unset group(mtime)}	;# unset to catch errors
	foreach i [array names group "group*"] {
	    unset group($i)
	}
	if {[catch {open $info(htaccessp,groupfile)} in]} {
	    return 0
	}
	while {[gets $in line] >= 0} {
	    if {[regexp {^([^:]+):[      ]*(.+)} $line x key value]} {
		set group(group,$key) [split $value " ,"]
	    }
	}
	close $in
	set group(mtime) $mtime
    }

    foreach index $groups {
	if {[info exist group(group,$index)]} {
	    if {[lsearch $group(group,$index) $user] >= 0} {
		return 1
	    }
	}
    }
    return 0
}

# Parse the AuthUserFile and return the user's information.
# The information is built up in the array:
#	auth$info(htaccessp,userfile)
# 
# To create an authentication array, unconnected to a physical file:
# array set auth$pseudo [list mtime 0 user,$u password group,$g group]
#
# If the .htaccess file didn't specify a userfile, it defaults to an authentication
# array authdefault, which contains configured default passwords and groups

proc AuthGetPass {sock file user} {
    upvar #0 auth$file info
    upvar #0 auth$info(htaccessp,userfile) passwd

    if {[catch {file mtime $info(htaccessp,userfile)} mtime]} {
	set mtime -1	;# the file may not exist
    }

    if {![info exists passwd(mtime)] || ($mtime > $passwd(mtime))} {
	catch {unset passwd(mtime)}	;# unset to catch errors
	foreach i [array names passwd "user*"] {
	    unset passwd($i)
	}
	if {[catch {open $info(htaccessp,userfile)} in]} {
	    return *
	}
	while {[gets $in line] >= 0} {
	    if {[regexp {^([^:]+):[      ]*([^:]+)} $line x key value]} {
		set passwd(user,$key) $value
	    }
	}
	close $in
	set passwd(mtime) $mtime
    }
    if {[info exists passwd(user,$user)]} {
	return $passwd(user,$user)
    } else {
	return *
    }
}

# Check the allow/deny lists for this operation

proc AuthVerifyNet {sock file op} {
    upvar #0 auth$file info
    set order [split $info(htaccessp,order,$op) ,]
    set peer [fconfigure $sock -peername]
    set rname [string tolower [lindex $peer 1]]
    set raddr [lindex $peer 0]
    set ok 0
    foreach way $order {
	if {![info exists info(htaccessp,network,$way,$op)]} {
	    continue
	}
	foreach addr $info(htaccessp,network,$way,$op) {
	    if {[AuthNetMatch $sock $addr $rname $raddr]} {
		if {[string compare $way "allow"] == 0} {
		    set ok 1
		} else {
		    set ok 0
		}
	    }
	}
    }
    if {! $ok} {
	Log $sock AuthVerifyNet "access denied to $rname in [file tail [file dirname $file]]"
    }
    return $ok
}

proc AuthNetMatch {sock addr rname raddr} {
    if {[string compare $addr "all"] == 0} {
	return 1
    }
    if {[string match *$addr $rname] || [string match ${addr}* $raddr]} {
	return 1
    }
    return 0
}

# Parse the htaccess file.  Uhler would probably regsub/subst this,
# but here we just call a Tcl proc to handle each "command" in the file.
# The information is built up in the info array.

proc AuthParseHtaccess {sock file} {
    upvar #0 auth$file info
    set mtime [file mtime $file]
    if {![info exists info] || ($mtime > $info(htaccessp,mtime))} {
	# Parse .htaccess file
	foreach i [array names info "htaccessp*"] {
	    unset info($i)
	}
	set info(htaccessp,mtime) $mtime

	global Config
	set info(htaccessp,userfile) $Config(AuthUserFile)
	set info(htaccessp,groupfile) $Config(AuthGroupFile)

	set info(htaccessp,name) Digest
	if {[catch {open $file} in]} {
	    return 1
	}
	set state [list vars]
	foreach line [split [read $in] \n] {
	    if {[regexp ^# $line] || [string length [string trim $line]] == 0} {
		continue
	    }
	    if {[regexp <(.+)> $line x tag]} {
		set line $tag
	    }
	    set words [split $line]
	    set cmd [string tolower [lindex $words 0]]
	    if {[catch {
		eval {Ht-$cmd auth$file} [lrange $words 1 end]
	    } err]} {
		Log $sock Error $err
	    }
	}
	close $in
    }
    return 1
}
proc Ht-authtype {infoName type} {
    upvar #0 $infoName info
    set info(htaccessp,type) $type
}
proc Ht-authname {infoName name} {
    upvar #0 $infoName info
    set info(htaccessp,name) $name
}

proc Ht-authuserfile {infoName file} {
    upvar #0 $infoName info
    set info(htaccessp,userfile) $file
}

proc Ht-authgroupfile {infoName file} {
    upvar #0 $infoName info
    set info(htaccessp,groupfile) $file
}

proc Ht-limit {infoName args} {
    upvar #0 $infoName info
    set info(htaccessp,limit) $args       ;# List of operations, GET, POST, ...
}

proc Ht-/limit {infoName args} {
    upvar #0 $infoName info
    set info(htaccessp,limit) {}
}

proc Ht-require {infoName key list} {
    upvar #0 $infoName info
    if {![info exists info(htaccessp,limit)]} {
	set info(htaccessp,limit) {}
    }
    foreach op $info(htaccessp,limit) {
	if {![info exists info(htaccessp,require,$op,$key)]} {
		set info(htaccessp,require,$op,$key) {}
	    }
	    foreach a $list {
		lappend info(htaccessp,require,$op,$key) $a
	    }
     }
}

proc Ht-order {infoName value} {
    upvar #0 $infoName info
    if {![info exists info(htaccessp,limit)]} {
	set info(htaccessp,limit) {}
    }
    foreach op $info(htaccessp,limit) {
	if {[info exists info(htaccessp,order,$op)]} {
		 unset info(htaccessp,order,$op)
	}
	set info(htaccessp,order,$op) $value
    }
}

proc Ht-deny {infoName args} {
    HtByNet $infoName deny $args
}
proc Ht-allow {infoName args} {
    HtByNet $infoName allow $args
}
proc HtByNet {infoName how list} {
    upvar #0 $infoName info
    if {![info exists info(htaccessp,limit)]} {
	set info(htaccessp,limit) {}
    }
    if {[string compare [lindex $list 0] "from"] == 0} {
	set list [lrange $list 1 end]
    }
    foreach op $info(htaccessp,limit) {
	if {![info exists info(htaccessp,network,$how,$op)]} {
	    set info(htaccessp,network,$how,$op) {}
	}
	foreach a $list {
	    lappend info(htaccessp,network,$how,$op) [string tolower $a]
	}
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/cgi.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
# cgi.tcl
# CGI support
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: cgi.tcl,v 1.31 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::cgi 1.1

package require httpd	;# Httpd_Date Httpd_Error Httpd_Port Httpd_SelfUrl Httpd_SockClose
package require httpd::counter	;# Count
package require httpd::doc	;# DocAccessHook Doc_RegisterRoot Doc_Root Doc_Virtual
package require httpd::doc_error	;# Doc_NotFound
package require httpd::log	;# Log
package require httpd::threadmgr	;# Thread_Id Thread_Send Thread_SendAsync
package require httpd::url	;# Url_Dispatch Url_Handle Url_PathCheck Url_PrefixInstall
#package require httpd::utils	;# file

# Cgi parameters
# timeout	Seconds before pipe to CGI program is closed
# maxcgi	Number of concurrent requests allowed
# cgi		Running total of cgi requests
# ident		If true, try to use the ident protocol
# env-pass	List of environment variables to preserve when setting
#		up the environment.  The rest are deleted and then recreated
#		from information in the CGI request.
# tclsh		Pathname to a Tcl interpreter.  If you preserve the env(PATH)
#		by listing PATH in env-pass, this can be "tclsh80.exe"
#		or "protclsh80.exe".  Otherwise it has to be an absolute path.

array set Cgi {
    timeout	300000
    maxcgi	100
    cgi		0
    ident	0
    env-pass	{PATH LD_LIBRARY_PATH TZ}
}
if {"$tcl_platform(platform)" == "windows"} {

    # On windows we hard-code the interpreters for various script types

    regsub -nocase wish [info nameofexecutable] tclsh Cgi(tclsh) ;# For .tcl
    set Cgi(perl) "perl.exe"			;# For .pl
    set Cgi(cgiexe) $Cgi(tclsh)			;# For .cgi

    # More environment variables need to be passed through.
    # Windows NT Need Lib and SystemRoot so DLLs loaded by tcl are found.
    # Windows 95 needs more... so we just pass everything

    lappend Cgi(env-pass) * 
}

# Register a cgi-bin directory.
# This causes the server to pay attention to the extra path information
# after the program name.

proc Cgi_Directory {virtual {directory {}}} {

    # Set up the URL-directory mapping so that DocAccessHook works right.

    if {[string length $directory] == 0} {
	set directory [Doc_Virtual {} {} $virtual]
    }
    Doc_RegisterRoot $virtual $directory

    # Register the domain - not in a thread becaused we'll use another process anyway.
    # The CGI module will also read the post data itself so TclHttpd doesn't buffer
    # it all in memory before passing it to the CGI process.

    Url_PrefixInstall $virtual [list Cgi_Domain $virtual $directory] \
	-thread 0 -readpost 0
}

# Cgi_Domain is called from Url_Dispatch for URLs inside cgi-bin directories.

proc Cgi_Domain {virtual directory sock suffix} {
    global Cgi env

    # Check the path and then find the part beyond the program name.
    # The trimleft avoids a buildup of extra / after the domain prefix.

    if {[catch {Url_PathCheck [string trimleft $suffix /]} pathlist]} {
	Doc_NotFound $sock
	return
    }

    # url is the logical name as viewed by a browser
    # path is a physical file system name as viewd by the server

    set url [string trimright $virtual /]
    set path $directory
    set i 0
    foreach component $pathlist {
	incr i
	set path [file join $path $component]
	append url /$component
	if {[file isfile $path]} {
#	    if {[file executable $path]} {
		# Don't bother testing execute permission here,
		# because it doens't test right on windows anyway.
		set extra [lrange $pathlist $i end]
#	    }
	    break
	} elseif {![file exists $path]} { 
	    Doc_NotFound $sock
	    return
	}
    }
    if {![info exists extra]} {
	# Didn't find an executable file
	Httpd_Error $sock 403
	return
    } elseif {[llength $extra]} {
	set extra /[join $extra /]
    }

    # The CGI needs the server-relative url of the script,
    # the extra part after the program name,
    # and the translated version of the whole pathname.

    Url_Handle [list CgiHandle $url $extra $path] $sock
}

proc CgiHandle {url extra path sock} {
    global Doc env
    Cgi_SetEnvAll $sock $path $extra $url env
    CgiSpawn $sock $path
}

# This gets called if there is no extra pathname after
# the name of a cgi script, and the Doc module finds a .cgi file

proc Doc_application/x-cgi {path suffix sock} {
    upvar #0 Httpd$sock data
    Url_Handle [list CgiHandle $data(url) {} $path] $sock
}

# Set the environment for the cgi scripts.  This is passed implicitly to
# the cgi script during the "open" call.

proc Cgi_SetEnv {sock path {var env}} {
    upvar 1 $var env
    upvar #0 Httpd$sock data
    Cgi_SetEnvAll $sock $path {} $data(url) env
}

proc Cgi_SetEnvInterp {sock path interp} {
    upvar #0 Httpd$sock data
    Cgi_SetEnvAll $sock $path {} $data(url) env
    interp eval $interp [list uplevel #0 \
	[list array set env [array get env]]]
}

proc Cgi_SetEnvAll {sock path extra url var} {
    upvar #0 Httpd$sock data
    upvar 1 $var env
    global Httpd Httpd_EnvMap Cgi

    # we can't "unset env" or it won't get passed to the CGI script
    foreach i [array names env] {
	set clear 1
	foreach x $Cgi(env-pass) {
	    if {[string match $x $i]} {
		# Preserve some path settings
		set clear 0
		break
	    }
	}
	if {$clear} {
	    unset env($i)
	}
    }
    foreach name [array names Httpd_EnvMap] {
	set env($name) ""
	catch {
	    set env($name) $data($Httpd_EnvMap($name))
	}
    }
    set env(REQUEST_URI) [Httpd_SelfUrl $data(uri) $sock]
    set env(GATEWAY_INTERFACE) "CGI/1.1"
    set env(SERVER_PORT) [Httpd_Port $sock]
    if {[info exist Httpd(https_port)]} {
	set env(SERVER_HTTPS_PORT) $Httpd(https_port)
    }
    set env(SERVER_NAME) $Httpd(name)
    set env(SERVER_SOFTWARE) $Httpd(server)
    set env(SERVER_PROTOCOL) HTTP/1.0
    set env(REMOTE_ADDR) $data(ipaddr)
    set env(SCRIPT_NAME) $url
    set env(PATH_INFO) $extra
    set env(PATH_TRANSLATED) [string trimright [Doc_Root] /]/[string trimleft $data(url) /]
    set env(DOCUMENT_ROOT) [Doc_Root]
    set env(HOME) [Doc_Root]

    if {$Cgi(ident)} {
	catch {
	    set ident [::ident::get $sock]
	    set env(REMOTE_IDENT) [lindex $ident 0]
	}
    }

    if {$data(proto) == "POST"} {
	set env(QUERY_STRING) ""
    }
}

# Enable/disable IDENT lookup.  Disabled by default.

proc Cgi_Ident state {
    global Cgi

    regsub {^(1|yes|true|on)$} $state 1 state
    regsub {^(0|no|false|off)$} $state 0 state

    if {$state} {
	package require ident
    }

    set Cgi(ident) $state
}

# Run a cgi script:
# Our caller needs to set up the environment with Cgi_SetEnv.
# Run the script, and copy the
# output to the socket. 
# Set a timer to deal with invalid scripts.

proc CgiSpawn {sock script} {
    upvar #0 Httpd$sock data
    global env Cgi

    if {$Cgi(cgi) >= $Cgi(maxcgi)} {
	Httpd_Error $sock 504  "Too many CGI's"
	return
    }
    incr Cgi(cgi)

    # for GET queries, pass the query as an argument to the cgi script
    if {$data(proto) == "POST"} {
	set arglist ""
    } else {
	set arglist $data(query)
    }
    set pwd [pwd]
    cd [file dirname $script]
    if {[catch {CgiExec $script $arglist} fd]} {
	cd $pwd
	Httpd_Error $sock 400 $fd
	incr Cgi(cgi) -1
	return
    }
    cd $pwd
    Count cgihits
    set data(infile) $fd	;# So close happens in Httpd_SockClose
    set data(header) 0		;# Have not read header yet
    set data(headerlist) {}	;# list of read headers
    set data(headercode) "200 data follows"	;# normal return
    fconfigure $fd -blocking 0

    # Set up a timer in case it hangs

    catch {after cancel $data(cancel)}
    set data(cancel) [after $Cgi(timeout) CgiCancel $fd $sock]

    if {$data(proto) == "POST"} {

        # Read the pipe in auto mode to properly detect the end of
        # headers in Unix and Windows.  Pump the POST data in
        # binary mode.

	fconfigure $fd -translation {auto binary}

	if {$data(count) == 0} {

	    # Either there was no POST data, or we are inside a domain
	    # that automatically read the POST data into data(query) already
	    # Errors appear here because of the non-blocking writes.

	    catch {
		puts -nonewline $fd $data(query)
		flush $fd
	    }
	} else {

	    # Pump the query data to the CGI process in the background
	    # We set up fileevents after this finishes, so return now

	    # fcopy bug in Tcl 8.3.2 and Tcl 8.4a2 and all previous versions 
	    # prevents this from working reliably on large amounts of POST data
	    # fcopy $sock $fd -command [list CgiCopyDone $sock $fd] -size $data(count)
	    fileevent $sock readable [list CgiCopyPost $sock $fd]
	    return
	}
    }

    CgiCopyDone $sock $fd $data(count) ""
}

# CgiCopyPost --
#
#	Called to copy POST data down the pipe - need to avoid fcopy bug

proc CgiCopyPost {sock fd} {
    upvar #0 Httpd$sock data
    global tcl_version

    set buf [read $sock $data(count)]
    puts -nonewline $fd $buf
    if {$tcl_version <= 8.0} {
	set len [string length $buf]
    } else {
	# Ensure we get byte count, not I18N character count
	set len [string bytelength $buf]
    }
    set data(count) [expr {$data(count) - $len}]
    if {$data(count) <= 0} {
	flush $fd
	CgiCopyDone $sock $fd dummy ""
    }
}

# CgiCopyDone --
#
#	Called when we have finished copying POST data to the CGI process

proc CgiCopyDone {sock fd bytes {errmsg {}}} {
    upvar #0 Httpd$sock data

    # Reset this otherwise the Httpd module tries to read the
    # extra data

    set data(count) 0

    if {[string length $errmsg]} {
	CgiCancel
    } else {
	# Wait for output from the CGI process (CgiRead)
	# Watch the socket (CgiCleanup)
	# In a worker thread, this is not really a socket, hence the catch.

	catch {fileevent $sock readable [list CgiCleanup $fd $sock]}
	fileevent $fd readable [list CgiRead $fd $sock]
    }
}

# Execute the CGI process.

proc CgiExec {script arglist} {
    global tcl_platform
    global Cgi
    switch -- $tcl_platform(platform) {
	unix {
	    if {[file exists /dev/stdout]} {

		# This trick "2> /dev/stdout" fails if you start the process in
		# the background under an xterm, then quit the xterm.  In that case
		# the open raises an error.

		if { ! [catch {open "|[list $script] $arglist 2> /dev/stdout" r+} pipe]} {
		    return $pipe
		}
	    }

	    # We use cat to merge the stderr and stdout

	    return [open "|[list $script] $arglist |& cat" r+]
	}
	windows {
	    switch -- [file extension $script] {
		.pl {
		    return [open "|[list $Cgi(perl) $script] $arglist" r+]
		}
		.cgi {
		    return [open "|[list $Cgi(cgiexe) $script] $arglist" r+]
		}
		.tcl {
		    return [open "|[list $Cgi(tclsh) $script] $arglist" r+]
		}
		.exe {
		    return [open "|[list $script] $arglist" r+]
		}
		default {
		    error "Don't know how to execute CGI $script"
		}
	    }
	}
	macintosh {
	    error "CGI not supported on Macintosh"
	}
    }
}

# Read data from the CGI script, write to client.

proc CgiRead {fd sock} {
    upvar #0 Httpd$sock data
    global Cgi Httpd

    if {[eof $fd]} {
	CgiClose $fd $sock
    } elseif {[catch {
	if {!$data(header)} {

	    # Read and accumulate headers until we know what kind
	    # of response to make

	    set n [gets $fd line]
	    if {$n < 0} {
		# Blocked or EOF - do nothing.
		# EOF will be caught on next fileevent.
		# Blocked means we have a partial line, just wait.
	    } elseif {$n == 0} {
		set data(header) 1
		append header "HTTP/1.0 $data(headercode)\n"
		append header "Server: $Httpd(server)\n"
		append header "Date: [Httpd_Date [clock seconds]]\n"
		append header "Connection: Close\n"
		foreach line $data(headerlist) {
		    append header $line\n
		}
		append header "\n"
		CgiPutHeader $sock $header
	    } else {
		lappend data(headerlist) $line
		if {[regexp -nocase ^(location|uri): $line]} {
		    set data(headercode) "302 found"
		}
	    }
	} else {

	    CgiCopy $fd $sock
	}
    } oops]} {
	# Socket may have gone away
	CgiCancel $fd $sock
    }
}

# Emit the header, handling the case where we are in a worker thread.

proc CgiPutHeader {sock header} {
    upvar #0 Httpd$sock data
    if {[info exist data(master_thread)] &&
            $data(master_thread) != [Thread_Id]} {

        Thread_Send $data(master_thread) \
            [list CgiCopyDirect $sock $header]
        Thread_Send $data(master_thread) \
            [list fconfigure $sock -translation binary]
    } else {
        puts -nonewline $sock $header
    }

}

# Copy data from the pipe to the socket

proc CgiCopy {fd sock} {
    upvar #0 Httpd$sock data
    global Httpd

    fconfigure $fd -translation binary
    if {[info exist data(master_thread)] &&
            $data(master_thread) != [Thread_Id]} {
        # Read the data and copy it to the main thread for return.
        # Quick and dirty until we can transfer file descriptors.
        # The pipe is already non-blocking - read what we can

        Thread_SendAsync $data(master_thread) \
                    [list CgiCopyDirect $sock [read $fd]]

        return
    }

    # Normal one-thread case - set up to copy data from pipe to socket

    fconfigure $sock -translation binary
    fileevent $sock readable {}
    fileevent $fd readable {}
    fcopy $fd $sock -command [list CgiClose $fd $sock]
}

proc CgiCopyDirect {sock block} {
    puts -nonewline $sock $block
    flush $sock
}

# This is installed after running the sub-process to
# check for eof on the socket before the processing is complete.

proc CgiCleanup {fd sock} {
    fconfigure $sock -blocking 0 -translation auto
    set n [gets $sock line]
    if {[eof $sock]} {
	CgiCancel $fd $sock
    }
}

# Cancel a cgi script if it is taking too long.

proc CgiCancel {fd sock} {
    upvar #0 Httpd$sock data

    if {[info exist data(url)]} {
	Log $sock CgiCancel $data(url)
    }
    catch {exec kill [pid $fd]}
    CgiClose $fd $sock
}

# Close down the CGI connection

proc CgiClose {fd sock {bytes {}} {error {}}} {
    global Cgi
    upvar #0 Httpd$sock data

    catch {after cancel $data(cancel)}
    incr Cgi(cgi) -1
    if {![info exists data(header)]} {
	Httpd_Error $sock 204
    } else {
	Httpd_SockClose $sock 1
    }
    if {[string length $error] > 0} {
	Log $sock CgiClose $error
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/compat.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# compat.tcl
#@c Compatibility layer - deprecated
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# Colin McCormack (c) 2002
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: compat.tcl,v 1.5 2003/04/04 04:24:49 coldstore Exp $

package provide httpd::compat 3.3

foreach {oldname newname} {
    Doc_Cookie	Cookie_Get
    Doc_GetCookie	Cookie_Get
    Doc_SetCookie	Cookie_Set
    Doc_IsLinkToSelf	Url_IsLinkToSelf
    Doc_Redirect	Redirect_To
    Doc_RedirectSelf	Redirect_Self
    Doc_IsLinkToSelf	Url_IsLinkToSelf
    Doc_IndexFile	DirList_IndexFile
    Doc_Webmaster	Httpd_Webmaster
    Doc_CheckTemplates	Template_Check
    Doc_TemplateInterp	Template_Interp
    Doc_TemplateLibrary	Template_Library
    Doc_Dynamic		Template_Dynamic
    Doc_Subst		Subst_ReturnFile
    Doc_TemplateScope	Subst_Scope
    Doc_SubstInstall		Subst_Install

    Url_Redirect	Redirect_Url
    Url_RedirectSelf	Redirect_UrlSelf

} {
    interp alias {} $oldname {} $newname
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































Deleted lib/config.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# config.tcl
#
# This provides a simple module to manage configuration variables
#
# Brent Welch (c) 2000 Scriptics Corporation
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: config.tcl,v 1.4 2004/09/05 05:10:13 coldstore Exp $

package provide httpd::config 1.0

namespace eval config {
    
    # The main array holding the configuration information

    variable Config

    # The file containing the configuration information

    variable ConfigFile

    namespace export cget
}

# config::init --
#
#	Get the list of resources from disk.
#
# Arguments:
#	config		The name of the configuration file (optional)
#	aname		Name of array containing default configuration
#			values on input, and the new values after
#			processing the config file.
#
# Side Effects:
#	Defines the Config parameter array and records the name of
#	the configuration file in ConfigFile

proc config::init {config aname} {
    upvar 1 $aname TheirConfig
    variable Config
    variable ConfigFile

    if {[catch {open $config} in]} {
	return -code error "Cannot read configuration file \"$config\"\nError: $in"
    }
    set X [read $in]
    close $in

    # Load the file into a safe interpreter that just creates Config array

    set i [interp create -safe]
    if {$::tcl_version >= 8.5} {
      namespace ensemble create -command ::SafeFile -map {
        isdirectory {::file isdirectory}
        exists      {::file exists}
        join        {::file join}
        dirname     {::file dirname}
      }
      $i alias file SafeFile
    } else {
      interp expose $i file
    }
    $i alias fileutil::tempdir ::fileutil::tempdir 

    # Create the slave's Config array, then source the config script

    interp eval $i [list array set Config [array get TheirConfig]]

    interp eval $i {
	proc Config {name {value {}}} {
	    global Config
	    if {![info exist Config($name)] || [string length $value]} {
		set Config($name) $value
	    } else {
		set Config($name)
	    }
	}
    }
    if {[catch {interp eval $i $X} err]} {
	return -code error "Error in configuration file \"$config\"\n:Error: $err"
    }
    array set Config [interp eval $i {array get Config}]
    interp delete $i

    set ConfigFile $config
}

# config::cget --
#
#	Get the value for an index in the Config array.
#
# Arguments:
#	index	index in Config array to get.
#
# Results:
#	Returns the value of Config for the given index, or "" if
#	there is no such index.

proc config::cget {index} {
    variable Config

    if {![info exists Config($index)]} {
	return ""
    }
    return $Config($index)
}

# config::setValue --
#
#	Set one or more values for an index(es) in the Config array, and store
#	the array's new contents in the configuration file.
#
# Arguments:
#	args	A list of index, value pairs
#
# Results:
#	None.

proc config::setValue {args} {
    variable Config
    variable ConfigFile

    if {![info exist ConfigFile]} {
	return -code error "config is not initialized"
    }
    set in "(original lost)"
    if {![file exists $ConfigFile] || [catch {open $ConfigFile} in]} {
	set note "# Emergency copy: $in\n"
	unset in
    }
    append note "# Last modified: [clock format [clock seconds]]\n"

    # Re-write config file

    if {![info exist in]} {

	# We've lost the original, just dump out the array

	if {[catch {open $ConfigFile w} out]} {
	    return -code error "Cannot create configuration file: $out"
	}
	puts $out "# Server Configuration File\n$note\n"
	foreach name [lsort [array names Config]] {
	    puts $out [list Config $name $Config($name)]\n
	}
	close $out
    } else {
	
	# Re-write the original, inserting the new values.
	# This code only supports values that fit on one line

	set X [read $in]
	close $in
	if {[catch {open $ConfigFile w} out]} {
	    return -code error "Cannot re-write configuration file: $out"
	}

	regsub "^# Last modified:.*?\n" $X $note X

	foreach {name value} $args {
	    if {[regsub -all "\n\\s*?Config\\s*?[list $name](\\s*?).*?\n" $X \
			    "\nConfig [list $name]\\1 [list $value]\n" X] == 0} {
		append X "\n[list Config $name $value]\n"
	    }
	}
	puts -nonewline $out $X
	close $out
    }
    
    # Update in-memory information

    array set Config $args

    return
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































Deleted lib/cookie.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# cookie.tcl
#@c Cookie support
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: cookie.tcl,v 1.11 2005/01/02 03:36:38 coldstore Exp $

package provide httpd::cookie 1.0

package require httpd	;# Httpd_CurrentSocket Httpd_RemoveCookies Httpd_SetCookie
package require httpd::utils	;# K file lassign

# Cookie_Save
#
#@c	instruct httpd to return cookies, if any, to the browser
#
# Arguments:
#@a	interp  The interpreter in which to subst.

proc Cookie_Save {sock {interp {}}} {
    global Cookie
    if {![catch {
	interp eval $interp {uplevel #0 {set Cookie(set-cookie)}}
    } cookie]} {
	foreach c $cookie {
	    Httpd_SetCookie $sock $c
	}
	interp eval $interp {uplevel #0 {unset Cookie(set-cookie)}}
    }
}

# Cookie_Get
#
#@c	Return a *list* of cookie values, if present, else ""
#@c	It is possible for multiple cookies with the same key
#@c	to be present, so we return a list.
#@c     WARNING: This uses the environment HTTP_COOKIE, which can
#@c     get stomped on if a request reenters the event loop
#@c	See also Cookie_GetSock that doesn't have this problem
#
# Arguments:
#@a	cookie	The name of the cookie (the key)
# Returns:
#@r	a list of cookie values matching argument

proc Cookie_Get {cookie} {
    global env
    set result ""
    if {[info exist env(HTTP_COOKIE)]} {
	set rawcookie $env(HTTP_COOKIE)
    } else {
	# Try to find the connection
	if {[info exists env(HTTP_CHANNEL)]} {
	    upvar #0 Httpd$env(HTTP_CHANNEL) data
	    if {[info exist data(mime,cookie)]} {
		set rawcookie $data(mime,cookie)
	    }
	}
    }
    if {[info exist rawcookie]} {
	foreach pair [split $rawcookie \;] {
	    lassign [split [string trim $pair] =] key value
	    if {[string compare $cookie $key] == 0} {
		lappend result $value
	    }
	}
    }
    return $result
}

# Cookie_GetSock
#
#@c	Return a *list* of cookie values, if present, else ""
#@c	It is possible for multiple cookies with the same key
#@c	to be present, so we return a list.
#@c     This always gets the cookie state associated with the specified
#@c     socket, unlike Cookie_Get that looks at the environment.
#
# Arguments:
#@a	cookie	The name of the cookie (the key)
#@a	sock	A handle on the socket connection
# Returns:
#@r	a list of cookie values matching argument

proc Cookie_GetSock {sock cookie} {
    upvar #0 Httpd$sock data
    set result ""
    set rawcookie ""
    if {[info exist data(mime,cookie)]} {
        set rawcookie $data(mime,cookie)
    }
    foreach pair [split $rawcookie \;] {
        lassign [split [string trim $pair] =] key value
        if {[string compare $cookie $key] == 0} {
            lappend result $value
        }
    }
    return $result
}

# Cookie_Make
#
#$c	make a cookie from name value pairs
#
# Arguments:
#	args	Name value pairs, where the names are:
#@a		-name	Cookie name
#@a		-value	Cookie value
#@a		-path	Path restriction
#@a		-domain	domain restriction
#@a		-expires	Time restriction
#@a		-secure Append "secure" to cookie attributes
#@r	a formatted cookie

proc Cookie_Make {args} {
    array set opt $args
    set line "$opt(-name)=$opt(-value) ;"
    foreach extra {path domain} {
	if {[info exist opt(-$extra)]} {
	    append line " $extra=$opt(-$extra) ;"
	}
    }
    if {[info exist opt(-expires)]} {
	switch -glob -- $opt(-expires) {
	    *GMT {
		set expires $opt(-expires)
	    }
	    default {
		set expires [clock format [clock scan $opt(-expires)] \
			-format "%A, %d-%b-%Y %H:%M:%S GMT" -gmt 1]
	    }
	}
	append line " expires=$expires ;"
    }
    if {[info exist opt(-secure)]} {
	append line " secure "
    }
    return $line
}


# Cookie_Set
#
#$c	Set a return cookie
#
# Arguments:
#	args	Name value pairs, where the names are:
#@a		-name	Cookie name
#@a		-value	Cookie value
#@a		-path	Path restriction
#@a		-domain	domain restriction
#@a		-expires	Time restriction

proc Cookie_Set {args} {
    global Cookie
    lappend Cookie(set-cookie) [eval Cookie_Make $args]
}


# Cookie_UnSet
#
#$c	Unset a return cookie
#
# Arguments:
#	args	Name value pairs, where the names are:
#@a		-name	Cookie name
#@a		-path	Path restriction
#@a		-domain	domain restriction
proc Cookie_Unset {name args} {
    Httpd_RemoveCookies [Httpd_CurrentSocket] $name
    eval [list Cookie_Set -name $name -value "" -expires [clock format [clock scan "last year"] -format "%A, %d-%b-%Y %H:%M:%S GMT" -gmt 1]] $args
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































Deleted lib/counter.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# counter.tcl
#
# Global counters and histograms
#
# This module was generalized and moved into the Standard Tcl Library.
# This code is now a thin layer over that more general package.
#
# We pre-declare any non-simple counters (e.g., the time-based
# histogram for urlhits, and the interval-histogram for service times)
# and everything else defaults to a basic counter.  Once things
# are declared, the counter::count function counts things for us.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: counter.tcl,v 1.20 2004/09/05 05:10:13 coldstore Exp $

# Layer ourselves on top of the Standard Tcl Library counter package.

package require counter 2.0
package provide httpd::counter 2.0

package require httpd	;# Httpd_RegisterShutdown
package require httpd::log	;# Log
package require httpd::utils	;# file parray

proc Counter_Init {{secsPerMinute 60}} {
    global counter
    if {[info exists counter]} {
	unset counter
    }
    set counter(starttime) [clock seconds]
    
    # The Count procedure will be self-initializing because
    # the counter::count module is not.  The knownTags list is
    # searched to determine if we need to initialize the counter.
    # Predefine well known counters here.

    # urlhits is the number of requests serviced.

    counter::init urlhits -timehist $secsPerMinute

    # This start/stop timer is used for connection service times.
    # The linear histogram has buckets of 5 msec.

    counter::init serviceTime -hist 0.005

    # This log-scale histogram multiplies the seconds time by
    # 1000 to get milliseconds, and then plots the log of that.
    # The log-base histgram isn't useful
    #counter::init serviceTime -histlog 10

    # These group counters are used for per-page hit, notfound, and error
    # statistics.  If you auto-gen unique URLS, these are a memory leak
    # that you can plug by doing
    #
    #	status::countInit hit -simple

    foreach g {domainHit hit notfound errors} {
	counter::init $g -group $g
    }

    # These are simple counters about each kind of connection event

    foreach c {accepts sockets connections urlreply keepalive connclose 
		http1.0 http1.1 cgihits} {
	counter::init $c
    }
    Httpd_RegisterShutdown Counter_CheckPoint
}

proc Counter_CheckPoint {} {
    global Log
    if {[info exists Log(log)]} {
	set path $Log(log)counter
	catch {file rename -force $path $path.old}
	if {![catch {open $path w} out]} {
	    puts $out \n[parray counter]
	    puts $out \n[parray [counter::get urlhits -histVar]]
	    puts $out \n[parray [counter::get urlhits -histHourVar]]
	    puts $out \n[parray [counter::get urlhits -histDayVar]]
	    close $out
	}
    }
}

proc Count {what {delta 1}} {
    if {![counter::exists $what]} {
	counter::init $what
    }
    counter::count $what $delta
}

proc CountName {instance tag} {
    if {![counter::exists $tag]} {
	counter::init $tag
    }
    counter::count $tag 1 $instance
}

proc Counter_Reset {what args} {
    eval {counter::reset $what} $args
}

proc CountHist {what {delta 1}} {
    counter::count $what $delta
}

proc CountStart {what instance} {
    counter::start $what $instance
}
proc CountStop {what instance} {
    counter::stop $what $instance
#    counter::stop $what $instance CountMsec
}
proc CountMsec {x} {
    return [expr {$x * 1000}]
}
proc CountVarName {what} {
    return [counter::get $what -totalVar]
}
proc Counter_StartTime {} {
    return $counter::startTime
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































Deleted lib/debug.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
# debug.tcl --
#
#	Application-direct URLs to help debug the server.
# 	Tcl procedures of the form Debug/hello implement URLS
#	of the form /debug/hello
#
# Copyright (c) 1998-2000 by Ajuba Solutions.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: debug.tcl,v 1.21 2004/09/05 05:10:13 coldstore Exp $

package provide httpd::debug 1.0

package require httpd	;# Httpd_Webmaster
package require httpd::config	;# Config
package require httpd::direct	;# Direct_Url Direct_UrlRemove
package require httpd::status	;# Version
package require httpd::threadmgr	;# Thread_List Thread_Send
package require httpd::utils	;# Stderr file parray

# Debug_Url
#
#       Use this to register the URL prefix that corresponds to
#       the debug URLs implemented by this module
#
# Arguments:
#	dir	The URL prefix

proc Debug_Url {dir} {
    Direct_Url $dir Debug
    DebugSetRandomPassword $dir
}

# DebugSetRandomPassword
#
#       Choose and save a random password used to secure the /debug domain

proc DebugSetRandomPassword {dir} {
  set alphabet {a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 . + - =}
  for {set i 0} {$i < 12} {incr i} {
    set c [lindex $alphabet [expr int(rand() * [llength $alphabet])]]
    append passwd $c
  }
  set ::DebugPassword $passwd
  # This lets the admin see this important password during startup.
  # It is also displayed by the Tk srvui interface.
  Stderr "$dir user \"debug\" password \"$passwd\""
}

# DebugPasswordChecker
#
#	This is called to verify the username and password
#
# Arguments:
#	sock	Handle on the client connection
#	realm	Should be the realm we define above
#	user	The user name
#	pass	The password
#
# Results:
#	1	if access is allowed
#	0	if access is denied

proc DebugPasswordChecker {sock realm user pass} {
    # Any user will do, really, if you know the random password
    switch $user {
        tclhttpd -
        debug -
        default {
          return [DebugCheckRandomPassword $pass]
        }
    }
    return 0
}

# DebugCheckRandomPassword
#
#       Check that the input matches the random password

proc DebugCheckRandomPassword {input} {
  if {![info exist ::DebugPassword]} {
    return 0
  }
  return [expr {[string compare $::DebugPassword $input] == 0}]
}

# Debug/source --
#
#	Source the file into a server thread.  First look for the file to
#	source in the dir specified by Httpd(library).  If not found, use the
#	dir in Doc(templateLibrary) or Config(lib).
#
# Arguments:
#	source	the file to source
#
# Results:
#	Returns HTML code that displays result of loading the file.

proc Debug/source {source {thread main}} {
    global Httpd Doc Config
    set source [file tail $source]
    set dirlist $Httpd(library)
    if {[info exists Doc(templateLibrary)]} {
	lappend dirlist $Doc(templateLibrary)
    }
    if {[info exists Config(library)]} {
	lappend dirlist $Config(library)
    }
    if {[info exists Config(lib)]} {
	lappend dirlist $Config(lib)
    }
    foreach dir $dirlist {
	set file [file join $dir $source]
	if {[file exists $file]} {
	    break
	}
    }
    if {![file exists $file]} {
      set html "<h1>Error sourcing $source</h1>"
      append html "Cannot find it in <br>[join $dirlist <br>]"
      return $html
    }
      
    set error [catch {
	switch -- $thread {
	    main {
		uplevel #0 [list source $file]
	    }
	    all {
		foreach id [Thread_List] {
		    Thread_Send $id [list source $file]
		}
	    }
	    default {
                Thread_Send $thread [list source $file]
	    }
	}
    } result]
    set html "<title>Source $source</title>\n"
    if {$error} {
	global errorInfo
	append html "<H1>Error in $source</H1>\n"
	append html "<pre>$result<p>$errorInfo</pre>"
    } else {
	append html "<H1>Reloaded $source</H1>\n"
	append html "<pre>$result</pre>"
    }
    return $html
}

# Debug/package --
#
#	Forget, delete, and the reload a package into the server.
#
# Arguments:
#	name	the package to reload.
#
# Results:
#	Returns HTML code that displays the result of reloading the package.

proc Debug/package {name} {
    if {[catch {
	package forget $name
	catch {namespace delete $name}
	package require $name
    } result]} {
	set html "<title>Error</title>
<H1>Error Reloading Package $name</H1>

Unable to reload package \"$name\" due to:
<PRE>
$result
</PRE>
"
    } else {
	set html "<title>Package reloaded</title>
<H1>Reloaded Package $name</H1>
 
Version $result of package \"$name\" has been (re)loaded.
"
    }
 
    return $html
}
 
# Debug/pvalue --
#
#	Generate HTML code that displays the contents of all existing arrays
#	and variables that match the glob pattern.
#
# Arguments:
#	aname	the (fully qualified) glob pattern to match against existing
#		arrays and variables.
#
# Results:
#	Returns HTML code that displays the contents of the arrays and
#	variables that match the glob pattern.

proc Debug/pvalue {aname} {
    set html "<title>$aname</title>\n"
    append html [DebugValue $aname]
    return $html
}
proc DebugValue {aname} {
    upvar #0 $aname var
    append html "<p><b><font size=+=>$aname</font></b><br>\n"
    if {[array exists var]} {
	global $aname
	append html "<pre>[parray $aname]</pre>"
    } elseif {[info exists var]} {
	append html "<pre>[list set $aname $var]</pre>"
    } else {
	# Undefined variable - see if it is a pattern.
	# Be careful about declared but undefined procedures
	# that used to blow the recursion stack here...

	set list [lsort [uplevel #0 [list info vars $aname]]]
	if {[llength $list] == 1 &&
		[string compare [lindex $list 0] $aname] == 0} {
	    append html "<pre># $aname undefined</pre>"
	} else {
	    append html "<ul>"
	    foreach n $list {
		append html [DebugValue $n]
	    }
	    append html "</ul>"
	}
    }
    return $html
}

# Debug/parray --
#
#	Generate HTML code that displays 
#
# Arguments:
#	aname	the name of the array whose contents will appear.
#
# Results:
#	Returns HTML code that displays 

proc Debug/parray {aname} {
    global $aname
    set html "<title>Array $aname</title>\n"
    append html "<H1>Array $aname</H1>\n"
    append html "<pre>[parray $aname]</pre>"
    return $html
}

# Debug/raise --
#
#	Generate HTML code that causes the Tcl error specified by args to be thrown.
#
# Arguments:
#	args	(optional) the error string to throw.
#
# Side Effects:
#	An error is thrown.
#
# Results:
#	none.

proc Debug/raise {args} {
    error $args
}

# Debug/goof --
#
#	Generate HTML code that causes the Tcl error: "can't read "goof": no
#	such variable".
#
# Arguments:
#	none.
#
# Side Effects:
#	An error is thrown.
#
# Results:
#	None.

proc Debug/goof {} {
    set goof
    return
}

# Debug/after --
#
#	Generate HTML code that displays info regarding after events existing
#	on the server.
#
# Arguments:
#	none.
#
# Results:
#	Returns HTML.

proc Debug/after {} {
    global tcl_version
    set html "<title>After Queue</title>\n"
    append html "<H1>After Queue</H1>\n"
    append html "<pre>"
    if {[catch {after info} afterlist]} {
	append html "\"after info\" not supported in Tcl $tcl_version"
    } else {
	foreach a $afterlist {
	    append html "$a [after info $a]\n"
	}
    }
    append html </pre>
    return $html
}

# Debug/echo --
#
#	Generate HTML code that displays the attributes and values posted to
#	the URL.
#
# Arguments:
#	title	(optional) title to display
#	args	an even number of attrbutes and values to be displayed.
#
# Results:
#	Returns HTML.

proc Debug/echo {title args} {
    set html "<title>$title</title>\n"
    append html "<H1>$title</H1>\n"
    append html "<table border=1>\n"
    foreach {name value} $args {
	append html "<tr><td>$name</td><td>$value</td></tr>\n"
    }
    append html </table>
    return $html
}

# Debug/errorInfo --
#
#	Generate HTML code that displays a title, some errorInfo, and the
#	contents of (the env) array.
#
# Arguments:
#	title		(optional) page title to display
#	errorInfo	(optional) error data to display
#	env		(optional) the name of an array to display
#
# Results:
#	Returns HTML.

proc Debug/errorInfo {title errorInfo {env {no environment}}} {
    set html "<title>$title</title>\n"
    append html "<H1>$title</H1>\n"
    append html "<p>[Version]"
    append html "<br>Webmaster: [Httpd_Webmaster]"
    append html <pre>$errorInfo</pre>
    append html "<p>Environment:</p>"
    append html "<table>"
    catch {
    array set X $env
    foreach n [lsort [array names X]] {
	append html "<tr><td>$n</td><td>$X($n)</td></tr>\n"
    }
    }
    append html "</table>"
    return $html
}

# Debug/dbg --
#
#	Initiate a connection with the tcldebugger.
#
# Arguments:
#	host	the host where the debugger is running
#	port	the port on which the debugger is listening
#
# Results:
#	Returns the result of initiating the connection in HTML.

proc Debug/dbg {host port} {
    global debug_init Httpd

    # In case application-direct parameter bindings are broken,
    # use the local host and default prodebug port.
    if {$host == ""} {
	set host [info hostname]
    }
    if {$port == ""} {
	set port 2576
    }

    if {![info exist debug_init]} {
	if {[info command debugger_init] == ""} {
	    source [file join $Httpd(library) prodebug.tcl]
	}
	debugger_init $host $port
	set debug_init "$host $port"
	return "Contacted TclPro debugger at $host:$port"
    }
    return "Already connected to tclPro at $debug_init"
}

# Debug/showproc --
#
#	Generate HTML code that displays the args and body of a proc.
#
# Arguments:
#	proc	the name of the procedure
#
# Results:
#	Returns HTML.

proc Debug/showproc {proc} {
    global Debug/showproc
    set Debug/showproc text/plain

    set alist ""
    foreach arg [info args $proc] {
        if {[info default $proc $arg default]} {
            set arg [list $arg $default]
        }
        lappend alist $arg
    }
    return [list proc $proc $alist [info body $proc]]
}

# Debug/disable --
#
#	Disable debugging in tclhttpd.
#
# Side Effects:
#       Removes the /debug URL

proc Debug/disable {} {
    Direct_UrlRemove Debug
    return "<title>Debugging disabled</title>\n
                    <h1> Debugging disabled</h1>"
}  
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/deprecated/base64.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# base64.tcl
# Encode/Decode base64 for a string
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# The decoder was done for exmh by Chris Garrigues
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# SCCS: @(#) base64.tcl 1.4 98/02/24 16:00:03

package provide base64 1.0

set i 0
foreach char {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
	      a b c d e f g h i j k l m n o p q r s t u v w x y z \
	      0 1 2 3 4 5 6 7 8 9 + /} {
    set base64($char) $i
    set base64_en($i) $char
    incr i
}

proc Base64_Encode {string} {
    global base64_en
    set result {}
    set state 0
    set length 0
    foreach {c} [split $string {}] {
	scan $c %c x
	switch [incr state] {
	    1 {	append result $base64_en([expr {($x >>2) & 0x3F}]) }
	    2 { append result \
		$base64_en([expr {(($old << 4) & 0x30) | (($x >> 4) & 0xF)}]) }
	    3 { append result \
		$base64_en([expr {(($old << 2) & 0x3C) | (($x >> 6) & 0x3)}])
		append result $base64_en([expr {($x & 0x3F)}])
		set state 0}
	}
	set old $x
	incr length
	if {$length >= 72} {
	    append result \n
	    set length 0
	}
    }
    set x 0
    switch $state {
	0 { # OK }
	1 { append result $base64_en([expr {(($old << 4) & 0x30)}])== }
	2 { append result $base64_en([expr {(($old << 2) & 0x3C)}])=  }
    }
    return $result
}
proc Base64_Decode {string} {
    global base64

    set output {}
    set group 0
    set j 18
    foreach char [split $string {}] {
	if {[string compare $char \n] == 0} {
	    continue
	}
	if [string compare $char "="] {
	    set bits $base64($char)
	    set group [expr {$group | ($bits << $j)}]
	} else {
	    break
	}

	if {[incr j -6] < 0} {
	    scan [format %06x $group] %2x%2x%2x a b c
	    append output [format %c%c%c $a $b $c]
	    set group 0
	    set j 18
	}
    }
    switch $j {
	-6 { # Even multiple of 4 6-bit chars }
	0 { # One traiing = means one extra byte we don't want
	    scan [format %06x $group] %2x%2x%2x a b c
	    append output [format %c%c $a $b]
	}
	6 { # Two tailing == means two extra bytes we don't want
	    scan [format %06x $group] %2x%2x%2x a b c
	    append output [format %c $a] 
	}
	12 { # Shouldn't happen, go through loop at least twice }
    }
    return $output
}


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































Deleted lib/digest.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# digest.tcl
#
# Provides Digest Authentication, per http://www.ietf.org/rfc/rfc2617.txt
# Works in conjunction with auth.tcl, requires tcllib.
# Digest authentication is selectable in .htaccess.
# No provision for dual Basic/Digest authentication.
#
# Supports only algorithm=MD5 and qop=auth
# (which is more than most browsers support :)
#
# Copyright 2004 Colin McCormack.  [email protected]
# Licensed on terms identical to tclhttpd's license.

package require base64

package provide httpd::digest 1.0
package require httpd::md5hex
package require httpd::auth

# generate private key
if {[catch {package require Random}]} {
    # use the built in tcl random
    proc DigestRand {} {
	return [expr {rand() * 65536}]
    }
} else {
    # use http://mini.net/tcl/random
    # cvs -d:pserver:[email protected]:/cvsroot/tclsoap co Random
    # generate a random seed
    if {[catch {
	# try for hardware support
	set r [open /dev/random]
	binary scan [read $r 4] I seed
	close $r
    }]} {
	set seed [clock clicks]
    }
    ::isaac::isaac seed $seed	;# seed random

    # get an integer secret
    proc DigestRand {} {
	return [::isaac::isaac integer]
    }
}
set DigestSecret [DigestRand]

proc Digest_Passwd {username realm passwd} {
    return [string tolower [md5hex "$username:$realm:$passwd"]]
}

# calculate a digest key for a given session
proc DigestA1 {sock} {
    upvar #0 Httpd$sock data
    upvar #0 Digest$data(digest,nonce) digest

    # create a digest for this socket
    set userstuff "$data(digest,username):$data(digest,realm):$digest(passwd)"
    #Stderr "DigestA1: $userstuff"
    switch -- [string tolower $data(digest,algorithm)] {
	md5 {
	    set digest(A1) [md5hex $userstuff]
	}
	md5-sess {
	    set digest(A1) [md5hex "[string tolower [md5hex $userstuff]]:$data(digest,nonce):$data(digest,cnonce)"]
	}
	default {
	    error "unknown algorithm: $data(digest,algorithm)"
	}
    }
    set digest(A1) [string tolower $digest(A1)]
    return $digest(A1)
}

# per operation hash
proc DigestA2 {sock} {
    upvar #0 Httpd$sock data
    set uri $data(digest,uri)
    regexp {[^?]+} $uri uri
    if {[info exists data(proto)]} {
	#Stderr "A2: op:$data(proto) uri:$data(digest,uri)"
	set result [string tolower [md5hex "[string toupper $data(proto)]:$data(digest,uri)"]]
	# nb: we don't offer auth-int
    } else {
	#Stderr "A2: uri:$data(digest,uri)"
	set result [string tolower [md5hex "GET:$data(digest,uri)"]]
    }
    return [string tolower $result]
}

# generate a nonce
proc DigestNonce {} {
    #return "dcd98b7102dd2f0e8b11d0f600bfb0c093"	;# test

    global DigestSecret
    set time [clock clicks]
    return [string tolower [md5hex ${time}:${DigestSecret}]]
}

# calculate the digest value for a given operation and session
proc DigestDigest {sock} {
    upvar #0 Httpd$sock data
    upvar #0 Digest$data(digest,nonce) digest
    if {![info exists digest(A1)]} {
	set digest(A1) [DigestA1 $sock]
    }
    set digest(A2) [DigestA2 $sock]

    #Stderr "DigestDigest A1:$digest(A1) A2:$digest(A2) nc:[format %08x $data(digest,nc)] cnonce:$data(digest,cnonce) qop:$data(digest,qop)"

    if {[info exists data(digest,qop)]} {
	set result [md5hex "$digest(A1):$data(digest,nonce):[format %08x $data(digest,nc)]:$data(digest,cnonce):$data(digest,qop):$digest(A2)"]
    } else {
	set result [md5hex "$digest(A1):$data(digest,nonce):$digest(A2)"]
    }
    return [string tolower $result]
}

# handle the client's Digest
proc Digest_Request {sock realm file} {
    upvar #0 Httpd$sock data
    upvar #0 Digest$data(digest,nonce) digest
    set digest(last) [clock clicks]	;# remember the last use

    if {![info exists digest(A1)]} {
	set A1 [AuthGetPass $sock $file $data(digest,username)@$data(digest,realm)]
	if {$A1 != "*"} {
	    set digest(A1) $A1
	} else {
	    # no digest password on record - use plaintext password
	    if {![info exists digest(passwd)]} {
		set digest(passwd) [AuthGetPass $sock $file $data(digest,username)]
	    }
	    set digest(A1) [DigestA1 $sock]
	    #Stderr "Plaintext password $digest(passwd)"
	}
	#Stderr "A1 Calc: $digest(A1)"
    }

    # check that realms match
    if {$realm != $data(digest,realm)} {
	#Stderr "realm"
	return 0
    }

    #Stderr "Digest_Request: [array get digest] - [array get data digest,*]"

    if {[info exists digest(opaque)]} {
	if {$digest(opaque) != $data(digest,opaque)} {
	    #Stderr "Digest Opaque $digest(opaque) ne $data(digest,opaque)"
	    return 0
	}
    }

    # check the nonce count
    set data(digest,nc) [scan $data(digest,nc) %08x]
    if {[info exists digest(nc)]} {
	if { $data(digest,nc) <= $digest(nc)} {
	    set digest(stale) 1
	    #Stderr "Digest Stale $digest(nc) ne $data(digest,nc)"
	    #return 0	;# Mozilla doesn't implement nc
	}
	#Stderr "Digest nc $digest(nc) - $data(digest,nc)"
    } else {
	#Stderr "Digest New Nonce $data(digest,nc)"
	return 0	;# this is new to us
    }
    set digest(nc) $data(digest,nc)

    # check the password
    set calc_digest [DigestDigest $sock]
    if {$calc_digest != $data(digest,response)} {
	#Stderr "Digest Response: $calc_digest ne $data(digest,response)"
	return 0
    }

    # successful authentication
    # construct authentication args
    set a_args "qop=auth"
    if {[info exists data(digest,cnonce)]} {
	append a_args ", cnonce=\"$data(digest,cnonce)\""
	append a_args ", rspauth=\"${calc_digest}\""
    }
    if {[info exists data(digest,nc)]} {
	append auth_info [format ", nc=%08x" [expr 1 + $data(digest,nc)]]
    }

    # remember some data
    set digest(realm) $data(digest,realm)
    set digest(cnonce) $data(digest,cnonce)
    set digest(username) $data(digest,username)

    # associate nonce with realm,user
    global DigestByRealmName
    set DigestByRealmName($digest(realm),$digest(username)) $digest(nonce)

    Httpd_AddHeaders $sock Authentication-Info $auth_info

    #Stderr "Digest Request OK"
    return 1
}

# decode an Authentication request
# "parts" comes from the Authorization HTTP header.

proc Digest_Get {sock parts} {
    upvar #0 Httpd$sock data
    #Stderr "Digest_Get $parts"
    # get the digest request args
    foreach el [lrange $parts 1 end] {
	set el [string trimright $el ,]
	#foreach {n v} [split $el =] break
	regexp {^[ ]*([^=]+)[ ]*=[ ]*(.*)$} $el junk n v
	#Stderr "Getting: '$el' -> $n $v"
	set data(digest,[string trim $n " "]) [string trim $v " \""]
    }
    #Stderr "Digest Got: [array get data digest,*]"
    # perform some desultory checks on credentials
}

# create and issue a Digest challenge to the client
proc Digest_Challenge {sock realm user} {
    upvar #0 Httpd$sock data

    global DigestByRealmName
    if {[info exists DigestByRealmName($realm,$user)]} {
	# find an existing nonce for this realm,user pair
	set nonce $DigestByRealmName($realm,$user)

	upvar #0 Digest$nonce digest
	set digest(last) [clock clicks]	;# remember the last use
    } else {
	# get a new unique nonce
	# (redundant, really MD5 doesn't collide)
	set nonce [DigestNonce]
	while {[info exists ::Digest$nonce]} {
	    set nonce [DigestNonce]
	}
	upvar #0 Digest$nonce digest
	set digest(last) [clock clicks]	;# remember the last use

	# initialise the digest state
	global DigestSecret
	set digest(nonce) $nonce
	set digest(opaque) [string tolower [md5hex "[clock clicks]${DigestSecret}"]]
	#set digest(opaque) 5ccc069c403ebaf9f0171e9517f40e41	;# test
	set digest(nc) 0
	#set digest(stale) 0
    }

    # construct authentication args
    # minimally nonce, opaque, qop and algorithm
    set challenge [list nonce \"$digest(nonce)\" \
		       domain \"/" \
		       opaque \"$digest(opaque)\" \
		       qop \"auth\" \
		       algorithm MD5]
    #		   algorithm \"MD5,MD5-sess\"
    #if {$digest(stale)} {
    #lappend challenge stale true
    #}

    #Stderr "Digest Challenge: [array get digest] - $challenge"
    # issue Digest authentication challenge
    eval Httpd_RequestAuth $sock Digest $realm $challenge
}

if {0} {
    # test
    array set Httpd999 {
	digest,username Mufasa
	digest,realm [email protected]
	digest,nonce dcd98b7102dd2f0e8b11d0f600bfb0c093
	uri /dir/index.html
	digest,uri /dir/index.html
	op GET
	digest,qop auth
	digest,nc 00000001
	digest,cnonce 0a4f113b
	digest,response 6629fae49393a05397450978507c4ef1
	digest,opaque 5ccc069c403ebaf9f0171e9517f40e41
	digest,algorithm MD5
    }
    array set Digest$Httpd999(digest,nonce) [list last [clock clicks] nc [format %08d 1] opaque $Httpd999(digest,opaque) nonce $Httpd999(digest,nonce) realm [email protected] qop auth,auth-int passwd "Circle Of Life"]

    AuthParseHtaccess 999 /usr/lib/tclhttpd3.5.0/testdigest
    if {[catch {Digest_Request 999 [email protected] /usr/lib/tclhttpd3.5.0/testdigest}  DTest]} {
	error "Digest test error"
    }
    if {$DTest != 1} {
	error "Failed digest test"
    }
}

# nb: mozilla converts UCS2 to UTF8 for username and password
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































Deleted lib/direct.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# direct.tcl
#
# Support for application-direct URLs that result in Tcl procedures
# being invoked inside the server.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: direct.tcl,v 1.21 2004/11/20 07:10:04 coldstore Exp $

package provide httpd::direct 1.1

package require httpd	;# Httpd_Redirect Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::cookie	;# Cookie_Save
package require httpd::doc_error	;# Doc_NotFound
package require httpd::url	;# Url_PrefixInstall Url_PrefixRemove Url_QuerySetup
package require httpd::utils	;# file iscommand

# Direct_Url
#	Define a subtree of the URL hierarchy that is implemented by
#	direct Tcl calls.
#
# Arguments
#	virtual The name of the subtree of the hierarchy, e.g., /device
#	prefix	The Tcl command prefix to use when constructing calls,
#		e.g. Device
#	inThread	True if this should be dispatched to a thread.
#
# Side Effects
#	Register a prefix

proc Direct_Url {virtual {prefix {}} {inThread 0}} {
    global Direct
    if {[string length $prefix] == 0} {
	set prefix $virtual
    }
    set Direct($prefix) $virtual	;# So we can reconstruct URLs
    Url_PrefixInstall $virtual [list DirectDomain $prefix] $inThread
}

# Direct_UrlRemove
#       Remove a subtree of the URL hierarchy that is implemented by
#       direct Tcl calls.
#
# Arguments
#       prefix  The Tcl command prefix used when constructing calls,
#
# Side Effects
#
       
proc Direct_UrlRemove {prefix} {
    global Direct
    catch { Url_PrefixRemove $Direct($prefix) }
    catch { unset Direct($prefix) }
}
        
# Main handler for Direct domains (i.e. tcl commands)
# prefix: the Tcl command prefix of the domain registered with Direct_Url 
# sock: the socket back to the client
# suffix: the part of the url after the domain prefix.
#
# This calls out to the Tcl procedure named "$prefix$suffix",
# with arguments taken from the form parameters.
# Example:
# Direct_Url /device Device
# if the URL is /device/a/b/c, then the Tcl command to handle it
# should be
# proc Device/a/b/c
# You can define the content type for the results of your procedure by
# defining a global variable with the same name as the procedure:
# set Device/a/b/c text/plain
#  The default type is text/html

proc DirectDomain {prefix sock suffix} {
    global Direct
    global env
    upvar #0 Httpd$sock data

    # Set up the environment a-la CGI.

    Cgi_SetEnv $sock $prefix$suffix

    # Prepare an argument data from the query data.

    Url_QuerySetup $sock
    set cmd [Direct_MarshallArguments $prefix $suffix]
    if {$cmd == ""} {
	Doc_NotFound $sock
	return
    }

    # Eval the command.  Errors can be used to trigger redirects.

    set code [catch $cmd result]

    set type text/html
    upvar #0 $prefix$suffix aType
    if {[info exist aType]} {
	set type $aType
    }

    Direct_Respond $sock $code $result $type
}

# Direct_MarshallArguments --
#
#	Use the url prefix, suffix, and cgi values (set with the
#	ncgi package) to create a Tcl command line to invoke.
#
# Arguments:
# 	prefix		The Tcl command prefix of the domain registered 
#			with Direct_Url.
#	suffix		The part of the url after the domain prefix.
#
# Results:
#	Returns a Tcl command line.
#
# Side effects:
#	If the prefix and suffix do not map to a Tcl procedure,
#	returns empty string.

proc Direct_MarshallArguments {prefix suffix} {
    global Direct

    set cmd $prefix$suffix
    if {![iscommand $cmd]} {
	return
    }

    # Compare built-in command's parameters with the form data.
    # Form fields with names that match arguments have that value
    # passed for the corresponding argument.
    # Form fields with no corresponding parameter are collected into args.

    set cmdOrig $cmd
    set params [info args $cmdOrig]
    foreach arg $params {
	if {[ncgi::empty $arg]} {
	    if {[info default $cmdOrig $arg value]} {
		lappend cmd $value
	    } elseif {[string compare $arg "args"] == 0} {
		set needargs yes
	    } else {
		lappend cmd {}
	    }
	} else {
	    
	    # The original semantics for Direct URLS is that if there
	    # is only a single value for a parameter, then no list
	    # structure is added.  Otherwise the parameter gets a list
	    # of all values.

	    set vlist [ncgi::valueList $arg]
	    if {[llength $vlist] == 1} {
		lappend cmd [ncgi::value $arg]
	    } else {
		lappend cmd $vlist
	    }
	}
    }
    if {[info exists needargs]} {
	foreach {name value} [ncgi::nvlist] {
	    if {[lsearch $params $name] < 0} {
		lappend cmd $name $value
	    }
	}
    }
    return $cmd
}

# Direct_Respond --
#
#	This function returns the result of evaluating the direct
#	url.  Usually, this involves returning a page, but a redirect
#	could also occur.
#
# Arguments:
# 	sock	The socket back to the client.
#	code	The return code from evaluating the direct url.
#	result	The return string from evaluating the direct url.
#	type	The mime type to use for the result.  (Defaults to text/html).
#	
#
# Results:
#	None.
#
# Side effects:
#	If code 302 (redirect) is passed, calls Httpd_Redirect to 
#	redirect the current request to the url in result.
#	If code 0 is passed, the result is returned to the client.
#	If any other code is passed, an exception is raised, which
#	will cause a stack trace to be returned to the client.
#

proc Direct_Respond {sock code result {type text/html}} {
    switch $code {
	0 {
	    # Fall through to Httpd_ReturnData.
	}
	302	{
	    # Redirect.

	    Httpd_Redirect $result $sock
	    return ""
	}
	default {
	    # Exception will cause error page to be returned.

	    global errorInfo errorCode
	    return -code $code -errorinfo $errorInfo -errorcode $errorCode \
		    $result
	}
    }

    # See if a content type has been registered for the URL.

    # Save any return cookies which have been set.
    # This works with the Doc_SetCookie procedure that populates
    # the global cookie array.
    Cookie_Save $sock

    Httpd_ReturnData $sock $type $result
    return ""
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































































































































































































Deleted lib/dirlist.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# dirlist.tcl --
#
# Create a HTML-formatted directory listing
#
# Steve Ball (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: dirlist.tcl,v 1.13 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::dirlist 1.1

package require httpd	;# Httpd_ReturnData
package require httpd::doc	;# Doc_Handle
package require httpd::doc_error	;# Doc_NotFound
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_Encode
package require httpd::utils	;# file file_latest setmax

# DirList_IndexFile --
#
#	Define the index file for a directory
#
# Arguments:
#	pat	A glob pattern for index files in a directory.
#
# Results:
#	None
#
# Side Effects:
#	Sets the index file glob pattern.

proc DirList_IndexFile {pat} {
    global dirlist
    set dirlist(indexpat) $pat
}

# DirList_Directory --
#
#	Handle a directory.  Look for the index file, falling back to
#	the Directory Listing module, if necessary.  If the Directory
#	Listing is hidden, then give the not-found page.
#
# Arguments:
#	prefix	The URL domain prefix.
#	path	The file system pathname of the directory.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Dispatches to the appropriate page handler.

proc DirList_Directory {prefix path suffix sock} {
    upvar #0 Httpd$sock data
    global dirlist tcl_platform

    # Special case because glob doesn't work in wrapped files
    # Just set indexpat to "index.tml" or "index.html"

    set npath [file join $path $dirlist(indexpat)]
    if {[info exist tcl_platform(isWrapped)] && $tcl_platform(isWrapped)} {
	set newest $npath
    } else {
	set newest [file_latest [glob -directory $path -nocomplain -- $dirlist(indexpat)]]
    }
    if {[string length $newest]} {

	# Template hack.  Ask for the corresponding .html file in
	# case that file should be cached when running the template.
	# If we ask for the .tml directly then its result is never cached.
	global Template
	if {[string compare $Template(tmlExt) [file extension $newest]] == 0} {
	    set newest [file root $newest]$Template(htmlExt)
	}
	return [Doc_Handle $prefix $newest $suffix $sock]
    }
    if {[Dir_ListingIsHidden]} {
        # Directory listings are hidden, so give the not-found page.
        return [Doc_NotFound $sock]
    }
    # Listings are not hidden, so show it.
    Httpd_ReturnData $sock text/html [DirList $sock $path $data(url)]
}

# Dir_HideListings --
#
#	If a directory is viewed, hide the directory listing.
#
# Arguments:
#	None
#
# Results:
#	None
#
# Side Effects:
#	From now on, directory listings are hidden.

proc Dir_HideListings {} {
    global Doc
    set Doc(HideDirListing) 1
    return
}

# Dir_ShowListings --
#
#	If a directory is viewed, show the directory listing.
#
# Arguments:
#	None
#
# Results:
#	None
#
# Side Effects:
#	From now on, directory listings can be shown.

proc Dir_ShowListings {} {
    global Doc
    set Doc(HideDirListing) 0
    return
}

# Dir_ListingIsHidden --
#
#	Tell whether directory listings are currently hidden.
#
# Arguments:
#	None
#
# Results:
#	Returns 1 if listings are hidden, otherwise 0.
#
# Side Effects:
#	None

proc Dir_ListingIsHidden {} {
    global Doc
    return $Doc(HideDirListing)
}

# By default, directory listings are shown.
Dir_ShowListings

proc DirListForm {dir urlpath {sort name} {pattern *}} {
    set what [DirListTerm]
    set namecheck ""
    set sizecheck ""
    set numcheck ""
    switch -- $sort {
        number {
	    set numcheck checked
	}
	size {
	    set sizecheck checked
	}
	default {
	    set namecheck checked
	}
    }
    set listing "
<H1>Listing of $what $urlpath</H1>

<form action=$urlpath>
Pattern <input type=text name=pattern value=$pattern><br>
Sort by Modify Date <input type=radio name=sort value=number $numcheck>
or Name <input type=radio name=sort value=name $namecheck>
or Size <input type=radio name=sort value=size $sizecheck><br>
<input type=submit name=submit value='Again'><p>
"
    append listing [DirListInner $dir $urlpath $sort $pattern]
    append listing "</form>\n"
    return $listing
}

proc DirListInner {dir urlpath sort pattern} {
    set listing "<PRE>\n"
    set path [file split $dir]

    # Filter pattern to avoid leaking path information
    regsub -all {\.+/} $pattern {} pattern
    set pattern [string trimleft $pattern /]

    set list [glob -directory $dir -nocomplain -- $pattern]
    if {[llength $path] > 1} {
	append listing \
	    "<A HREF=\"..\">Up to parent [string tolower [DirListTerm]]</A>\n"
    }

    set timeformat "%b %e, %Y %X"
    if {[llength $list] > 0} {
	set max 0
	foreach entry $list {
	    setmax max [string length [file tail $entry]]
	}
	incr max [string length </a>]

	# Resort the list into list2

	switch -- $sort {
	    number {
		set mlist {}
		foreach entry $list {
		    lappend mlist [list $entry [file mtime $entry]]
		}
		if {[catch {lsort -decreasing -integer -index 1 $mlist} list2]} {
		    set list2 [lsort -command DateCompare $mlist]
		}
		set extra 1
	    }
	    size {
		set slist {}
		foreach entry $list {
		    lappend slist [list $entry [file size $entry]]
		}
		if {[catch {lsort -decreasing -integer -index 1 $slist} list2]} {
		    set list2 [lsort -command SizeCompare $slist]
		}
		set extra 1
	    }
	    default {
		if {[catch {lsort -dict $list} list2]} {
		    set list2 [lsort -command DirlistCompare $list]
		}
		set extra 0
	    }
	}

	# Loop through list2, which may have an extra sorting field we ignore

	foreach entry $list2 {
	    if {$extra} {
		set entry [lindex $entry 0]
	    }
	    file lstat $entry lst
	    switch $lst(type) {
		file {
		    # Should determine dingbat from file type
		    append listing "<A HREF=\"[DirHref $entry]\">[format %-*s $max [file tail $entry]</a>] [format %8d $lst(size)] [format %-5s bytes]  [clock format $lst(mtime) -format $timeformat]\n"
		}
		directory {
		    append listing "<A HREF=\"[DirHref $entry]/\">[format %-*s $max [file tail $entry]/</a>] [format %8s {}] [format %-5s dir]  [clock format $lst(mtime) -format $timeformat]\n"
		}
		link {
		    append listing "<A HREF=\"[DirHref $entry]\">[format %-*s $max [file tail $entry]</a>] [format %8s {}] [format %-5s link]  [clock format $lst(mtime) -format $timeformat] -> [file readlink $entry]\n"
		}
		characterSpecial -
		blockSpecial -
		fifo -
		socket {
		    append listing "<A HREF=\"${urlpath}[file tail $entry]\">[format %-20s [file tail $entry]</a>] $lst(type)\n"
		}
	    }
	}
    } else {
	append listing "[DirListTerm] is empty\n"
    }

    append listing "
</PRE>
"
    return $listing
}

proc DirHref {entry} {
    set entry [Url_Encode [file tail $entry]]
    # Decode ".",
    regsub -all -nocase {%2e} $entry . entry
    regsub -all -nocase {%5f} $entry _ entry
    return $entry
}

proc DirList {sock dir urlpath} {
    upvar #0 Httpd$sock data

    set sort name
    set pattern *
    if {[info exists data(query)]} {
	foreach {name value} [Url_DecodeQuery $data(query)] {
	    switch $name {
		sort {set sort $value}
		pattern {set pattern $value}
	    }
	}
    }

    return "
<HTML>
<HEAD>
    <TITLE>Listing of [DirListTerm] $urlpath</TITLE>
</HEAD>
<BODY>
    [DirListForm $dir $urlpath $sort $pattern]
</BODY>
</HTML>"
}

# DirlistCompare --
#
# Utility procedure for case-insensitive filename comparison.
# Suitable for use with lsort

proc DirlistCompare {a b} {
    string compare [string tolower $a] [string tolower $b]
}


proc DateCompare {a b} {
    set a [lindex $a 1]
    set b [lindex $b 1]
    if {$a > $b} {
	return -1
    } elseif {$a < $b} {
	return 1
    } else {
	return 0
    }
}

proc SizeCompare {a b} {
    set aa [lindex $a 1]
    set bb [lindex $b 1]
    set res [string compare $aa $bb]
    if { $res != 0 } {
	return $res
    } else {
	return [string compare $a $b]
    }
}

# DirListTerm --
#
# Return "Folder" or "Directory" as appropriate

proc DirListTerm {} {
    global tcl_platform

    if {[string compare macintosh $tcl_platform(platform)]} {
	set what Directory
    } else {
	set what Folder
    }
    return $what
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































































































































































































































































































































Deleted lib/doc.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
# doc.tcl
#
# File system based URL support.
# This calls out to the Auth module to check for access files.
# Once a file is found, it checks for content-type handlers defined
# by Tcl procs of the form Doc_$contentType.  If those are present
# then they are responsible for processing the file and returning it.
# Otherwise the file is returned by Doc_Handle.
#
# If a file is not found then a limited form of content negotiation is
# done based on the browser's Accept header.  For example, this makes
# it easy to transition between foo.shtml and foo.html.  Just rename
# the file and content negotiation will find it from old links.
#
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: doc.tcl,v 1.59 2004/12/11 13:22:40 coldstore Exp $

package require uri

package provide httpd::doc 1.1

package require httpd	;# Httpd_ReturnFile
package require httpd::auth	;# Auth_Check Auth_Verify
package require httpd::cgi	;# Cgi_Domain
package require httpd::counter	;# Count CountName
package require httpd::dirlist	;# DirList DirList_Directory
package require httpd::doc_error ;# Doc_NotFound
package require httpd::fallback	;# Fallback_Try
package require httpd::mtype	;# Mtype
package require httpd::redirect	;# Redirect_Dir Redirect_Self Redirect_To
package require httpd::template	;# Template_Dynamic Template_Try
package require httpd::url	;# Url_AccessInstall Url_PathCheck Url_PrefixInstall Url_PrefixMatch
package require httpd::utils	;# file iscommand

# Doc_Root --
#
# Query or set the physical pathname of the document root
#
# Arguments:
#	real 	Optional.  The name of the file system directory
#		containing the root of the URL tree.  If this is empty,
#		then the current document root is returned instead.
#	args	"real" followed by "args" for Url_PrefixInstall.
#		"real" is the name of the file system directory
#		containing the root of the URL tree.  If no args are given,
#		then the current document root is returned instead.
#
# Results:
#	If querying, returns the name of the directory of the document root.
#	Otherwise returns nothing.
#
# Side Effects:
#	Sets the document root.

proc Doc_Root {args} {
    global Doc
    if {[llength $args] > 0} {
        set real [lindex $args 0]
	set Doc(root) $real
	eval [list Doc_AddRoot / $real] [lrange $args 1 end]
        return
    }
    return $Doc(root)
}

# Doc_AddRoot
#	Add a file system to the virtual document hierarchy
#
# Arguments:
#	virtual		The URL prefix of the document tree to add.
#	directory	The file system directory containing the doc tree.
#	args		Same as args for Url_PrefixInstall
#
# Results:
#	None
#
# Side Effects:
#	Sets up a document URL domain and the document-based access hook.

proc Doc_AddRoot {virtual directory args} {
    Doc_RegisterRoot $virtual $directory
    eval [list Url_PrefixInstall $virtual [list DocDomain $virtual $directory]] $args
    Url_AccessInstall DocAccessHook
    return
}

# Doc_RegisterRoot
#	Add a file system managed by any Domain Handler (e.g. CGI)
#	This is necessary for Doc_AccessControl to search directories right.
#
# Arguments:
#	virtual		The prefix of the URL
#	directory	The directory that corresponds to $virtual
#
# Results:
#	None
#
# Side Effects:
#	Registers the URL to directory mapping

proc Doc_RegisterRoot {virtual directory} {
    global Doc
    if {[info exist Doc(root,$virtual)] &&
	    [string compare $Doc(root,$virtual) $directory] != 0} {
	return -code error \
		"Doc_RegisterRoot will not change an existing url to directory mapping"
    }
    set Doc(root,$virtual) [file normalize $directory]
}

# Doc_Include
#
#	Read the contents of the file and substitute them at the stack level
#	at which this procedure was called.  Relative paths will be joined
#	with the directory at the top of the include stack in global variable
#	page(includeStack).
#
# Arguments:
#	filename	The relative path of the file to read.
#
# Results:
#	Returns the substituted contents of the file.
#
# Side Effects:
#	None.

proc Doc_Include {filename} {
    global page

    # Use the path at the top of the include stack.
    set oldIncludeStack $page(includeStack)
    set path [file join [lindex $oldIncludeStack 0] $filename]

    # Read the data from the file.
    ::set f [open $path]
    ::set data [read -nonewline $f]
    close $f

    # Call subst on the data in the stack frame above this one.

    # To support nested includes, we use a uniquely named
    # variable to store incremental results.
    ::set resultVar "__result_[expr rand()]"

    # Create the script to eval in the stack frame above this one.
    ::set script "append $resultVar \[subst \{$data\}\]"

    # Create a temporary variable in the stack frame above this one,
    # and use it to store the incremental resutls of the multiple loop
    # iterations.  Remove the temporary variable when we're done so there's
    # no trace of this loop left in that stack frame.
    upvar $resultVar tmp
    ::set tmp ""

    # Including of doc templates can be nested.
    # Push the directory of the file we are subst'ing onto the include stack.
    # Perform the substitution, and the pop that dir from the stack.
    set page(includeStack) [linsert $oldIncludeStack 0 [file dirname $path]]
    uplevel $script
    set page(includeStack) $oldIncludeStack

    ::set result $tmp
    unset tmp
    return $result
}

# Doc_PublicHtml --
#
# Enable URLS of the form ~user/a/b/c and map those to
# a subdirectory of that users account.
#
# Arguments:
#	homedir The directory under a user's home that is their
#		personal URL root.  Defaults to public_html.
#		If this is empty, then user home directories
#		are disabled.
#
# Results:
#	None
#
# Side Effects:
#	Sets the per-user public_html directory name.

proc Doc_PublicHtml {{homedir public_html}} {
    global Doc
    if {[string length $homedir] == 0} {
	catch {unset Doc(homedir)}
    } else {
	set Doc(homedir) [string trim $homedir /]
    }
}

# Doc_Virtual - return a real pathname corresponding to a 
# "virtual" path in an include
#
# Arguments:
#	sock	The client connection.
#	curfile	The pathname of the file that contains the
#		"virtual" URL spec.  This is used to resolve
#		relative URLs.
#	virtual	The URL we need the file name of.
#
# Results:
#	The file name corresponding to the URL.
#	If "" is returned, then the URL is invalid.
#
# Side Effects:
#	None

proc Doc_Virtual {sock curfile virtual} {
    global Doc
    if {[regexp ^~ $virtual]} {
	# This is UNIX-specific, so we don't need file joins
	if {![info exists Doc(homedir)]} {
	    return {}	;# Not allowed
	}
	set list [split $virtual /]
	set user [lindex $list 0]
	if {[catch {glob $user} homedir]} {
	    return {}	;# No such user
	}
	return $homedir/$Doc(homedir)/[join [lrange $list 1 end] /]
    }

    # Try to hook up the pathname under the appropriate document root

    if {[regexp ^/ $virtual]} {
	Url_PrefixMatch $virtual prefix suffix
	if {[info exist Doc(root,$prefix)]} {
	    return [file join $Doc(root,$prefix) [string trimleft $suffix /]]
	} else {
	    # Not a document domain, so there cannot be a file behind this url.

	    return {}
	}
    }

    # Non-absolute URL

    return [file join [file dirname $curfile] $virtual]
}

# DocAccessHook
#
#	Access handle for Doc domains.
#	This looks for special files in the file system that
#	determine access control.  This is registered via
#	Url_AccessInstall
#
# Arguments:
#	sock	Client connection
#	url	The full URL. We realy need the prefix/suffix, which
#		is stored for us in the connection state
#
# Results:
#	"denied", in which case an authorization challenge or
#	not found error has been returned.  Otherwise "skip"
#	which means other access checkers could be run, but
# 	most likely access will be granted.

proc DocAccessHook {sock url} {
    global Doc
    upvar #0 Httpd$sock data

    # Make sure the path doesn't sneak out via ..
    # This turns the URL suffix into a list of pathname components

    if {[catch {Url_PathCheck $data(suffix)} data(pathlist)]} {
	Doc_NotFound $sock
	return denied
    }

    # Figure out the directory corresponding to the domain, taking
    # into account other document roots.

    if {[info exist Doc(root,$data(prefix))]} {
	set directory $Doc(root,$data(prefix))
    } else {
	set directory [file join $Doc(root,/) [string trimleft $data(prefix) /]]
    }

    # Look for .htaccess and .tclaccess files along the path
    # If you wanted to have a time-limited cache of these
    # cookies you could save the cost of probing the file system
    # for these files on each URL.

    set cookie [Auth_Check $sock $directory $data(pathlist)]

    # Finally, check access

    if {![Auth_Verify $sock $cookie]} {
	return denied
    } else {
	return skip
    }
}

# DocDomain --
#
# Main handler for Doc domains (i.e. file systems)
# This looks around for a file and, if found, uses Doc_Handle
# to return the contents.
#
# Arguments:
#	prefix		The URL prefix of the domain.
#	directory	The directory containing teh domain.
#	sock		The socket connection.
#	suffix		The URL after the prefix.
#
# Results:
#	None
#
# Side Effects:
#	Dispatch to the document handler that is in charge
#	of generating an HTTP response.

proc DocDomain {prefix directory sock suffix} {
    global Doc
    upvar #0 Httpd$sock data

    # The pathlist has been checked and URL decoded by
    # DocAccess, so we ignore the suffix and recompute it.

    if {![info exists data(pathlist)]} {
	set data(pathlist) [Url_PathCheck $data(suffix)]
    }
    set pathlist $data(pathlist)
    set suffix [join $pathlist /]

    # Check for personal home pages

    if {[regexp ^~ $pathlist] && [info exists Doc(homedir)]} {

	set user [lindex $pathlist 0]
	if {[catch {glob $user} homedir]} {
	    Doc_NotFound $sock
	    return	;# No such user
	}

	set directory [file join $homedir $Doc(homedir)]
	if {![file isdirectory $directory]} {
	    Doc_NotFound $sock
	    return	;# No User's Public Directory
	}

	if {![file readable $directory]} {
	    Doc_NotFound $sock
	    return	;# No access to User's Public Directory
	}

	set pathlist [lrange $pathlist 1 end]
	set suffix [join $pathlist /]
    }

    # The file join here is subject to attacks that create absolute
    # pathnames outside the URL tree.  We trim left the / and ~
    # to prevent those attacks.

    set path [file join $directory [string trimleft $suffix /~]]
    set path [DocPathNormalize $path]
    set data(path) $path	;# record this path for not found handling
    set data(directory) $directory

    # Handle existing files
    return [Doc_Handle $prefix $path $suffix $sock]
}

# Doc_Return --
#
# Return a document from a URL.  Dispatch to the mime type handler, if defined.
#
# Arguments:
#	prefix	The URL prefix of the domain.
#	path	The file system pathname of the file.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Dispatch to the correct document handler.

proc Doc_Return {prefix path suffix sock} {
    upvar #0 Httpd$sock data

    # precise match - return file or dispatch to mime type handler
    CountName $data(url) hit

    switch [file type $path] {
	directory {
	    if {[string length $data(url)] && ![regexp /$ $data(url)]} {
		# Insist on the trailing slash
		Redirect_Dir $sock
		return
	    }

	    return [DirList_Directory $prefix $path $suffix $sock]
	}
 
	link {
	    set link [file readlink $path]
	    if {[file pathtype $link] == "relative"} {
		set link [file join [file dirname $path] $link]
	    }
	    return [Doc_Return $prefix $link $suffix $sock] 
	}

	default {
	    # Look for a Tcl procedure whose
	    # name matches the MIME Content-Type
	    if {[info exists data(contentType)]} {
		set ctype $data(contentType) ;# set by a template
	    } else {
		set ctype [Mtype $path]
	    }
	    
	    set cmd Doc_$ctype
	    if {[iscommand $cmd]} {
		# call the Mime type handler
		return [$cmd $path $suffix $sock]
	    } else {
		return [Httpd_ReturnFile $sock $ctype $path]
	    }
	}
    }
}

# Doc_Handle --
#
# Handle a document URL.  Dispatch to the mime type handler, if defined.
#
# Arguments:
#	prefix	The URL prefix of the domain.
#	path	The file system pathname of the file.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Dispatch to the correct document handler.

proc Doc_Handle {prefix path suffix sock} {
    upvar #0 Httpd$sock data

    # first we check if there's a template file to run, and run it
    # if there's a precise file match, we return it
    # otherwise we generate alternatives from the client's Accept
    # otherwise we leave it Cgi to try to satisfy the request

    # Look for a fresh template which generates the desired path
    if {[Template_Try $sock $path $suffix]} {
	# template has handled the request
	return 1
    }

    # Template_Try hasn't satisfied the request,
    # Look for an exact match.
    if {[file exists $path] && [file readable $path]} {
	# we have a file precisely matching the request
	Doc_Return $prefix $path $suffix $sock
	return 1
    }

    # Negotiate an Acceptable available alternative file
    # if one is found, a redirect is provoked
    # (FIXME: is this according to the spec?)
    if {[Fallback_Try $prefix $path $suffix $sock]} {
	# we have found an Accept-able alternative
	# Fallback_Try generates a redirect
	return 1
    }

    # Couldn't find any matches
    # check for cgi script in the middle of the path
    # will generate Doc_Notfound if necessary
    Cgi_Domain $prefix $data(directory) $sock $suffix

    return 1
}

# Doc_GetPath --
#	
#	Return a list of unique directories from domain root to a given path
#	Adjusts for Document roots and user directories
#
# Arguments:
#	sock		The client connection
#	file		The file endpoint of the path
# Results:
#	A list of directories from root to directory of $data(path)
#
# Side Effects:
#	None.

proc Doc_GetPath {sock {file ""}} {
    global Doc
    upvar #0 Httpd$sock data

    if {$file == ""} {
	set file $data(path)
    }

    # Start at the Doc_AddRoot point
    if {[info exist Doc(root,$data(prefix))]} {
	set root [file normalize $Doc(root,$data(prefix))]

	# always start in the rootdir
	set dirs $Doc(root)
    } else {
	set root $Doc(root,/)
	set dirs {}
    }

    set dirsplit [file split [file dirname $file]]
    if {[string match ${root}* $file]} {

	# Normal case of pathname under domain prefix

	set path $root
	set extra [lrange $dirsplit [llength [file split $root]] end]

    } elseif {[set hindex [lsearch -exact $dirsplit $Doc(homedir)]] >= 0} {
	
	# "public_html" is in the path, so we have been warped
	# to a user's URL tree.

	set path [eval file join [lrange $dirsplit 0 $hindex]]
	incr hindex
	set extra [lrange $dirsplit $hindex end]
    } else {
	# Don't know where we are - just use the current directory

	set path [file dirname $file] 
	set extra {}
    }

    foreach dir [concat [list {}] $extra] {
	set path [file join $path $dir]
	# Don't add duplicates to the list.
	if {[lsearch $dirs $path] == -1} {
	    lappend dirs $path
	}
    }

    return $dirs
}

# Helper routine for cleaning up file names
# Part of the context here is that "file exists" on Windows
# ignores trailing . in a pathname, leading to cute attacks

if {[catch {file normalize /a/b/../c/foo.tml.}]} {
  # No file normalize command
  if {$tcl_platform(platform) == "windows"} {
    proc DocPathNormalize {path} {
      return [string trimright $path .]
    }
  } else {
    proc DocPathNormalize {path} {
      return $path
    }
  }
} else {
  proc DocPathNormalize {path} {
    return [file normalize $path]
  }
}

# Compat routines with 3.4 routines

catch {interp alias {} Doc_Dynamic {} Template_Dynamic}
catch {interp alias {} Doc_Redirect {} Redirect_To}
catch {interp alias {} Doc_RedirectSelf {} Redirect_Self}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/doc_error.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# doc_error.tcl
#@c handlers for server errors and doc-not-found cases.
#
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: doc_error.tcl,v 1.7 2004/09/05 05:10:13 coldstore Exp $

package provide httpd::doc_error 1.0

package require httpd	;# Httpd_Error
package require httpd::counter	;# Count CountName
package require httpd::doc	;# Doc_Virtual
package require httpd::log	;# Log
package require httpd::subst	;# Subst_ReturnFile
package require httpd::utils	;# file lappendOnce protect_text

# Doc_NotFoundPage --
#
#@c Register a file not found error page.
#@c This page always gets "subst'ed, but without the fancy
#@c context of the ".tml" pages.
#@c
# Arguments:
#@a	virtual	The URL of the not-found page, e.g., /notfound.html
#
# Results:
#@r	None
#
# Side Effects:
#@e	Sets the not-found page.

proc Doc_NotFoundPage { virtual } {
    global Doc
    set Doc(page,notfound) [Doc_Virtual {} {} $virtual]
}

# Doc_ErrorPage --
#
#@c Register a server error page.
#@c This page always gets "subst'ed"
#
# Arguments:
#@a	virtual	The URL of the error page, e.g., /error.html
#
# Results:
#@r	None
#
# Side Effects:
#@e	Sets the error page.

proc Doc_ErrorPage { virtual } {
    global Doc
    set Doc(page,error) [Doc_Virtual {} {} $virtual]
}

# Doc_NotFound --
#
#@c	Called when a page is missing.  This looks for a handler page
#@c	and sets up a small amount of context for it.
#
# Arguments:
#@a	sock	The socket connection.
#
# Results:
#@r	None
#
# Side Effects:
#@e	Returns a page.

proc Doc_NotFound { sock } {
    global Doc Referer
    upvar #0 Httpd$sock data
    CountName $data(url) notfound
    set Doc(url,notfound) $data(url)	;# For subst
    if {[info exists data(mime,referer)]} {

	# Record the referring URL so we can track down
	# bad links

	lappendOnce Referer($data(url)) $data(mime,referer)
    }
    DocSubstSystemFile $sock notfound 404 [protect_text $Doc(url,notfound)]
}

# Doc_Error --
#
#@c	Called when an error has occurred processing the page.
#
# Arguments:
#@a	sock	The socket connection.
#	ei	errorInfo
#
# Results:
#@r	None
#
# Side Effects:
#@e	Returns a page.

proc Doc_Error { sock ei } {
    global Doc
    upvar #0 Httpd$sock data
    # Could have been reset!!!
    catch {
	set Doc(errorUrl) $data(url)
	set Doc(errorInfo) $ei	;# For subst
	CountName $Doc(errorUrl) errors
    }
    if {![info exists data(error_hook)] || [catch {$data(error_hook) $sock}]} {
	DocSubstSystemFile $sock error 500 [protect_text $ei]
    }
}

# DocSubstSystemFile --
#
#	Simple template processor for notfound and error pages.
#
# Arguments:
#	sock	The socket connection
#	key	Either "notfound" or "error"
#	code	HTTP code
#	extra 	Optional string to include in return page.
#	interp  Interp to use for Subst.
#
# Results:
#	None
#
# Side Effects:
#	Returns a page.

proc DocSubstSystemFile {sock key code {extra {}} {interp {}}} {
    global Doc env
    if {![info exists Doc(page,$key)]} {
	set path [Doc_Virtual {} {} /$key.html]
	if {[file exists $path]} {
	    set Doc(page,$key) $path
	}
    }
    if {![info exists Doc(page,$key)] || 
	[catch {Subst_ReturnFile $sock $Doc(page,$key) $interp} err]} {
	if {[info exists err]} {
	    Log $sock DocSubstSystemFile $err
	}
	Httpd_Error $sock $code $extra
    }
}

# Doc_ErrorInfo --
#
#@c Return the error information raised by this page
#
# Arguments:
#
# Results:
#@r	$Doc(errorInfo)
#
# Side Effects:
#@e	None

proc Doc_ErrorInfo {} {
    global Doc
    return $Doc(errorInfo)
}

# Doc_UrlNotFound --
#
#@c Return the url which was not found (in notfound handler)
#
# Arguments:
#
# Results:
#@r	$Doc(url,notfound)
#
# Side Effects:
#@e	None

proc Doc_UrlNotFound {} {
    global Doc
    return $Doc(url,notfound)
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































































































































Deleted lib/doctools.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# doctools.tcl
#
# tclllib doctools support

package provide httpd::doctools 1.0

if {[catch {package require doctools}]} {
    # tcllib's doctools package must be available
    return
}

package require httpd	;# Httpd_PostDataSize Httpd_ReturnData Httpd_ReturnFile
package require httpd::mtype	;# Mtype Mtype_Add
package require httpd::url	;# Url_ReadPost
#package require httpd::utils	;# file

# register the man suffix as a doctool application
set Doctools(suffix) .man
Mtype_Add $Doctools(suffix) application/x-doctool

# Doc_application/x-doctool --
#
# use doctools to format up and return an html document
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Sets up the interpreter context and runs doctools over the page
#	if necessary, to generate a cached version which is returned to the client.

proc Doc_application/x-doctool {path suffix sock} {

    # allow selection of doctool output types
    DoctoolsQuery $sock
    set format [ncgi::value format]
    if {$format == ""} {
	set format html
    }

    # check if a cached version exists and is newer
    if {[file exists ${path}.$format]} {
	set mtime [file mtime ${path}.$format]
	if {$mtime > [file mtime $path]} {
	    return [Httpd_ReturnFile $sock text/$format ${path}.$format]
	}
    }

    # generate the requested format
    set fd [open $path]
    ::doctools::new doctool -format $format
    if {[catch {doctool format [read $fd]} result]} {
    }
    doctool destroy
    close $fd

    # write the cached version
    if {![catch {set fd [open ${path}.$format w]}]} {
	puts $fd $result
	close $fd
	# return the file
	return [Httpd_ReturnFile $sock text/$format ${path}.$format]
    } else {
	# can't cache - return as data
	Httpd_ReturnData $sock text/$format $result
    }
}

# this should be a global facility somewhere
proc DoctoolsQuery {sock} {
    upvar #0 Httpd$sock data

    if {[Httpd_PostDataSize $sock] > 0 && ![info exists data(query)]} {
	set data(query) {}
    }
    if {[info exist data(query)]} {
	if {![info exist data(mime,content-type)] || $data(proto) == "GET"} {
	    
	    # The check against GET is because IE 5 has the following bug.
	    # If it does a POST with content-type multipart/form-data and
	    # keep-alive reuses the connection for a subsequent GET request,
	    # then the GET request erroneously has a content-type header
	    # that is a copy of the one from the previous POST!

	    set type application/x-www-urlencoded
	} else {
	    set type $data(mime,content-type)
	}

	# Read and append the pending post data to data(query).

	Url_ReadPost $sock data(query)

	# Initialize the Standard Tcl Library ncgi package so its
	# ncgi::value can be used to get the data.
	ncgi::reset $data(query) $type
	ncgi::parse
	ncgi::urlStub $data(url)
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































Deleted lib/fallback.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# fallback.tcl
#@c Fallback does "content negotation" if a file isn't found
#@c look around for files with different suffixes but the same root.
#
# NOTE: This feature is probably more trouble than it is worth.
# It was originally used to be able to choose between different
# iamge types (e.g., .gif and .jpg), but is now also used to
# find templates (.tml files) that correspond to .html files.
#
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: fallback.tcl,v 1.8 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::fallback 1.0

package require httpd::mtype	;# Mtype Mtype_Accept
package require httpd::redirect	;# Redirect_QuerySelf
package require httpd::template	;# Template_Choose
#package require httpd::utils	;# file

# Fallback_ExcludePat --
#
# Define a pattern of files names to exclude in Fallback
#
# Arguments:
#	patlist	A glob pattern of files to avoid when playing
#		games in FallBack to find an alternative file.
#
# Results:
#	None
#
# Side Effects:
#	Sets the exclude pattern.

proc Fallback_ExcludePat {patlist} {
    global Fallback
    set Fallback(excludePat) $patlist
}
if {![info exists Fallback(excludePat)]} {
    set Fallback(excludePat) {*.bak *.swp *~}
}

# Fallback_Try
#
# Try to find an file which matches the HTTP Accept alternatives
# given by the client.
#
# Arguments:
#	prefix	The URL prefix of the domain.
#	path	The pathname we were trying to find.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	This either triggers an HTTP redirect to switch the user
#	to the correct file name, or it calls out to the template-aware
#	text/html processor.

proc Fallback_Try {virtual path suffix sock} {
    set root [file root $path]
    if {[string match */ $root]} {
	# Input is something like /a/b/.xyz
	return 0
    }

    # Look for files indicated by any Accept headers.
    # Most browsers say */*, but they may provide some ordering info, too.

    # First generate a list of candidate files by ignoring extension
    global Template	;# we need the template extension here
    set ok {}
    foreach choice [glob -nocomplain $root.*] {
	# don't let "foo.html.old" match for "foo.html"
	# but let foo.*.tml match for foo.*
	if {[string equal $root [file root $choice]]
	    || [string equal [file extension $choice] $Template(tmlExt)]} {

	    # Filter on the exclude patterns
	    if {![FallbackExclude $choice]} {
		lappend ok $choice
	    }
	}
    }

    # Now we pick the best file from the files and templates that matched
    # Template_Choose will return us the best possible match
    # the best match might not yet exist, but may be able to be generated 
    # from a template, which will be handled after the redirection we provoke
    set npath [Template_Choose [Mtype_Accept $sock] $ok]
    if {[string length $npath] == 0} {
	# there was no viable alternative
	return 0
    } elseif {[string compare $path $npath] == 0} {
	# the best alternative was the original path requested
	# FIXME: this is bogus - we shouldn't even be called if there's a match
	return 0
    } else {
	# A file matched with a different extension to that requested
	# (if the match was a template, we offer the untemplated name.)

	# Redirect_to/offer our best match.
	# Redirect so we don't mask spelling errors like john.osterhoot

	set new [file extension $npath]	;# candidate extension
	set old [file extension $suffix]	;# requested extension
	if {[string length $old] == 0} {
	    append suffix $new	;# client request was without extension
	} else {
	    # client requested foo.$old, we're offering foo.$new
	    # Watch out for specials in $old, like .html)
	    # FIXME: the following seems bogus and heavyweight
	    # if there's an element in the path which happens to match the ext,
	    # we will subst it too, which can't be a good thing.
	    # we should really decompose the path and reconstruct it.
	    regsub -all {[][$^|().*+?\\]} $old {\\&} old ;# quote special chars
	    regsub $old\$ $suffix $new suffix	;# substitute $new for $old
	}

	# Offer alternative to the client by redirection, preserving query data
	Redirect_QuerySelf $sock "$virtual[string trimleft $suffix /~]"
	return 1	;# we have completely handled the request.
    }
}

# FallbackExclude --
#
# This is used to filter out files like "foo.bak"  and foo~
# from the Fallback failover code
#
# Arguments:
#	name	The filename to filter.
#
# Results:
#	1	If the file should be excluded, 0 otherwise.
#
# Side Effects:
#	None

proc FallbackExclude {name} {
    global Fallback
    foreach pat $Fallback(excludePat) {
	if {[string match $pat $name]} {
	    return 1
	}
    }
    return 0
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































Deleted lib/httpd.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
# httpd.tcl --
#
# HTTP 1.0 protocol stack, plus connection keep-alive and 1.1 subset.
# This accepts connections and calls out to Url_Dispatch once a request
# has been recieved.  There are several utilities for returning
# different errors, redirects, challenges, files, and data.
#
# For binary data transfer this uses unsupported0 or fcopy.
# Tcl8.0a2 was the last release with unsupported0.
# Note that Tcl8.0b1 has a bug in fcopy where if an error occurs then
# bgerror is called instead of the command callback to fcopy.  This
# causes file descriptor leaks, so don't use 8.0b1 for real servers.
#
# For async operation, such as long-lasting server-side operations use
# Httpd_Suspend.
#
# Copyright
# Matt Newman (c) 1999 Novadigm Inc.
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# Brent Welch (c) 2001-2004 Panasas Inc
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: httpd.tcl,v 1.90 2005/02/26 02:33:31 coldstore Exp $

package provide httpd 1.7

package require httpd::config	;# Config config::cget config::init
package require httpd::counter	;# Count CountHist CountStart CountStop
package require httpd::log	;# Log Log_Flush Log_FlushMinutes Log_SetFile
package require httpd::logstd	;# LogValue
package require httpd::redirect	;# Redirect_Dir
package require httpd::threadmgr	;# Thread_Enabled Thread_Init Thread_Respond
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_Dispatch Url_PostHook
package require httpd::utils	;# K Stderr file protect_text
package require httpd::version	;# Httpd_Version

# initialize all the global data

# Location of this package
set Httpd(library) [file dirname [info script]]

# HTTP/1.0 error codes (the ones we use)
array set Httpd_Errors {
    200 {Data follows}
    204 {No Content}
    302 {Found}
    304 {Not Modified}
    400 {Bad Request}
    401 {Authorization Required}
    403 {Permission denied}
    404 {Not Found}
    408 {Request Timeout}
    411 {Length Required}
    419 {Expectation Failed}
    500 {Server Internal Error}
    501 {Server Busy}
    503 {Service Unavailable}
    504 {Service Temporarily Unavailable}
}
# Environment variables that are extracted from the mime header
# by Cgi_SetEnv.  The values are keys into the
# per-connection state array (i.e. "data")

array set Httpd_EnvMap {
    CONTENT_LENGTH	mime,content-length
    CONTENT_TYPE	mime,content-type
    HTTP_ACCEPT		mime,accept
    HTTP_AUTHORIZATION	mime,authorization
    HTTP_FROM		mime,from
    HTTP_REFERER	mime,referer
    HTTP_USER_AGENT	mime,user-agent
    QUERY_STRING	query
    REQUEST_METHOD	proto
    HTTP_COOKIE         mime,cookie
    HTTP_FORWARDED      mime,forwarded
    HTTP_HOST           mime,host
    HTTP_PROXY_CONNECTION mime,proxy-connection
    REMOTE_USER		remote_user
    AUTH_TYPE		auth_type
}

# The per-connection state is kept in the "data" array, which is
# really an array named Httpd$sock - (note the upvar #0 trick throughout)
# The elements of this array are documented here.  URL implementations
# are free to hang additional state off the data array so long as they
# do not clobber the elements documented here:

# These fields are semi-public, or "well known".  There are a few
# API's to access them, but URL implementations can rely on these:
#
# self		A list of protocol (http or https), name, and port that
#		capture the server-side of the socket address
#		Available with  Httpd_Protocol, Httpd_Name, and Httpd_Port API.
# uri		The complete URL, including proto, servername, and query
# proto		http or https
# url		The URL after the server name and before the ?
# query		The URL after the ?
# ipaddr	The remote client's IP address
# cert		Client certificate (The result of tls::status)
# host		The host specified in the URL, if any (proxy case)
# port		The port specified in the URL, if any
# mime,*	HTTP header request lines (e.g., mime,content-type)
# count		Content-Length
# set-cookie	List of Set-Cookie headers to stick into the response
#		Use Httpd_SetCookie to append to this.
# headers		List of http headers to stick into the response
#		Use Httpd_AddHeaders to append to this.

# prefix	(Set by Url_Dispatch to be the URL domain prefix)
# suffix	(Set by Url_Dispatch to be the URL domain suffix)

# auth_type	(Set by the auth.tcl module to "Basic", etc.)
# remote_user	(Set by the auth.tcl to username from Basic authentication)
# session	(Set by the auth.tcl to "realm,$username" from Basic auth)
#		You can overwrite this session ID with something more useful

# Internal fields used by this module.
# left		The number of keep-alive connections allowed
# cancel	AfterID of event that will terminate the connection on timeout
# state		State of request processing
# version	1.0 or 1.1
# line		The current line of the HTTP request
# mimeorder	List indicating order of MIME header lines
# key		Current header key
# checkNewLine	State bit for Netscape SSL newline bug hack
# callback	Command to invoke when request has completed
# file_size	Size of file returned by ReturnFile
# infile	Open file used by fcopy to return a file, or CGI pipe
# filter	List of http post-generation filter procs to apply to content
# path	normalized path to Doc file (set by doc.tcl)

# Httpd_Init
#	Initialize the httpd module.  Call this early, before Httpd_Server.
#
# Arguments:
#	none
#
# Side Effects:
#	Initialize the global Httpd array.
# bufsize:	Chunk size for copies
# initialized:	True after server started.
# ipaddr:	Non-default ipaddr for the server (for multiple interfaces)
# library:	a directory containing the tcl scripts.
# port:		The port this server is serving
# listen:	the main listening socket id
# server:	The server ID for the HTTP protocol.
# shutdown:	A list of Tcl callbacks made when the server shuts down
# sockblock:	blocking mode value for sockets (normally this should be 0)
# timeout1:	Time before the server closes a kept-alive socket (msecs)
# timeout2:	Time before the server kills an in-progress transaction.  (msecs)
# timeout3:	Time allowed to drain extra post data
# version:	The version number.
# maxused:	Max number of transactions per socket (keep alive)

proc Httpd_Init {} {
    global Httpd
    array set Httpd {
	timeout1	120000
	timeout2	120000
	timeout3	2000
	server		"Tcl-Webserver/"
	initialized 	1
	shutdown	""
	sockblock	0
	bufsize		16384
	maxused		25
    }
    if {![info exist Httpd(maxthreads)]} {
	set Httpd(maxthreads) 0
    }
    Httpd_Version
    append Httpd(server) $Httpd(version)
}

# Httpd_Server --
#	Start the server by listening for connections on the desired port.
#	This may be re-run to re-start the server.  Call this late,
# 	fter Httpd_Init and the init calls for the other modules.
#
# Arguments:
#	port	The TCP listening port number
#	name	The qualified host name returned in the Host field.  Defaults
#		to [info hostname]
#	ipaddr	Non-default interface address.  Otherwise IP_ADDR_ANY is used
#		so the server can accept connections from any interface.
#
# Results:
#	none
#
# Side Effects:
#	This sets up a callback to HttpdAccept for new connections.

proc Httpd_Server {{port 80} {name {}} {ipaddr {}}} {
    global Httpd

    if {![info exists Httpd(initialized)]} {
	Httpd_Init
    }
    catch {close $Httpd(listen)}
    set Httpd(name) $name
    set Httpd(ipaddr) $ipaddr
    set Httpd(port) $port
    if {[string length $name] == 0} {
	set Httpd(name) [info hostname]
    }
    set cmd [list socket -server [list HttpdAccept \
	    [list http $name $port]]]
    if {[string length $ipaddr] != 0} {
        lappend cmd -myaddr $ipaddr
    }
    lappend cmd $port
    if {[catch $cmd Httpd(listen)]} {
        return -code error "$Httpd(name):$port $Httpd(listen)\ncmd=$cmd"
    }
}

# Httpd_ServerShutdown --
#
#	Close the server's HTTP socket.
#
# Arguments:
#	none
#
# Results:
#	Returns "" if the socket was successfully closed, otherwise an error string.
#
# Side Effects:
#	Close the server's HTTP listening socket.

proc Httpd_ServerShutdown {} {
    global Httpd
    Log {} ShutdownSocket
    catch {close $Httpd(listen)} err
    return $err
}

proc Httpd_VirtualHost {host file} {
    return [Httpd_VirtualHosts [list $host] $file]
}

proc Httpd_VirtualHosts {hostNames file} {
    variable virtual

    foreach host $hostNames {
        set host [string tolower $host]
        if {[info exists virtual($host)]} {
	    error "Virtual host $host already exists"
        }
    }
    set slave [interp create]

    # Transfer the scalar global variables
    foreach var {::v ::auto_path} {
	$slave eval [list set $var [set $var]]
    }
    # Transfer the array global variables
    foreach arr {::Config ::Httpd} {
	$slave eval [list array set $arr [array get $arr]]
    }
    $slave eval [list array set ::Httpd [list name $host]]
    # Load the packages
    $slave eval package require httpd [package provide httpd]
    foreach pkg {version utils counter config} {
	$slave eval \
		package require httpd::$pkg [package provide httpd::$pkg]
    }
    $slave eval [list array set Config [list config $file host $host]]
    $slave eval {
	config::init $Config(config) Config
	namespace import config::cget

	# This replaces the command line processing
	array set Config [array get config::Config]

	if {[string length $Config(library)] &&
		[lsearch -exact $auto_path $Config(library)] == -1} {
	    lappend auto_path $Config(library)
	}
	Httpd_Init

	if {$Config(threads) > 0} {
	    package require Thread		;# C extension
	    package require httpd::threadmgr	;# Tcl layer on top
	    Thread_Init $Config(threads)
	} else {
	    # Stub out Thread_Respond so threadmgr isn't required
	    proc Thread_Respond {args} {return 0}
	    proc Thread_Enabled {} {return 0}
	}
	source $Config(main)
	Log_SetFile		[cget LogFile]$Config(port)_
	Log_FlushMinutes	[cget LogFlushMinutes]
	Log_Flush
    }

    foreach host $hostNames {
        set host [string tolower $host]
	set virtual($host) $slave
    }

}

# Httpd_SecureServer --
#
#	Like Httpd_Server, but with additional setup for SSL.
#	This requires the TLS extension.
#
# Arguments:
#	port	The TCP listening port number
#	name	The qualified host name returned in the Host field.  Defaults
#		to [info hostname]
#	ipaddr	Non-default interface address.  Otherwise IP_ADDR_ANY is used
#		so the server can accept connections from any interface.
#
# Results:
#	none
#
# Side Effects:
#	This sets up a callback to HttpdAccept for new connections.

proc Httpd_SecureServer {{port 443} {name {}} {ipaddr {}}} {
    global Httpd

    if {![info exists Httpd(initialized)]} {
	Httpd_Init
    }
    catch {close $Httpd(https_listen)}
    set Httpd(name) $name
    set Httpd(https_ipaddr) $ipaddr
    set Httpd(https_port) $port
    if {[string length $name] == 0} {
	set Httpd(name) [info hostname]
    }
    package require tls

    # This now depends on a call to tls::init being made elsewhere, typically
    # in the main startup script.  That call sets all the various SSL parameters
    # based on the server's configuration file.

    set cmd [list tls::socket -server [list HttpdAccept \
	    [list https $name $port]]]
    if {[string length $ipaddr] != 0} {
        lappend cmd -myaddr $ipaddr
    }
    lappend cmd $port
    if {[catch $cmd Httpd(https_listen)]} {
        return -code error "$Httpd(name):$port $Httpd(https_listen)\ncmd=$cmd"
    }
}

# Httpd_SecureServerShutdown --
#
#	Close the server's secure socket.
#
# Arguments:
#	none
#
# Results:
#	Returns "" if the socket was successfully closed, otherwise an error string.
#
# Side Effects:
#	Close the server's HTTPS listening socket.

proc Httpd_SecureServerShutdown {} {
    global Httpd
    Log {} ShutdownSecureSocket
    catch {close $Httpd(https_listen)} err
    return $err
}

# Httpd_Shutdown --
#
#	Kill the server gracefully
#
# Arguments:
#	none
#
# Results:
#	none
#
# Side Effects:
#	Close the server listening socket(s)
#	Invoke any registered shutdown procedures.

proc Httpd_Shutdown {} {
    global Httpd
    variable virtual
    set ok 1
    foreach host [array names virtual] {
	$virtual($host) eval Httpd_Shutdown
    }
    foreach handler $Httpd(shutdown) {
	if {[catch {eval $handler} err]} {
	    Log "" "Shutdown: $handler" $err
	    set ok 0
	}
    }
    Log {} Shutdown
    Httpd_ServerShutdown
    Httpd_SecureServerShutdown
    return $ok
}

# Httpd_RegisterShutdown --
#
#	Register a Tcl command to be called by Httpd_Shutdown
#
# Arguments:
#	cmd	The command to eval from Httpd_Shutdown
#
# Results:
#	none
#
# Side Effects:
#	Save the callback.

proc Httpd_RegisterShutdown {cmd} {
    global Httpd
    if {[lsearch $Httpd(shutdown) $cmd] < 0} {
	lappend Httpd(shutdown) $cmd
    }
}

# HttpdAccept --
#
#	This is the socket accept callback invoked by Tcl when
#	clients connect to the server.
#
# Arguments:
#	self	A list of {protocol name port} that identifies the server
#	sock	The new socket connection
#	ipaddr	The client's IP address
#	port	The client's port
#
# Results:
#	none
#
# Side Effects:
#	Set up a handler, HttpdRead, to read the request from the client.
#	The per-connection state is kept in Httpd$sock, (e.g., Httpdsock6),
#	and upvar is used to create a local "data" alias for this global array.

proc HttpdAccept {self sock ipaddr port} {
    global Httpd
    upvar #0 Httpd$sock data

    Count accepts
    Count sockets
    set data(self) $self
    set data(ipaddr) $ipaddr
    if {[Httpd_Protocol $sock] == "https"} {
	
	# There is still a lengthy handshake that must occur.
	# We do that by calling tls::handshake in a fileevent
	# until it is complete, or an error occurs.

	Count accept_https
	fconfigure $sock -blocking 0
	fileevent $sock readable [list HttpdHandshake $sock]
    } else {
	HttpdReset $sock $Httpd(maxused)
    }
}

# HttpdHandshake --
#
#	Complete the SSL handshake. This is called from a fileevent
#	on a new https connection.  It calls tls::handshake until done.
#
# Arguments:
#	sock	The socket connection
#
# Results:
#	none
#
# Side Effects:
#	If the handshake fails, close the connection.
#	Otherwise, call HttpdReset to set up the normal HTTP protocol.

proc HttpdHandshake {sock} {
    upvar #0 Httpd$sock data
    global Httpd errorCode
	
    if {[catch {tls::handshake $sock} complete]} {
	if {[lindex $errorCode 1] == "EAGAIN"} {
	    # This seems to occur normally on UNIX systems
	    return
	}
	Log $sock "HttpdHandshake" "\{$data(self)\} $sock \
	    $data(ipaddr) $complete"
	Httpd_SockClose $sock 1 "$complete"
    } elseif {$complete} {
	set data(cert) [tls::status $sock]
	HttpdReset $sock $Httpd(maxused)
    }
}

# HttpdReset --
#
#	Initialize or reset the socket state.
#	We allow multiple transactions per socket (keep alive).
#
# Arguments:
#	sock	The socket connection
#	left	(optional) The keepalive connection count.
#
# Results:
#	none
#
# Side Effects:
#	Resets the "data" array.
#	Cancels any after events.
#	Closes the socket upon error or if the reuse counter goes to 0.
#	Sets up the fileevent for HttpdRead

proc HttpdReset {sock {left {}}} {
    global Httpd
    upvar #0 Httpd$sock data

    if {[catch {
	flush $sock
    } err]} {
	Httpd_SockClose $sock 1 $err
	return
    }
    Count connections

    # Count down transactions.

    if {[string length $left]} {
	set data(left) $left
    } else {
	set left [incr data(left) -1]
    }
    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
    }

    # Clear out (most of) the data array.

    set ipaddr $data(ipaddr)
    set self $data(self)
    if {[info exist data(cert)]} {
	set cert $data(cert)
    }
    unset data
    array set data [list state start version 0 \
	    left $left ipaddr $ipaddr self $self]
    if {[info exist cert]} {
	set data(cert) $cert
    }

    # Set up a timer to close the socket if the next request
    # is not completed soon enough.  The request has already
    # been started, but a bad URL domain might not finish.

    set data(cancel) [after $Httpd(timeout1) \
	[list Httpd_SockClose $sock 1 "timeout"]]
    fconfigure $sock -blocking 0 -buffersize $Httpd(bufsize) \
	-translation {auto crlf}
    fileevent $sock readable [list HttpdRead $sock]
    fileevent $sock writable {}
}

# Httpd_Peername --
#
# Really need to fix the core to support DNS lookups.
# This routine is not used anywhere.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	The clients dns name.
#
# Side Effects:
#	None

proc Httpd_Peername {sock} {
    # This is expensive!
    fconfigure $sock -peername
}

# HttpdRead --
#
# Read request from a client.  This is the main state machine
# for the protocol.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Reads the request from the socket and dispatches the
#	URL request when ready.

proc HttpdRead {sock} {
    global Httpd
    upvar #0 Httpd$sock data

    # Use line mode to read the request and the mime headers

    if {[catch {gets $sock line} readCount]} {
	Httpd_SockClose $sock 1 "read error: $readCount"
	return
    }

    # State machine is a function of our state variable:
    #	start: the connection is new
    #	mime: we are reading the protocol headers
    # and how much was read. Note that
    # [string compare $readCount 0] maps -1 to -1, 0 to 0, and > 0 to 1
    set state [string compare $readCount 0],$data(state)

    switch -glob -- $state {
	1,start	{
	    if {[regexp {^([^ ]+) +([^?]+)\??([^ ]*) +HTTP/(1.[01])} \
		    $line x data(proto) data(url) data(query) data(version)]} {
		
		# data(uri) is the complete URI

		set data(uri) $data(url)
		if {[string length $data(query)]} {
		    append data(uri) ?$data(query)
		}

		# Strip leading http://server and look for the proxy case.

		if {[regexp {^https?://([^/:]+)(:([0-9]+))?(.*)$} $data(url) \
			x xserv y xport urlstub]} {
		    set myname [Httpd_Name $sock]
		    set myport [Httpd_Port $sock]
		    if {([string compare \
			    [string tolower $xserv] \
			    [string tolower $myname]] != 0) ||
			    ($myport != $xport)} {
			set data(host) $xserv
			set data(port) $xport
		    }
		    # Strip it out if it is for us (i.e., redundant)
		    # This makes it easier for doc handlers to
		    # look at the "url"
		    set data(url) $urlstub
		}
		set data(state) mime
		set data(line) $line
		CountHist urlhits

		# Limit the time allowed to serve this request

		if {[info exists data(cancel)]} {
		    after cancel $data(cancel)
		}
		set data(cancel) [after $Httpd(timeout2) \
		    [list HttpdCancel $sock]]
	    } else {
		# Could check for FTP requests, here...
		Log $sock HttpError $line
		Httpd_SockClose $sock 1
	    }
	}
	0,start {
	    # This can happen in between requests.
	}
	1,mime	{
	    # This regexp picks up
	    # key: value
	    # MIME headers.  MIME headers may be continue with a line
	    # that starts with spaces.
	    if {[regexp {^([^ :]+):[ 	]*(.*)} $line dummy key value]} {

                # The following allows something to
                # recreate the headers exactly

                lappend data(headerlist) $key $value

                # The rest of this makes it easier to pick out
                # headers from the data(mime,headername) array

		set key [string tolower $key]
		if {[info exists data(mime,$key)]} {
		    append data(mime,$key) ,$value
		} else {
		    set data(mime,$key) $value
		    lappend data(mimeorder) $key
		}
		set data(key) $key

	    } elseif {[regexp {^[ 	]+(.*)}  $line dummy value]} {
		# Are there really continuation lines in the spec?
		if {[info exists data(key)]} {
		    append data(mime,$data(key)) " " $value
		} else {
		    Httpd_Error $sock 400 $line
		}
	    } else {
		Httpd_Error $sock 400 $line
	    }
	    # Check for virtual host
	    variable virtual
	    if {[string compare host $key]} {return}
	    set host [lindex [split [string tolower $value] :] 0]
	    if {[catch {set virtual($host)} i]} {return}

	    # Transfer $sock to interp $i
	    fileevent $sock readable {}
	    interp transfer {} $sock $i
	    set data(self) [list [Httpd_Protocol $sock] \
		    $host [Httpd_Port $sock]]
	    if {[info exists data(cancel)]} {
		after cancel $data(cancel)
		unset data(cancel)
	    }
	    $i eval [list array set Httpd$sock [array get data]]
	    unset data
	    $i eval [list fileevent $sock readable [list HttpdRead $sock]]
	    set tmp [$i eval [list \
		    after $Httpd(timeout2) [list HttpdCancel $sock]]]
	    $i eval [list array set Httpd$sock [list cancel $tmp]]
	}
	0,mime	{
	    if {$data(proto) == "POST"} {
		fconfigure $sock  -translation {binary crlf}
		if {![info exists data(mime,content-length)]} {
		    Httpd_Error $sock 411
		    return
		}
		set data(count) $data(mime,content-length)
		if {$data(version) >= 1.1 && [info exists data(mime,expect)]} {
		    if {$data(mime,expect) == "100-continue"} {
			puts $sock "100 Continue HTTP/1.1\n"
			flush $sock
		    } else {
			Httpd_Error $sock 419 $data(mime,expect)
			return
		    }
		}

		# Flag the need to check for an extra newline
		# in SSL connections by some browsers.

		set data(checkNewline) 1

		# Facilitate a backdoor hook between Url_DecodeQuery
		# where it will read the post data on behalf of the
		# domain handler in the case where the domain handler
		# doesn't use an Httpd call to read the post data itself.

		Url_PostHook $sock $data(count)
	    } else {
		Url_PostHook $sock 0    ;# Clear any left-over hook
		set data(count) 0
	    }

	    # Disabling this fileevent makes it possible to use
	    # http::geturl in domain handlers reliably

	    fileevent $sock readable {}

	    # The use of HTTP_CHANNEL is a disgusting hack.

	    set ::env(HTTP_CHANNEL) $sock

	    # Do a different dispatch for proxies.  By default, no proxy.

	    if {[info exist data(host)]} {
		if {[catch {
		    Proxy_Dispatch $sock
		} err]} {
		    Httpd_Error $sock 400 "No proxy support\n$err"
		}
	    } else {
		# Dispatch to the URL implementation.

		# As a service for domains that loose track of their
		# context (e.g., .tml pages) we save the socket in a global.
		# If a domain implementation would block and re-enter the
		# event loop, it must use Httpd_Suspend to clear this state,
		# and use Httpd_Resume later to restore it.

		set Httpd(currentSocket) $sock
		CountStart serviceTime $sock
		Url_Dispatch $sock
	    }
	}
	-1,* {
	    if {[fblocked $sock]} {
		# Blocked before getting a whole line
		return
	    }
	    if {[eof $sock]} {
		Httpd_SockClose $sock 1 ""
		return
	    }
	}
	default {
	    Httpd_Error $sock 404 "$state ?? [expr {[eof $sock] ? "EOF" : ""}]"
	}
    }
}

# Httpd_PostDataSize --
#
# Arguments:
#	sock	Client connection
#
# Results:
#	The amount of post data available.

proc Httpd_PostDataSize {sock} {
    upvar #0 Httpd$sock data

    return $data(count)
}

# Httpd_GetPostData --
#
# Arguments:
#	sock	Client connection
#	varName	Name of buffer variable to append post data to
#	size	Amount of data to read this call. -1 to read all available.
#
# Results:
#	The amount of data left to read.  When this goes to zero, you are done.

proc Httpd_GetPostData {sock varName {size -1}} {
    global Httpd
    upvar #0 Httpd$sock data
    upvar 1 $varName buffer

    if {$size < 0} {
	set size $Httpd(bufsize)
    }
    HttpdReadPost $sock buffer $size
    return $data(count)
}

# Httpd_ReadPostDataAsync --
#
#	Convenience layer on Http-GetPostDataAsync to
#	read the POST data into a the data(query) variable.
#
# Arguments:
#	(Same as HttpdReadPost)
#
# Side Effects:
#	(See Httpd_GetPostDataAsync)

proc Httpd_ReadPostDataAsync {sock cmd} {
    global Httpd
    upvar #0 Httpd$sock data
    if {[string length $data(query)]} {
	# This merges query data from the GET/POST URL
	append data(query) &
    }
    Httpd_Suspend $sock
    fileevent $sock readable [list HttpdReadPostGlobal $sock \
	    Httpd${sock}(query) $Httpd(bufsize) $cmd]
    return
}

# Httpd_GetPostDataAsync --
#
#	Read the POST data into a Tcl variable, but do it in the
#	background so the server doesn't block on the socket.
#
# Arguments:
#	(Same as HttpdReadPost)
#
# Side Effects:
#	This schedules a readable fileevent to read all the POST data
#	asynchronously.  The data is appened to the named variable.
#	The callback is made 

proc Httpd_GetPostDataAsync {sock varName blockSize cmd} {
    Httpd_Suspend $sock
    fileevent $sock readable \
	[list HttpdReadPostGlobal $sock $varName $blockSize $cmd]
    return
}

# HttpdReadPostGlobal --
#
# This fileevent callback can only access a global variable.
# But HttpdReadPost needs to affect a local variable in its
# caller so it can be shared with Httpd_GetPostData.
# So, the fileevent case has an extra procedure frame.
#
# Arguments:
#	(Same as HttpdReadPost)
#
# Results:
#	None
#
# Side Effects:
#	Accumulates POST data into the named variable

proc HttpdReadPostGlobal {sock varName blockSize {cmd {}}} {
    upvar #0 $varName buffer
    HttpdReadPost $sock buffer $blockSize $cmd
}

# HttpdReadPost --
#
#	The core procedure that reads post data and accumulates it
#	into a Tcl variable.
#
# Arguments:
#	sock	Client connection
#	varName	Name of buffer variable to append post data to.  This
#		must be a global or fully scoped namespace variable, or
#		this can be the empty string, in which case the data
#		is discarded.
#	blockSize	Default read block size.
#	cmd	Callback to make when the post data has been read.
#		It is called like this:
#		cmd $sock $varName $errorString
#		Where the errorString is only passed if an error occurred.
#
# Results:
#	None
#
# Side Effects:
#	Consumes post data and appends it to a variable.

proc HttpdReadPost {sock varName blockSize {cmd {}}} {
    global Httpd
    upvar #0 Httpd$sock data

    # Ensure that the variable, if specified, exists by appending "" to it

    if {[string length $varName]} {
	upvar 1 $varName buffer
	append buffer ""
    }

    if {[eof $sock]} {
	if {$data(count)} {
	    set doneMsg "Short read: got [string length $buffer] bytes,\
		expected $data(count) more bytes"
	    set data(count) 0
	} else {
	    set doneMsg ""
	}
    } else {
	if {[info exist data(checkNewline)]} {

	    # Gobble a single leading \n from the POST data
	    # This is generated by various versions of Netscape
	    # when using https/SSL.  This extra \n is not counted
	    # in the content-length (thanks!)

	    set nl [read $sock 1]
	    if {[string compare $nl \n] != 0} {

		# It was not an extra newline.

		incr data(count) -1
		if {[info exist buffer]} {
		    append buffer $nl
		}
	    }
	    unset data(checkNewline)
	}
	set toRead [expr {$data(count) > $blockSize ? \
		$blockSize : $data(count)}]
	if {[catch {read $sock $toRead} block]} {
	    set doneMsg $block
	    set data(count) 0
	} else {
	    if {[info exist buffer]} {
		append buffer $block
	    }

	    set data(count) [expr {$data(count) - [string length $block]}]
	    if {$data(count) == 0} {
		set doneMsg ""
	    }
	}
    }
    if {[info exist doneMsg]} {
	Url_PostHook $sock 0
	catch {fileevent $sock readable {}}
	Httpd_Resume $sock
	if {[string length $cmd]} {
	    eval $cmd [list $sock $varName $doneMsg]
	}
	return $doneMsg
    } else {
	return ""
    }
}

# Httpd_CopyPostData --
#
#	Copy the POST data to a channel and make a callback when that
#	has completed.
#
# Arguments:
#	sock	Client connection
#	channel	Channel, e.g., to a local file or to a proxy socket.
#	cmd	Callback to make when the post data has been read.
#		It is called like this:
#		    cmd $sock $channel $bytes $errorString
#		Bytes is the number of bytes transferred by fcopy.
#		errorString is only passed if an error occurred,
#		otherwise it is an empty string
#
# Side Effects:
#	This uses fcopy to transfer the data from the socket to the channel.

proc Httpd_CopyPostData {sock channel cmd} {
    upvar #0 Httpd$sock data
    fcopy $sock $channel -size $data(count) \
    	-command [concat $cmd $sock $channel]
    Url_PostHook $sock 0
    return
}

# Httpd_GetPostChannel --
#
# Arguments:
#	sock		Client connection
#	sizeName	Name of variable to get the amount of post
#			data expected to be read from the channel
#
# Results:
#	The socket, as long as there is POST data to read

proc Httpd_GetPostChannel {sock sizeName} {
    upvar #0 Httpd$sock data
    upvar 1 $sizeName size

    if {$data(count) == 0} {
	error "no post data"
    }
    set size $data(count)
    return $sock
}

# The following are several routines that return replies

# HttpdCloseP --
#	See if we should close the socket
#
# Arguments:
#	sock	the connection handle
#
# Results:
#	1 if the connection should be closed now, 0 if keep-alive

proc HttpdCloseP {sock} {
    upvar #0 Httpd$sock data

    if {[info exists data(mime,connection)]} {
	if {[string tolower $data(mime,connection)] == "keep-alive"} {
	    Count keepalive
	    set close 0
	} else {
	    Count connclose
	    set close 1
	}
    } elseif {[info exists data(mime,proxy-connection)]} {
	if {[string tolower $data(mime,proxy-connection)] == "keep-alive"} {
	    Count keepalive
	    set close 0
	} else {
	    Count connclose
	    set close 1
	}
    } elseif {$data(version) >= 1.1} {
	Count http1.1
    	set close 0
    } else {
	# HTTP/1.0
	Count http1.0
	set close 1
    }
    if {[expr {$data(left) == 0}]} {
	# Exceeded transactions per connection
	Count noneleft
    	set close 1
    }
    return $close
}

# Httpd_CompletionCallback --
#
#	Register a procedure to be called when an HTTP request is
#	completed, either normally or forcibly closed.  This gives a
#	URL implementation a guaranteed callback to clean up or log
#	requests.
#
# Arguments:
#	sock	The connection handle
#	cmd	The callback to make.  These arguments are added:
#		sock - the connection
#		errmsg - An empty string, or an error message.
#
# Side Effects:
# 	Registers the callback

proc Httpd_CompletionCallback {sock cmd} {
    upvar #0 Httpd$sock data
    set data(callback) $cmd
}

# HttpdDoCallback --
#
#	Invoke the completion callback.
#
# Arguments:
#	sock	The connection handle
#	errmsg	The empty string, or an error message.
#
# Side Effects:
# 	Invokes the callback

proc HttpdDoCallback {sock {errmsg {}}} {
    upvar #0 Httpd$sock data
    if {[info exists data(callback)]} {
	catch {eval $data(callback) {$sock $errmsg}}

	# Ensure it is only called once
	unset data(callback)
    }
    CountStop serviceTime $sock
}

# Httpd_AddHeaders
#	Add http headers to be used in a reply
#	Call this before using Httpd_ReturnFile or
#	Httpd_ReturnData
#
# Arguments:
#	sock	handle on the connection
#	args	a list of header value ...

proc Httpd_AddHeaders {sock args} {
    upvar #0 Httpd$sock data

    eval lappend data(headers) $args
}

# Httpd_RemoveHeaders
#	Remove previously set headers from the reply.
#	Any headers that match the glob pattern are removed.
#
# Arguments:
#	sock	handle on the connection
#	pattern	glob pattern to match agains cookies.

proc Httpd_RemoveHeaders {sock {pattern *}} {
    upvar #0 Httpd$sock data
    if {[info exists data(headers)] && $data(headers) != {}} {
        set tmp {}
        foreach {header value} $data(headers) {
            if {![string match $pattern $header]} {
                lappend tmp $header $value
            }
        }
        set data(headers) $tmp
    }
    return
}

# Httpd_NoCache
#	Insert header into http header to indicate that this page
#	should not be cached
#
# Arguments:
#	sock	handle on the connection

proc Httpd_NoCache {sock} {
    Httpd_RemoveHeaders $sock Cache-Control
    Httpd_AddHeaders $sock Cache-Control no-cache
    Httpd_AddHeaders $sock Expires content '-1'
}

# Httpd_Refresh
#	Insert header into http header to cause browser to refresh
#	after a delay, optionally to a different URL
#
# Arguments:
#	sock	handle on the connection
#	time	time in seconds before refresh
#	url	optional: url to refresh to

proc Httpd_Refresh {sock time {url ""}} {
    Httpd_RemoveHeaders $sock Cache-Control
    if {$url == ""} {
	Httpd_AddHeaders $sock Refresh $time
    } else {
	Httpd_AddHeaders $sock Refresh ${time}\;url=${url}
    }
}

# HttpdRespondHeader --
#
#	Utility routine for outputting response headers for normal data Does
#	not output the end of header markers so additional header lines can be
#	added
#
# Arguments:
#	sock	The connection handle
#	type	The mime type of this response
#	close	If true, signal connection close headers.  See HttpdCloseP
#	size	The size "in bytes" of the response
#	code	The return code - defualts to 200
#
# Side Effects:
# 	Outputs header lines

proc HttpdRespondHeader {sock type close size {code 200}} {
    global Httpd
    upvar #0 Httpd$sock data

    set data(code) $code
    append reply "HTTP/$data(version) $code [HttpdErrorString $code]" \n
    append reply "Date: [Httpd_Date [clock seconds]]" \n
    append reply "Server: $Httpd(server)\n"

    if {$close} {
	append reply "Connection: Close" \n
    } elseif {$data(version) == 1.0 && !$close} {
	append reply "Connection: Keep-Alive" \n
    }
    append reply "Content-Type: $type" \n
    if {[string length $size]} {
	append reply "Content-Length: $size" \n
    }

    if {[info exists data(headers)]} {
	foreach {header value} $data(headers) {
	    catch {
		append reply "[string trimright $header :]: " $value \n
	    }
	}
    }

    puts -nonewline $sock $reply
}

# HttpdErrorString --
#
#	Map from an error code to a meaningful string.
#
# Arguments:
#	code	An HTTP error code, e.g., 200 or 404
#
# Results:
#	An error string, e.g. "Data follows" or "File Not Found"
#
# Side Effects:
# 	None

proc HttpdErrorString { code } {
    global Httpd_Errors
    if {[info exist Httpd_Errors($code)]} {
	return $Httpd_Errors($code)
    } else {
	return "Error $code"
    }
}

# Httpd_RemoveCookies
#	Remove previously set cookies from the reply.
#	Any cookies that match the glob pattern are removed.
#	This is useful for expiring a cookie that was previously set.
#
# Arguments:
#	sock	handle on the connection
#	pattern	glob pattern to match agains cookies.

proc Httpd_RemoveCookies {sock pattern} {
    upvar #0 Httpd$sock data
    if {[info exists data(set-cookie)] && $data(set-cookie) != {}} {
        set tmp {}
        foreach c $data(set-cookie) {
            if {![string match $pattern $c]} {
                lappend tmp $c
            }
        }
        set data(set-cookie) $tmp
    }
    return
}

# Httpd_SetCookie
#	Define a cookie to be used in a reply
#	Call this before using Httpd_ReturnFile or
#	Httpd_ReturnData
#
# Arguments:
#	sock	handle on the connection
#	cookie	Set-Cookie line
#	modify	(optional) If true, overwrite any preexisting
#		cookie that matches.  This way you can change
#		the expiration time.

proc Httpd_SetCookie {sock cookie {modify 0}} {
    upvar #0 Httpd$sock data
    lappend data(set-cookie) $cookie
}

# HttpdSetCookie
#	Generate the Set-Cookie headers in a reply
#	Use Httpd_SetCookie to register cookes eariler
#
# Arguments:
#	sock	handle on the connection

proc HttpdSetCookie {sock} {
    upvar #0 Httpd$sock data
    if {[info exist data(set-cookie)]} {
	foreach item $data(set-cookie) {
	    puts $sock "Set-Cookie: $item"
	}
	# HttpdCookieLog $sock HttpdSetCookie
	unset data(set-cookie)
    }
}

# Httpd_ReturnFile
#	Return a file.
#
# Arguments:
#	sock	handle on the connection
#	type	is a Content-Type
#	path	is the file pathname
#	offset	amount to skip at the start of file
#
# Side Effects:
#	Sends the file contents back as the reply.

proc Httpd_ReturnFile {sock type path {offset 0}} {
    global Httpd
    upvar #0 Httpd$sock data

    if {[Thread_Respond $sock \
	    [list Httpd_ReturnFile $sock $type $path $offset]]} {
	return
    }

    # Set file size early so it gets into all log records

    set data(file_size) [file size $path]
    set data(code) 200

    Count urlreply
    if {[info exists data(mime,if-modified-since)]} {
        # No need for complicated date comparison, if they're identical then 304.
	if {$data(mime,if-modified-since) == [Httpd_Date [file mtime $path]]} {
            Httpd_NotModified $sock
            return
        }
    } 

    # Some files have a duality, when the client sees X bytes but the
    # file is really X + n bytes (the first n bytes reserved for server
    # side accounting information.

    incr data(file_size) -$offset

    if {[catch {
	set close [HttpdCloseP $sock]
	HttpdRespondHeader $sock $type $close $data(file_size) 200
	HttpdSetCookie $sock
	puts $sock "Last-Modified: [Httpd_Date [file mtime $path]]"
	puts $sock ""
	if {$data(proto) != "HEAD"} {
	    set in [open $path]		;# checking should already be done
	    fconfigure $in -translation binary -blocking 1
	    if {$offset != 0} {
		seek $in $offset
	    }
	    fconfigure $sock -translation binary -blocking $Httpd(sockblock)
	    set data(infile) $in
	    Httpd_Suspend $sock 0
	    fcopy $in $sock -command [list HttpdCopyDone $in $sock $close]
	} else {
	    Httpd_SockClose $sock $close
	}
    } err]} {
	HttpdCloseFinal $sock $err
    }
}

# Httpd_ReturnData
#	Return data for a page.
#
# Arguments:
#	sock	handle on the connection
#	type	a Content-Type
#	content	the data to return
#	code	the HTTP reply code.
#
# Side Effects:
#	Send the data down the socket

proc Httpd_ReturnData {sock type content {code 200} {close 0}} {
    global Httpd
    upvar #0 Httpd$sock data

    # process any filters
    if {[info exists data(filter)]} {
	while {[llength $data(filter)]} {
	    set cmd [lindex $data(filter) end]
	    set data(filter) [lrange $data(filter) 0 end-1]
	    set content [eval $cmd $sock [list $content]]
	}
    }

    if {[Thread_Respond $sock \
	    [list Httpd_ReturnData $sock $type $content $code $close]]} {
	return
    }

    Count urlreply
    if {$close == 0} {
    	set close [HttpdCloseP $sock]
    }
    if {[catch {
	HttpdRespondHeader $sock $type $close [string length $content] $code
	HttpdSetCookie $sock
	puts $sock ""
	if {$data(proto) != "HEAD"} {
	    fconfigure $sock -translation binary -blocking $Httpd(sockblock)
	    puts -nonewline $sock $content
	}
	Httpd_SockClose $sock $close
    } err]} {
	HttpdCloseFinal $sock $err
    }
}

# Httpd_ReturnCacheableData
#	Return data with a Last-Modified time so
#	that proxy servers can cache it.  Or they seem to, anyway.
#
# Arguments:
#	sock	Client connection
#	type	a Content-Type
#	content	the data to return
#	date	Modify date of the date
#	code	the HTTP reply code.
#
# Side Effects:
#	Send the data down the socket

proc Httpd_ReturnCacheableData {sock type content date {code 200}} {
    global Httpd 
    upvar #0 Httpd$sock data

    # process any filters
    if {[info exists data(filter)]} {
	while {[llength $data(filter)]} {
	    set cmd [lindex $data(filter) end]
	    set data(filter) [lrange $data(filter) 0 end-1]
	    set content [eval $cmd $sock [list $content]]
	}
    }

    if {[Thread_Respond $sock \
	    [list Httpd_ReturnCacheableData $sock $type $content $date $code]]} {
	return
    }

    Count urlreply
    set close [HttpdCloseP $sock]
    if {[catch {
	HttpdRespondHeader $sock $type $close [string length $content] $code
	HttpdSetCookie $sock
	puts $sock "Last-Modified: [Httpd_Date $date]"
	puts $sock ""
	if {$data(proto) != "HEAD"} {
	    fconfigure $sock -translation binary -blocking $Httpd(sockblock)
	    puts -nonewline $sock $content
	}
	Httpd_SockClose $sock $close
    } err]} {
	HttpdCloseFinal $sock $err
    }
}

# Httpd_Filter
#	Add a post-generation filter to the socket
#
# Arguments:
#	sock	Client connection
#	args	filter proc or specs
#
# Side Effects:
#	Adds a filter to data(filter)
proc Httpd_Filter {sock args} {
    upvar #0 Httpd$sock data
    lappend data(filter) $args
}

# HttpdCopyDone -- this is used with fcopy when the copy completes.
#
# Arguments:
#	in	Input channel, typically a file
#	sock	Socket connection
#	close	If true, the socket is closed after the copy.
#	bytes	How many bytes were copied
#	error	Optional error string.
#
# Results:
#	None
#
# Side Effects:
#	See Httpd_SockClose

proc HttpdCopyDone {in sock close bytes {error {}}} {
    if {$error == ""} {
        # This special value signals a normal close,
        # and triggers a log record so static files are counted
        set error Close
    }
    Httpd_SockClose $sock $close $error
}

# HttpdCancel --
#
# Cancel a transaction if the client doesn't complete the request fast enough.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Terminates the connection by returning an error page.

proc HttpdCancel {sock} {
    upvar #0 Httpd$sock data
    Count cancel
    Httpd_Error $sock 408
}

# generic error response

set Httpd_ErrorFormat {
    <title>Httpd_Error: %1$s</title>
    Got the error <b>%2$s</b><br>
    while trying to obtain <b>%3$s</b>.
}

# Httpd_Error --
#
# send the error message, log it, and close the socket.
# Note that the Doc module tries to present a more palatable
# error display page, but falls back to this if necessary.
#
# Arguments:
#	sock	Socket connection
#	code	HTTP error code, e.g., 500
#	detail  Optional string to append to standard error message.
#
# Results:
#	None
#
# Side Effects:
#	Generates a HTTP response.

proc Httpd_Error {sock code {detail ""}} {

    if {[Thread_Respond $sock [list Httpd_Error $sock $code $detail]]} {
	# We've passed the error back to the main thread
	return
    }

    upvar #0 Httpd$sock data
    global Httpd Httpd_ErrorFormat

    Count errors
    append data(url) ""
    set message [format $Httpd_ErrorFormat $code [HttpdErrorString $code] $data(url)]
    append message <br>$detail
    if {$code == 500} {
	append message "<h2>Tcl Call Trace</h2>"
	for {set l [expr [info level]-1]} {$l > 0} {incr l -1} {
	    append message "$l: [protect_text [info level $l]]<br>"
	}
    }
    Log $sock Error $code $data(url) $detail

    # We know something is bad here, so we make the completion callback
    # and then unregister it so we don't get an extra call as a side
    # effect of trying to reply.

    HttpdDoCallback $sock $message

    if {[info exists data(infile)]} {
	# We've already started a reply, so just bail out
	Httpd_SockClose $sock 1
	return
    }
    if {[catch {
	HttpdRespondHeader $sock text/html 1 [expr {[string length $message] + 4}] $code
	puts $sock ""
	puts $sock $message
    } err]} {
	Log $sock LostSocket $data(url) $err
    }
    Httpd_SockClose $sock 1
}

set HttpdRedirectFormat {
    <html><head>
    <title>Found</title>
    </head><body>
    This document has moved to a new <a href="%s">location</a>.
    Please update your documents and hotlists accordingly.
    </body></html>
}

# Httpd_Redirect --
#
# Generate a redirect reply (code 302)
#
# Arguments:
#	newurl	New URL to redirect to.
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generates an HTTP reply

proc Httpd_Redirect {newurl sock} {
    upvar #0 Httpd$sock data
    global Httpd HttpdRedirectFormat

    if {[Thread_Respond $sock \
	    [list Httpd_Redirect $newurl $sock]]} {
	return
    }

    set message [format $HttpdRedirectFormat $newurl]
    set close [HttpdCloseP $sock]
    HttpdRespondHeader $sock text/html $close [string length $message] 302
    HttpdSetCookie $sock
    puts $sock "Location: $newurl"
    puts $sock "URI: $newurl"
    puts $sock ""

    # The -nonewline is important here to work properly with
    # keep-alive connections

    puts -nonewline $sock $message
    Httpd_SockClose $sock $close
}

# Httpd_NotModified --
#
# Generate a Not Modified reply (code 304)
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generates an HTTP reply

proc Httpd_NotModified {sock} {
    upvar #0 Httpd$sock data

    if {[Thread_Respond $sock \
	    [list Httpd_NotModified $sock]]} {
	return
    }

    HttpdRespondHeader $sock text/html 0 0 304
    HttpdSetCookie $sock
    puts $sock ""

    Httpd_SockClose $sock 0
}

# Httpd_RedirectSelf --
#
# Generate a redirect to another URL on this server.
#
# Arguments:
#	newurl	Server-relative URL to redirect to.
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generates an HTTP reply.

proc Httpd_RedirectSelf {newurl sock} {
    Httpd_Redirect [Httpd_SelfUrl $newurl $sock] $sock
}

# Httpd_SelfUrl --
#
# Create an absolute URL for this server
#
# Arguments:
#	url	A server-relative URL on this server.
#	sock	The current connection so we can tell if it
#		is the regular port or the secure port.
#
# Results:
#	An absolute URL.
#
# Side Effects:
#	None

proc Httpd_SelfUrl {url {sock ""}} {
    global Httpd
    if {$sock == ""} {
	set sock $Httpd(currentSocket)
    }
    upvar #0 Httpd$sock data

    set type [Httpd_Protocol $sock]
    set port [Httpd_Port $sock]
    if {[info exists data(mime,host)]} {

	# Use in preference to our "true" name because
	# the client might not have a DNS entry for use.

	set name $data(mime,host)
    } else {
	set name [Httpd_Name $sock]
    }
    set newurl $type://$name
    if {[string first : $name] == -1} {
	# Add in the port number, which may or may not be present in
	# the name already.  IE5 sticks the port into the Host: header,
	# while Tcl's own http package does not...

	if {$type == "http" && $port != 80} {
	    append newurl :$port
	}
	if {$type == "https" && $port != 443} {
	    append newurl :$port
	}
    }
    append newurl $url
}

# Httpd_Protocol --
#
# Return the protocol for the connection
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	Either "http" or "https"
#
# Side Effects:
#	None

proc Httpd_Protocol {sock} {
    upvar #0 Httpd$sock data
    return [lindex $data(self) 0]
}

# Httpd_Name --
#
# Return the server name for the connection
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	The name of the server, e.g., www.tcltk.org
#
# Side Effects:
#	None

proc Httpd_Name {sock} {
    upvar #0 Httpd$sock data
    return [lindex $data(self) 1]
}

# Httpd_Port --
#
# Return the port for the connection
#
# Arguments:
#	sock	The current connection. If empty, then the
#		regular (non-secure) port is returned.  Otherwise
#		the port of this connection is returned.
#
# Results:
#	The server's port.
#
# Side Effects:
#	None

proc Httpd_Port {{sock {}}} {
    if {[string length $sock]} {

	# Return the port for this connection

	upvar #0 Httpd$sock data
	return [lindex $data(self) 2]
    } else {

	# Return the non-secure listening port

	global Httpd
	if {[info exist Httpd(port)]} {
	    return $Httpd(port)
	} else {
	    return {}
	}
    }
}
# Httpd_SecurePort --
#
#	Return the secure port of this server
#
# Arguments:
#
# Results:
#	The server's secure port.
#
# Side Effects:
#	None

proc Httpd_SecurePort {} {

    # Return the secure listening port

    global Httpd
    if {[info exist Httpd(https_port)]} {
	return $Httpd(https_port)
    } else {
	return {}
    }
}

set HttpdAuthorizationFormat {
    <HTML><HEAD>
    <TITLE>401 Authorization Required</TITLE>
    </HEAD><BODY>
    <H1>Authorization Required</H1>
    This server could not verify that you
    are authorized to access the document you
    requested.  Either you supplied the wrong
    credentials (e.g., bad password), or your
    browser doesn't understand how to supply
    the credentials required.<P>
    </BODY></HTML>
}

# Httpd_RequestAuth --
#
# Generate the (401) Authorization required reply
#
# Arguments:
#	sock	Socket connection
#	type	usually "Basic"
#	realm	browsers use this to cache credentials
#	args	additional name value pairs for request
#
# Results:
#	None
#
# Side Effects:
#	Generate an authorization challenge response.

proc Httpd_RequestAuth {sock type realm args} {
    upvar #0 Httpd$sock data
    global Httpd HttpdAuthorizationFormat

    if {[Thread_Respond $sock \
	    [list Httpd_RequestAuth $sock $type $realm]]} {
	return
    }

    set additional ""
    foreach {name value} $args {
	append additional ", " ${name}=$value
    }

    set close [HttpdCloseP $sock]
    HttpdRespondHeader $sock text/html $close [string length $HttpdAuthorizationFormat] 401
    puts $sock "Www-Authenticate: $type realm=\"$realm\" $additional"
    puts $sock ""
    puts -nonewline $sock $HttpdAuthorizationFormat
    Httpd_SockClose $sock $close
}

# Httpd_Date --
#
# generate a date string in HTTP format
#
# Arguments:
#	seconds	Clock seconds value
#
# Results:
#	A date string.
#
# Side Effects:
#	None

proc Httpd_Date {seconds} {
    return [clock format $seconds -format {%a, %d %b %Y %T GMT} -gmt true]
}

# Httpd_SockClose --
#	"Close" a connection, although the socket might actually
#	remain open for a keep-alive connection.
#	This means the HTTP transaction is fully complete.
#
# Arguments:
#	sock	Identifies the client connection
#	closeit	1 if the socket should close no matter what
#	message	Logging message.  If this is "Close", which is the default,
#		then an entry is made to the standard log.  Otherwise
#		an entry is made to the debug log.
#
# Side Effects:
#	Cleans up all state associated with the connection, including
#	after events for timeouts, the data array, and fileevents.

proc Httpd_SockClose {sock closeit {message Close}} {
    global Httpd
    upvar #0 Httpd$sock data

    if {[string length $message]} {
	Log $sock $message
	if {$message == "Close"} {

	    # This is a normal close.  Any other message
	    # is some sort of error.

	    set message ""
	}
    }
    # Call back to the URL domain implementation so they are
    # sure to see the end of all their HTTP transactions.
    # There is a slight chance of an error reading any un-read
    # Post data, but if the URL domain didn't want to read it,
    # then they obviously don't care.

    HttpdDoCallback $sock $message

    Count connections -1
    if {[info exist data(infile)]} {

	# Close file or CGI pipe.  Still need catch because of CGI pipe.

	catch {close $data(infile)}
    }
    if {$closeit} {
	if {[info exists data(count)] && $data(count) > 0} {

	    # There is unread POST data.  To ensure that the client
	    # can read our reply properly, we must read this data.
	    # The empty variable name causes us to discard the POST data.

	    if {[info exists data(cancel)]} {
		after cancel $data(cancel)
	    }
	    set data(cancel) [after $Httpd(timeout3) \
		[list HttpdCloseFinal $sock "timeout reading extra POST data"]]

	    Httpd_GetPostDataAsync $sock "" $data(count) HttpdReadPostDone
	} else {
	    HttpdCloseFinal $sock
	}
    } else {
	HttpdReset $sock
    }
}

# HttpdReadPostDone --
#
#	Callback is made to this when we are done cleaning up any
#	unread post data.
#
# Arguments:
#	sock	Socket connection
#	varname	Name of variable with post data
#	errmsg	If not empty, an error occurred on the socket.
#
# Results:
#	None
#
# Side Effects:
#	None here, but see HttpdCloseFinal.

proc HttpdReadPostDone {sock var errmsg} {
    HttpdCloseFinal $sock $errmsg
}

# HttpdCloseFinal --
#
#	Central close procedure.  All close operations should funnel
#	through here so that the right cleanup occurs.
#
# Arguments:
#	sock	Socket connection
#	errmsg	If non-empty, then something went wrong on the socket.
#
# Results:
#	None
#
# Side Effects:
#	Cleans up any after event associated with the connection.
#	Closes the socket.
#	Makes the callback to the URL domain implementation.

proc HttpdCloseFinal {sock {errmsg {}}} {
    upvar #0 Httpd$sock data
    Count sockets -1
    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
    }
    if {[catch {close $sock} err]} {
	Log $sock CloseError $err
	if {[string length $errmsg] == 0} {
	    set errmsg $err
	}
    }
    HttpdDoCallback $sock $errmsg
    if {[info exist data]} {
	unset data
    }
}

# Httpd_RequestComplete --
#
#	Detect if a request has been sent.  The holder of a socket
#	might need to know of the URL request was completed with
#	one of the return-data commands, or is still lingering open.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	1 if the request was completed, 0 otherwise.
#
# Side Effects:
#	None.

proc Httpd_RequestComplete {sock} {
    upvar #0 Httpd$sock data
    if {![info exist data(state)] || $data(state) == "start"} {
	
	# The connection was closed or reset in a keep-alive situation.

	return 1
    } else {
	return 0
    }
}

# server specific version of bgerror - indent to hide from indexer

    proc bgerror {msg} {
	global errorInfo

	set msg "[clock format [clock seconds]]\n$errorInfo"
	if {[catch {Log nosock bgerror $msg}]} {
	    Stderr $msg
	}
    }

# HttpdCookieLog --
#
#	Special loggin procedure to debug cookie implementation.
#
# Arguments:
#	sock	Socket connection
#	what	What procedure is doing the logging.
#
# Results:
#	None
#
# Side Effects:
#	Writes to the debug log.

proc HttpdCookieLog {sock what} {
    global Log Httpd
    upvar #0 Httpd$sock data
    if {[info exist Log(log)] && ![info exist Httpd(cookie_log)]} {
	set Httpd(cookie_log) [open $Log(log)cookie a]
    }
    if {[info exist Httpd(cookie_log)]} {
	append result [LogValue data(ipaddr)]
	append result { } \[[clock format [clock seconds] -format %d/%h/%Y:%T] -0700\]

	append result { } $what
	switch $what {
	    Httpd_Dispatch {
		if {![info exist data(mime,cookie)]} {
		    return
		}
		append result { } \"$data(mime,cookie)\"
	    }
	    Httpd_SetCookie -
	    HttpdSetCookie {
		append result { } \"[LogValue data(set-cookie)]\"
	    }
	}
	catch { puts $Httpd(cookie_log) $result ; flush $Httpd(cookie_log)}
    }
}

# Httpd_Suspend --
#
#	Suspend Wire Callback - for async transactions
#	Use Httpd_Resume once you are back in business
#	Note: global page array is not preserved over suspend
#
# Arguments:
#	sock	Socket connection
#	timeout Timeout period.  After this the request is aborted.
#
# Results:
#	None
#
# Side Effects:
#	Disables fileevents and sets up a timer.

proc Httpd_Suspend {sock {timeout ""}} {
    global Httpd
    upvar #0 Httpd$sock data

    fileevent $sock readable {}
    fileevent $sock writable {}

    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
	unset data(cancel)
    }
    if {[info exists Httpd(currentSocket)]} {
	unset Httpd(currentSocket)
    }
    if {$timeout == ""} {
	set timeout $Httpd(timeout2)
    }
    if {$timeout != 0} {
	set data(cancel) [after $timeout [list HttpdCancel $sock]]
    }
}

# Httpd_Resume --
#
#	Resume processing of a request.  Sets up a bit of global state that
#	has been cleared by Httpd_Suspend.
#
# Arguments:
#	sock	Socket connection
#	timeout Timeout period.  After this the request is aborted.
#
# Results:
#	None
#
# Side Effects:
#	Restores the Httpd(currentSocket) setting.

proc Httpd_Resume {sock {timeout ""}} {
    upvar #0 Httpd$sock data
    global Httpd
    set Httpd(currentSocket) $sock
    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
    }
    if {$timeout == ""} {
	set timeout $Httpd(timeout1)
    }
    set data(cancel) [after $timeout \
	[list Httpd_SockClose $sock 1 "timeout"]]
}

# Httpd_CurrentSocket --
#
#	Return (or set) the handle to the current socket.
#
# Arguments:
#	sock	Optional - if specified, set the current socket.
#
# Results:
#	A socket.
#
# Side Effects:
#	None.

proc Httpd_CurrentSocket {{sock {}}} {
    global Httpd
    if {[string length $sock]} {
	set Httpd(currentSocket) $sock
    }
    return $Httpd(currentSocket)
}

# Httpd_Pair --
#
#
# Pair two fd's - typically for tunnelling
# Close both if either one closes (or gets an error)
#
#
# Arguments:
#	sock	Socket connection
#	fd	Any other I/O connection
#
# Results:
#	None
#
# Side Effects:
#	Sets up fileevents for proxy'ing data.

proc Httpd_Pair {sock fd} {
    global Httpd
    upvar #0 Httpd$sock data

    syslog debug "HTTP: Pairing $sock and $fd"

    Httpd_Suspend $sock 0

    fconfigure $sock -translation binary -blocking 0
    fconfigure $fd -translation binary -blocking 0

    fileevent $sock readable [list HttpdReflect $sock $fd]
    fileevent $fd readable [list HttpdReflect $fd $sock]
}

# HttpdReflect --
#
#	This is logically fcopy in both directions, but the core
#	prevents us from doing that so we do it by hand.
#
# Arguments:
#	in	Input channel
#	out	Output channel
#
# Results:
#	None
#
# Side Effects:
#	Copy data between channels.

proc HttpdReflect {in out} {
    global Httpd
    if {[catch {
	set buf [read $in $Httpd(bufsize)]
	puts -nonewline $out $buf
	flush $out
	set buflen [string length $buf]
	if {$buflen > 0} {
	    syslog debug "Tunnel: $in -> $out ($buflen bytes)" 
	}
    } oops]} {
	Log $in Tunnel "Error: $oops"
    } elseif {![eof $in]} {
	return 1
    } else {
	syslog debug "Tunnel: $in EOF"
    }
    fileevent $in readable {}
    fileevent $out readable {}
    catch {flush $in}
    catch {flush $out}
    catch {close $in}
    catch {close $out}
    return 0
}

# Httpd_DumpHeaders --
#
#	Dump out the protocol headers so they can be saved for later.
#
# Arguments:
#	sock	Client connection
#
# Results:
#	A list structure that alternates between names and values.
#	The names are header names without the trailing colon and
#	mapped to lower case (e.g., content-type).  Two pseudo-headers
#	added: One that contains the original request URL; its name is "url"
#	Another that contains the request protocol; its name is "method"
#	There are no duplications in the header keys.  If any headers
#	were repeated, their values were combined by separating them
#	with commas.

proc Httpd_DumpHeaders {sock} {
    upvar #0 Httpd$sock data

    set result [list url $data(uri) method $data(proto) version $data(version)]
    if {[info exist data(mimeorder)]} {
	foreach key $data(mimeorder) {
	    lappend result $key $data(mime,$key)
	}
    }
    return $result
}

# Httpd_Webmaster --
#
# Define an email address for the webmaster
#
# Arguments:
#	email 	The email of the webmaster.  If empty, the
#		current value is returned, which is handy in
#		web pages.
#
# Results:
#	Returns the webmaster email.
#
# Side Effects:
#	Sets the webmaster email.

proc Httpd_Webmaster {{email {}}} {
    global Httpd
    if {[string length $email] == 0} {
	if {![info exists Httpd(webmaster)]} {
	    set Httpd(webmaster) webmaster
	}
	return $Httpd(webmaster)
    } else {
	set Httpd(webmaster) $email
    }
}

# this is too much of a compatibility hassle, so we alias
catch {interp alias {} Doc_Webmaster {} Httpd_Webmaster}
catch {interp alias {} Httpd_RedirectDir {} Redirect_Dir}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/imagemap.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# imagemap.tcl
# based on imagemap.c, version 1.8
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: imagemap.tcl,v 1.7 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::imagemap 1.0

package require httpd	;# Httpd_Redirect Httpd_ReturnData
package require httpd::counter	;# Count
package require httpd::utils	;# file parray

# Doc_application/x-imagemap --
#
# this is called by DocHandle to process .map files
#
# Arguments:
#	path	The file name of the .map file.
#	suffix	The URL suffix
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Redirect to the URL indicated by the map.

proc Doc_application/x-imagemap {path suffix sock} {
    upvar #0 Httpd$sock data
    if {![info exists data(query)]} {
	Httpd_ReturnData $sock text/plain "[parray Httpd$sock]"
	return
    }
    set url [Map_Lookup $path?$data(query)]
    Count maphits
    Httpd_Redirect $url $sock
}

proc MapPointInRect {X Y coordArray} {
	upvar $coordArray coords
        return [expr ($X >= $coords(0,X) && $X <= $coords(1,X)) && \
        ($Y >= $coords(0,Y) && $Y <= $coords(1,Y))]
}

proc MapPointInCircle {X Y coordArray} {
	upvar $coordArray coords

        set radius1 [expr (($coords(0,Y) - $coords(1,Y)) * ($coords(0,Y) - \
        $coords(1,Y))) + (($coords(0,X) - $coords(1,X)) * ($coords(0,X) - \
        $coords(1,X)))]
        set radius2 [expr (($coords(0,Y) - $Y) * ($coords(0,Y) - $Y)) + \
        (($coords(0,X) - $X) * ($coords(0,X) - $X))]
        return [expr $radius2 <= $radius1]
}

proc MapPointInPoly {tx ty pgonArray} {
	upvar $pgonArray pgon
	global MAXVERTS

	set numverts [expr [llength [array names pgon]] / 2]
	set lastvert [expr $numverts - 1]
        set crossings 0

        set y pgon($lastvert,Y)

        set p pgon(0,Y)
        if {($y >= $ty) != ($p >= $ty)} {
		set xflag0 [expr $pgon($lastvert,X) >= $tx]
                if {$xflag0 == ($pgon(0,X) >= $tx)} {
                        if $xflag0 {
                                incr crossings
			}
                } else {
                        incr crossings [expr {$pgon($lastvert,X) - ($y - $ty) *
			    ($pgon(0,X) - $pgon($lastvert,X)) /
			    ($p - $y) >= $tx}]
                }
        }

        for {set i 0} {$i < $numverts} {incr i} {
		set y $pgon($i,Y)
                if {$y >= $ty} {
			while {$i < $numverts && $pgon($i,Y) >= $ty} {
				incr i
			}
                } else {
			while {$i < $numverts && $pgon($i,Y) < $ty} {
				incr i
			}
		}
		if {$i >= $numverts} {
			break
		}
		set lasti [expr $i-1]
		set xflag0 [expr $pgon($lasti,X) >= $tx]
		if {$xflag0 == ($pgon($i,X) >= $tx)} {
			if $xflag0 {
				incr crossings
			}
		} else {
			incr crossings \
			    [expr ($pgon($lasti,X) - \
			    ($pgon($lasti,Y) - $ty) * \
			    ($pgon($i,X) - $pgon($lasti,X)) / \
			    ($pgon($i,Y) - $pgon($lasti,Y))) >= $tx]
		}
        }
        set inside_flag [expr $crossings & 0x01]
        return $inside_flag
}

proc MapTest {} {
    array set pgon {
	0,X 0.0   0,Y 0.0
	1,X 100.0 1,Y 0.0
	2,X 100.0 2,Y 100.0
	3,X 0.0   3,Y 100.0
    }
    foreach {X Y} {50. 50. 1. 1. 0. 0. 200. 200.} {
	puts "($X,$Y) In Poly [pointinpoly $X $Y pgon]"
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































Deleted lib/include.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# include.tcl
#
# Stephen Uhler (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: include.tcl,v 1.7 2004/10/22 03:43:06 coldstore Exp $

# Process server side includes.
# Look for comments of the form:
#   <!--#keyword args  -->
# Where "keyword" is one of:
#  ECHO FLASTMOD FSIZE INCLUDE EXEC
# We do not implement
#  CONFIG
# The input string is passed on the command line to Httpd_include,
# and the result is returned.
# Note: the included file is treated as text, which possibly has
# other include files in it.  We are not doing a full URL dispatch
# on the included files, so they cannot be cgi scripts or other fancy
# objects.

package require html

package provide httpd::include 1.0

package require httpd	;# Httpd_Error Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::counter	;# Count
package require httpd::doc	;# Doc_Virtual
package require httpd::utils	;# file iscommand

# Global state for this module
# maxdepth controls recursively included files.

array set Include {
	maxdepth 10
}

# Process a file with server includes

proc Doc_application/x-server-include {path suffix sock} {
    Count includes
    if {[catch {open $path} in]} {
	Httpd_Error $sock 404 $in
    } else {
	global env
	Cgi_SetEnv $sock $path 
	set html [Include_Html $sock $path [read $in]]
	close $in
	Httpd_ReturnData $sock text/html $html
    }
}

# Process all the server includes.
# sock: a token passed through to the include procedures
# path: required to handle relative paths in recursive includes
# html:  The html to process
# depth: A counter to detect include loops

proc Include_Html {sock path html {depth 0}} {
    set token \x87	;# this character never appears in an html stream
    regsub -all {([][$\\])} $html {\\\1} html	;# protect TCL special characters
    regsub -all -- --> $html $token html	;# convert end of comment to token
    regsub -all "<!--# *(\[^ ]+) *(\[^$token]+)$token" $html \
	    "\[IncludeInner $sock {$path} {\\1} {\\2} [incr depth]\]" html	;# find all includes
    regsub -all $token $html --> html		;# recover end of comment tokens
    return  [subst $html]			;# process the includes
}

proc IncludeInner {sock path command params depth} {
    set command [string tolower $command]
    if {![iscommand include_$command]} {
	return "<!-- Server not configured to processes \"$command\" includes -->\n"
    } elseif {[catch {include_$command $sock $path $params $depth} result]} {
    	return "<!-- Server error in include command $command: $result -->\n"
    } else {
    	return $result
    }
}

# utility to extract the file name specified from the include parameters

proc IncludeFile {sock op path params} {
    if {[html::extractParam $params virtual orig]} {
	set key virtual
	set npath [Doc_Virtual $sock $path $orig]
    } elseif {[html::extractParam $params file orig]} {
	set key file
	set npath [file join [file dirname $path] $orig]
    } else {
	error "<!-- Invalid $op parameter list: $params. -->\n"
    }
    return [list $key $npath $orig]
}

# Each server function has its own procedure, that returns the substituted value
###############################################################################

# include another file
# Params:
#  virtual=path
#  file=path

proc include_include {sock path params depth} {
    global Include
    if {$depth > $Include(maxdepth)} {
    	return "<!-- Include recursion depth exceeded ($depth) -->\n"
    }
    if {[catch {IncludeFile $sock include $path $params} info]} {
	return $info
    }
    set key [lindex $info 0]
    set npath [lindex $info 1]
    set orig [lindex $info 2]

    # now open the file and re-do substitutions.

    if {[catch {open $npath r} fd]} {
	return "<!-- invalid include $key path $orig: $fd -->\n"
    }
    set data [Include_Html $sock $npath [read $fd] $depth]
    close $fd
    return $data
}

proc include_echo {sock path params args} {
    global env
    set var ""
    if {[html::extractParam $params var]} {
	if {[info exists env($var)]} {
	    return $env($var)
	} else {
	    return "<!-- No such variable: $var. -->\n"
	}
    }
    return "<!-- Echo: No var parameter. -->\n"
}

proc include_fsize {sock path params args} {
    if {[catch {IncludeFile $sock fsize $path $params} info]} {
	return $info
    }
    set key [lindex $info 0]
    set npath [lindex $info 1]
    set orig [lindex $info 2]
    if {[file exists $npath]} {
	return [file size $npath]
    } else {
	return "<!-- File not found $key: $npath. -->\n"
    }
}

proc include_exec {sock path params args} {
    set cmd ""
    if {[html::extractParam $params cmd]} {
	if {[catch {eval exec $cmd} result]} {
	    regsub -all -- --> $result {} result
	    return "<!-- $cmd error: $result  -->\n"
	} else {
	    return $result
	}
    }
}

proc include_config {sock path params args} {
    return "<!-- include config not implemented -->\n"
}

proc include_flastmod {sock path params args} {
    if {[catch {IncludeFile $sock flastmod $path $params} info]} {
	return $info
    }
    set key [lindex $info 0]
    set npath [lindex $info 1]
    set orig [lindex $info 2]
    if {[file exists $npath]} {
	return [clock format [file mtime $npath]]
    } else {
	return "<!-- File not found $key: $npath. -->\n"
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































Deleted lib/log.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# log.tcl
#
#	This is a file-based logging module for TclHttpd.
#
#	This starts a new log file each day with Log_SetFile
#	It also maintains an error log file that is always appeneded to
#	so it grows over time even when you restart the server.
#
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: log.tcl,v 1.14 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::log 1.1

package require httpd::config	;# Config
package require httpd::counter	;# Count Counter_CheckPoint
package require httpd::logstd	;# LogStandardData
package require httpd::utils	;# Stderr file

# log an Httpd transaction

# This program is used to compress log files
if {![info exists Log(compressProg)]} {
    set Log(compressProg) gzip
}

# Flush interval
if {![info exists Log(flushInterval)]} {
    set Log(flushInterval) [expr {60 * 1000}]
}

# This is used to turn on an alternate debug log file
if {![info exist Log(debug_log)]} {
    set Log(debug_log) 0
}


# Log --
#
#	Log information about the activity of TclHttpd.  There are two kinds of
#	log entries.  One "normal" entry that goes into its own log, one line
#	for each HTTP transaction.  All other log records are appended to an
#	error log file.
#
# Arguments:
#	sock	The client connection.
#	reason	If "Close", then this is the normal completion of a request.
#		Otherwise, this is some error tag and the record goes to
#		the error log.
#	args	Additional information to put into the logs.
#
# Results:
#	None
#
# Side Effects:
#	Writes data to the log files.

proc Log {sock reason args} {
    global Log
    upvar #0 Httpd$sock data

    # Log normal closes to the regular log.
    # Log everything else to the error log.

    switch -- $reason {
	"Close" {
	    set now [clock seconds]
	    set result [LogStandardData $sock $now]
	    if {[catch {puts $Log(log_fd) $result} err]} {
		set urk !
	    }
	    if {$Log(flushInterval) == 0} {
		catch {flush $Log(log_fd)}
	    }
	}
	"Debug" {
	    set now [clock seconds]
	    append result { } \[[clock format $now -format %d/%h/%Y:%T]\]
	    append result { } $sock { } $reason { } $args
	    if {[info exists data(url)]} {
		append result { } $data(url)
	    }
	    catch { puts $Log(debug_fd)  $result ; flush $Log(debug_fd) }
	}
	default {
	    set now [clock seconds]
	    append result { } \[[clock format $now -format %d/%h/%Y:%T]\]
	    append result { } $sock { } $reason { } $args
	    if {[info exists data(url)]} {
		append result { } $data(url)
	    }
	    catch { puts $Log(error_fd)  $result ; flush $Log(error_fd) }
	}
    }
}

# Log_Configure --
#
#	Query/modify configuration settings for logging.
#
# Arguments:
#	args	option/value pairs
#
# Results:
#	Configuration value(s) or empty string

proc Log_Configure args {
    global Log

    switch [llength $args] {
	0 {
	    foreach {key value} [array get Log] {
		lappend result [list -$key $value]
	    }
	    return $result
	}
	1 {
	    return $Log(-[lindex $args 0])
	}
	default {
	    if {[llength $args] % 2} {
		error "no value specified for option \"[lindex $args end]\""
	    } else {
		foreach {option value} $args {
		    switch -- $option {
			-lognames {
			    lappend newOptions lognames [boolean $value]
			}
			default {
			    # TODO: Other logging options, such as filenames, flush interval, etc
			    error "unknown option \"$option\""
			}
		    }
		}
		array set Log $newOptions
	    }
	}
    }
    return {}
}

# Log_FlushMinutes --
#
# Set the interval at which the logs are flushed.
#
# Arguments:
#	min	The minutes between flushes.  If 0,
#		then the log is flushed on each write.
#
# Results:
#	None
#
# Side Effects:
#	None

proc Log_FlushMinutes {min} {
    global Log
    set Log(flushInterval) [expr int($min*60*1000)]
    if {[info exist Log(flushID)]} {
	Log_Flush
    }
}

# Log_CompressProg --
#
# Set log compression program
#
# Arguments:
#	prog	the program used to compress logs
#
# Results:
#	None
#
# Side Effects:
#	None

proc Log_CompressProg {prog} {
    global Log
    set Log(compressProg) $prog
}

# Log_SetFile --
# automatically change log files every midnight
#
# Arguments:
#	basename 	The name of a base filename
#			including its directory,
#			e.g. /logs/www
#			This will create files like:
#			/logs/www80_00.09.23
#
# Results:
#	None
#
# Side Effects:
#	Closes and opens files, creating new files
#	each time through.

proc Log_SetFile {{basename {}}} {
    global Log
    if {[string length $basename]} {
	set Log(log) $basename
    }
    if {![info exists Log(log)]} {
	catch {close $Log(log_fd)}
	catch {close $Log(error_fd)}
	catch {close $Log(debug_fd)}
	return
    }
    catch {Counter_CheckPoint} 		;# Save counter data

    # set after event to switch files after midnight
    set now [clock seconds]
    set next [expr {([clock scan 23:59:59 -base $now] -$now + 1000) * 1000}]
    after cancel Log_SetFile
    after $next Log_SetFile

    # set the log file and error file.
    # Log files rotate, error files don't

    if {[info exists Log(log_file)] && [file exists $Log(log_file)]} {
	set lastlog $Log(log_file)
    }
    set Log(log_file) $Log(log)[clock format $now -format %y.%m.%d]
    catch {close $Log(log_fd)}

    # Create log directory, if neccesary, then open the log file

    catch {file mkdir [file dirname $Log(log_file)]}
    if {[catch {set Log(log_fd) [open $Log(log_file) a]} err]} {
	 Stderr $err
    }

    if {[info exists lastlog]} {
	# compress log files as we go
	if {[file executable $Log(compressProg)] &&
	    [catch {exec $Log(compressProg) $lastlog &} err]} {
	    Stderr $err
	}
    }

    catch {close $Log(error_fd)}
    if {[catch {set Log(error_fd) [open $Log(log)error a]} err]} {
	Stderr $err
    }

    # This debug log gets reset daily

    catch {close $Log(debug_fd)}
    if {[info exists Log(debug_file)] && [file exists $Log(debug_file)]} {
	catch {file rename -force $Log(debug_file) $Log(debug_file).old}
    }

    if {[info exist Log(debug_log)] && $Log(debug_log)} {
	set Log(debug_file) $Log(log)debug
	if {[catch {set Log(debug_fd) [open $Log(debug_file) w]} err]} {
	    Stderr $err
	}
    }
}

# Log_Flush --
# flush the output to the log file.  Do this periodically, rather than
# for every transaction, for better performance
#
# Arguments:
#
# Results:
#	None
#
# Side Effects:
#	Flushes the logs to disk.

proc Log_Flush {} {
    global Log
    catch {flush $Log(log_fd)}
    catch {flush $Log(error_fd)}
    catch {after cancel $Log(flushID)}
    if {$Log(flushInterval) > 0} {
	set Log(flushID) [after $Log(flushInterval) Log_Flush]
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































Deleted lib/logstd.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# logstd.tcl
#
# Standard Web Log file format support.
#
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: logstd.tcl,v 1.5 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::logstd 1.0

package require httpd	;# Httpd_Peername
package require httpd::log	;# Log
package require httpd::utils	;# file

# Use IP address, or domain name?
# Default is IP address, because looking up names is expensive
if {![info exists Log(lognames)]} {
    set Log(lognames) 0
}

# If true, we append cookie values to the log
if {![info exists Log(cookie)]} {
    set Log(cookie) 0
}

# LogStandardData --
#
#	Generate a standard web log file record for the current connection.
#	This records the client address, the URL, the time, the error
#	code, and so forth.
#
# Arguments:
#	sock	The client connection.
#	now	The timestamp for the connection, in seconds
#
# Results:
#	A string containing the log fie record.
#
# Side Effects:
#	None

proc LogStandardData {sock now} {
    return [LogStandardPrint [LogStandardList $sock $now]]
}

# LogStandardPrint --
#
#	Generate a standard web log file record for the current connection.
#	This records the client address, the URL, the time, the error
#	code, and so forth.
#
# Arguments:
#	sock	The client connection.
#	now	The timestamp for the connection, in seconds
#
# Results:
#	A string containing the log fie record.
#
# Side Effects:
#	None

proc LogStandardPrint {data} {
    set sep ""
    set result ""
    foreach {n v} $data {
	if {$v == "" || $v == "-"} {
	    append result ${sep}-
	    continue
	}
	switch -- $n {
	    time {
		 append result $sep\[[clock format $v -format "%d/%h/%Y:%T %Z"]\]
	    }
	    http -
	    referer -
	    useragent -
	    cookie {
		append result $sep"$v"
	    }
	    default {
		append result $sep$v
	    }
	}
	set sep " "
    }
    return $result
}

# LogStandardList --
#
#	Like LogStandardData, but return the data in a name, value list
#	suitable for use in foreach loops, array get, or long term
#	storage.
#
# Arguments:
#	sock	The client connection
#	now	The timestamp for the connection, in seconds
#
# Results:
#	A name, value list of the fields in a standard web log entry.
#
# Side Effects:
#	None

proc LogStandardList {sock now} {
    global Log
    upvar #0 Httpd$sock data
    if {$Log(lognames)} {
	if {[catch {lappend result ipaddr [Httpd_Peername $sock]}]} {
	    lappend result ipaddr [LogValue data(ipaddr)]
	}
    } else {
	lappend result	ipaddr [LogValue data(ipaddr)]
    }
    lappend result authuser [LogValue data(mime,auth-user)]
    lappend result username [LogValue data(mime,username)]
    lappend result time $now
    lappend result http [LogValue data(line)]
    lappend result status [LogValue data(code)]
    lappend result filesize [LogValue data(file_size)]
    lappend result referer [LogValue data(mime,referer)]
    lappend result useragent [LogValue data(mime,user-agent)]
    if {$Log(cookie)} {
      # This field is not always present in logs
      lappend result cookie [LogValue data(mime,cookie)]
    }
    return $result
}

# LogValue --
#
#	Generate a field or the default "null field" representation.
#
# Arguments:
#	var	The variable whose value to use, if any
#
# Results:
#	The value of the variable, or - as the default.
#
# Side Effects:
#	None

proc LogValue {var} {
    upvar $var data
    if {[info exists data]} {
	return $data
    } else {
       return -
    }
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































Deleted lib/mail.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# mail.tcl
# mail support using tcllib's smtp and mime packages
#
# The /mail URL is registered as a direct url that maps to procedures
# in this file that begin with Mail.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: mail.tcl,v 1.16 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::mail 1.0

package require httpd	;# Httpd_Webmaster
package require httpd::config	;# Config
package require httpd::direct	;# Direct_Url
package require httpd::utils	;# file protect_text

# No useful default, but we define procedures so the vanilla server
# can start up.

# Config(mail) seems to be an old usage 
# MailServer is defined in tclhttpd.rc

if {[info exists Config(mail)] && ($Config(mail) != {})} {
    set Mail(server) $Config(mail)
} elseif {[config::cget MailServer] ne ""} {
    set Mail(server) [config::cget MailServer]
}

package require smtp
package require mime

# Mail_Send
#	Send email to recipients using tcllib's smtp client.
#
# Arguments:
#	recipients	list of email addresses to which to send the mail
#	subject	subject line for email
#	from	email address of email sender
#	type	mime type of body ("text/plain" for normal email)
#	body	the body of the email
#
# Results:
#	return the tcllib smtp client's return, {} if successful else:
#	A list indicating which recipients were unacceptable to the SMTP server.
#	Each element of the list is another list, containing the address,
#	an SMTP error code, and a textual diagnostic.
#	
# Side Effects:
#	Email is sent to each of the recipients

proc Mail_Send {recipients subject from type body} {
    global Mail

    set token [mime::initialize -canonical $type -string $body]
    mime::setheader $token Subject $subject

    set result [smtp::sendmessage $token \
		    -recipients $recipients \
		    -originator $from \
		    -servers $Mail(server)]
    mime::finalize $token
    return $result
}

# Mail_Result
#	convert tcllib smtp server result to a table suitable for display

proc Mail_Result {mail_err} {
    set html ""
    if {$result != {}} {
	set html <table>
	foreach el $result {
	    append html <tr>
	    foreach {addr errcode diagnostic} $el {
		append html <th> [protect_text $addr] </th>
		append html <td> [protect_text $errcode] </td>
		append html <td> [protect_text $diagnostic] </td>
	    }
	    append html </tr>
	}
	append html </table>
    }
    return $html
}

proc MailSend {recipients subject from type body} {
    set result [Mail_Send $recipients $subject $from $type $body]
    if {$result == ""} {
	set html "<b>Thank You!</b><br>Mailed report to <b>[protect_text $recipients]</b>"
    } else {
	return [Mail_Result $result]
    }
}

proc Mail_Url {dir} {
    Direct_Url $dir Mail
}

proc Mail/bugreport {email errorInfo args} {
    global Httpd
    set html "<pre>"
    foreach {name value} $args {
	if {([string compare $name "env"] == 0) && 
		([catch {array set X $value}] == 0)} {
	    # add this later
	    continue
	} else {
	    append html "$name: $value\n"
	}
    }
    append html  $Httpd(server)\n
    append html [protect_text $errorInfo]

    if {[info exist X]} {
	append html "\n\nEnvironment:\n"
	foreach n [lsort [array names X]] {
	    append html "  $n: $X($n)\n"
	}
    }
    append html "</pre>"
    if {$email == ""} {
	set email [Httpd_Webmaster]
    }
    MailSend $email "$Httpd(name):$Httpd(port) error" "" text/html $html
}

# If your form action is /mail/forminfo, then this procedure
# sends the results to the address specified by "sendto"
proc Mail/forminfo {sendto subject href label args} {
    set from ""
    foreach {name value} $args {
	# If the value has unbalanced braces, we will do base64
	# encoding to avoid a huge jumble of backslashes and
	# a long line that will not survive the email transport
	set blob [list $value]
	if {[regsub -all \\\\ $blob {} _] > 0} {
	    append message "[list Data64 $name] \\\n"
	    append message [list [base64::encode $value]]\n
	} else {
	    append message [list Data $name $value]\n
	}
	if {[string compare $name "email"] == 0} {
	    set from $value
	}
    }
    set html [MailSend $sendto $subject $from text/plain $message]
    if {[string length $href]} {
	if {[string length $label] == 0} {
	    set label Back
	}
	append html "<p><a href=\"$href\">$label</a>"
    }
    return $html
}

# This form is designed to be embedded into a page
# that handles form data.

proc Mail_FormInfo {} {
    global page
    set html {<!-- Mail_FormInfo -->}
    if {[info exist page(query)]} {
	array set q $page(query)
	if {[info exist q(sendto)] && [info exist q(subject)]} {
	    eval {Mail/forminfo $q(sendto) $q(subject) {} {}} $page(query)
	    set html {<!-- Mail_FormInfo sent email -->}
	}
    }
    return $html
}

# Older version of mail/forminfo
proc Mail/formdata {email subject args} {
    foreach {name value} $args {
	append message "$name: $value\n"
    }
    MailSend $email $subject {} text/plain $message
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































Deleted lib/maptcl.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# maptcl.tcl
# Pure Tcl imagemap handling.
#
# 	read in an image map file, and generate the appropriate canvas
# 	# sample image map
#	circle 	/sun-on-net/internet.sol/access.html  664,311 686,311
#	default	http://www.hal.com/
#	default 	/sunsoft/index.html
#	point /sunworldonline/common/swol-subscribe.html 45,134
#	poly / 182,11 184,88 301,77 365,86 393,57 393,10 
#	rect	/sunsoft/index.html 1,1 119,34
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: maptcl.tcl,v 1.7 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::ismaptcl 1.0
package require httpd::imagemap 1.0	;# MapPointInCircle MapPointInPoly MapPointInRect
package require httpd::log	;# Log
#package require httpd::utils	;# file

# translate an x/y coordinate into a url

proc Map_Lookup {request} {
    global ImageMaps
    if {[regexp {([^?]+)\?([0-9]+),([0-9]+)} $request {} map x y]} {
	if {[catch {file mtime $map} mtime]} {
	    return ""
	}
	if {![info exists ImageMaps($map)] ||
		($mtime > $ImageMaps(mtime,$map))} {
	    set ImageMaps($map) [MapRead $map]
	    set ImageMaps(mtime,$map) $mtime
	} 
	return [MapHit $ImageMaps($map) $x $y]
    } else {
	return ""
    }
}

# MapRead - this parses a map data file and converts it to
# a Tcl array that contains state about each region.
# This parser is another famous regsub-subst combo by Steve Uhler

proc MapRead {file} {
    if {[catch {open $file} fd]} {
	Log "" "file open" $fd
	return {}
    }
    regsub -all  {\.}  $file _ cookie
    set data [read $fd]
    close $fd
    regsub -all "(^|\n+)#\[^\n]*" $data {} data
    regsub -all {([][$\\])} $data {\\\1} data
    set types circle|default|point|poly|rect
    append exp {[ 	]*(} $types {)[ 	]+([^	}
    append exp \n { ]+)[ 	]*([^} \n\r {]*)} \[\n\r]+
    regsub -nocase -all $exp $data "\[MapInsert [list $cookie] \\1 {\\2} {\\3}]" cmd
    upvar #0 $cookie map
    catch {unset map}
    subst $cmd
    return $cookie
}

# helper proc for generating the data structure

proc MapInsert {cookie type href coords} {
    upvar #0 $cookie map
    if {![info exists map]} {
	set map(N) 0
    } else {
	incr map(N)
    }
    regsub -all , $coords { } coords
    set c {}
    set i 0
    foreach {X Y} $coords {
	lappend c $i,X $X $i,Y $Y
	incr i
    }
    set map($map(N),type) $type
    set map($map(N),coords) $c
    set map($map(N),href) $href
    if {$type == "default"} {
	set map(default) $href
    }
}

# MapHit looks up coordinates in a map

proc MapHit {cookie x y} {
    upvar #0 $cookie map
    set sawpoint 0
    for {set i 0} {$i < $map(N)} {incr i} {
	array set pgon $map($i,coords)
	switch $map($i,type) {
	    poly {
		if {[MapPointInPoly $x $y pgon]} {
		    return $map($i,href)
		}
	    }
	    circle {
		if {[MapPointInCircle $x $y pgon]} {
		    return $map($i,href)
		}
	    }
	    rect {
		if {[MapPointInRect $x $y pgon]} {
		    return $map($i,href)
		}
	    }
	    point {
		set dist [expr ($x - $pgon(0,X)) * ($x - $pgon(0,X)) + \
				($y - $pgon(0,Y)) * ($y - $pgon(0,Y))]
		if {!$sawpoint || ($dist < $mindist)} {
		    set mindist $dist
		    set default $map($i,href)
		}
	    }
	}
    }
    if {[info exists default]} {
	return $default
    }
    if {[info exists map(default)]} {
	return $map(default)
    }
    return {}
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































Deleted lib/maptk.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# maptk.tcl
# simple sample image map resolver
# uses Netscape map files
#
# This version uses a Tk canvas to do hit detection.
#
# Stephen Uhler (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: maptk.tcl,v 1.6 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::ismaptk 1.0

package require httpd::log	;# Log
#package require httpd::utils	;# file

# 	read in an image map file, and generate the appropriate canvas
# 	# sample image map
#	circle 	/sun-on-net/internet.sol/access.html  664,311 686,311
#	default	http://www.hal.com/
#	default 	/sunsoft/index.html
#	point /sunworldonline/common/swol-subscribe.html 45,134
#	poly / 182,11 184,88 301,77 365,86 393,57 393,10 
#	rect	/sunsoft/index.html 1,1 119,34

# translate an x/y coordinate into a url

proc Map_Lookup {request} {
    if {[regexp {([^?]+)\?([0-9]+),([0-9]+)} $request {} map x y]} {
	if {[catch {file mtime $map} mtime]} {
	    return ""
	}
	if {![info exists ImageMaps($map)] ||
		($mtime > $ImageMaps(mtime,$map))} {
	    set ImageMaps($map) [MapRead $map]
	    set ImageMaps(mtime,$map) $mtime
	} 
	return [MapHit $ImageMaps($map) $x $y]
    } else {
	return ""
    }
}

# Resolve hits by building a canvas (which is never mapped),
# with the map objects.  Use the file name as the canvas tag.

proc MapRead {file} {
    if {[catch {open $file} fd]} {
	Log "" "file open" $fd
	return {}
    }
    regsub -all  {\.}  $file _ cookie
    set data [read $fd]
    close $fd
    catch {destroy .image$cookie}
    set can [canvas .image$cookie]
    regsub -all "(^|\n+)#\[^\n]*" $data {} data
    regsub -all {([][$\\])} $data {\\\1} data
    set types circle|default|point|poly|rect
    append exp {[ 	]*(} $types {)[ 	]+([^	}
    append exp \n { ]+)[ 	]*([^} \n\r {]*)} \[\n\r]+
    regsub -nocase -all $exp $data "\[MapInsert [list $can] \\1 {\\2} {\\3}]" cmd
    $can lower default
    set tags [$can itemconfigure default -tags]
    $can itemconfigure default -tags [lindex $tags 0]
    subst $cmd
    return $can
}

# helper proc for generating the canvas

proc MapInsert {can type href coords} {
    regsub -all , $coords { } coords
    if {[catch {
    switch -- $type {
	default {
	    upvar #0 $can default
	    set default $href
#	    $can create rectangle  0 0 1000 1000 -fill white -tags [list $href default]
	}
	circle {
	    # The coords are the center and one point on the edge.
	    # Tk ovals are defined by two corner points.
	    foreach {x1 y1 x2 y2} $coords {break}
	    set r [expr int(sqrt(($y2 - $y1) * ($y2 - $y1) + \
				    ($x2 - $x1) * ($x2 - $x1)))]
	    set x1 [expr $x1 - $r]
	    set x2 [expr $x1 + 2*$r]
	    set y1 [expr $y1 - $r]
	    set y2 [expr $y1 + 2 * $r]
	    $can create oval $x1 $y1 $x2 $y2 -fill black -tags $href
	}
	rect {
	    eval {$can create rectangle} $coords -fill black -tags {$href}
	}
	poly {
	    eval {$can create polygon} $coords -fill black -tags {$href}
	}
	point {
	    eval {$can create oval} $coords $coords -width 2 -fill black \
		    -tags {$href}
	}
    }} err]} {
	Log $can $href $err
    }
}

proc MapHit {map x y} {
    if {[catch {
	$map gettags [lindex [$map find overlapping $x $y $x $y] 0]
    } result]} {
	set result {}
    }
    if {[string length $result] == 0} {
	upvar #0 $map default
	catch {set result $default}
    }
    return $result
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































Deleted lib/md5hex.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This is a shim layer to deal with the inconsistencies
# between md5 1 and md5 2 (grr)

package provide httpd::md5hex 1.0
catch {
    # for some reason pkg_mkIndex barfs on this ... hide it.
    package require md5

    # md5hex always returns a hex version of the md5 hash

    if {[package vcompare [package present md5] 2.0] > -1} {
	# we have md5 v2 - it needs to be told to return hex
	interp alias {} md5hex {} ::md5::md5 -hex --
    } else {
	# we have md5 v1 - it returns hex anyway
	interp alias {} md5hex {} ::md5::md5
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































Deleted lib/mime.types.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#
# Thanks to [email protected]
# This is the mime.types shipped with the NCSA http server

application/activemessage
application/andrew-inset                       
application/applefile
application/atomicmail                         
application/dca-rft                            
application/dec-dx                             
application/mac-binhex40	hqx
application/macwriteii
application/msword		doc dot
application/ms-excel		xls xlw xla xlc xlm xlt
application/ms-powerpoint	ppt pps pot
application/ms-project		mpp
application/x-msaccess		mdb
application/x-msmetafile	wmf
application/x-mswrite		wri
application/x-msschedule	scd
application/news-message-id                    
application/news-transmission      
application/octet-stream       bin core exe tgz gz Z zip          
application/octet-stream       sun4 i86pc
application/oda                oda
application/pdf                pdf
application/postscript         ai eps ps       
application/remote-printing                    
application/rtf                rtf             
application/slate                              
application/x-mif      mif
application/x-javascript	js
application/wita                               
application/wordperfect5.1
application/x-cgi		cgi
application/x-csh              csh             
application/x-dvi              dvi             
application/x-hdf              hdf             
application/x-latex            latex           
application/x-netcdf           nc cdf          
application/x-ns-proxy-autoconfig pac
application/x-safetcl		thtml
application/x-server-include	shtml
application/x-sh               sh              
application/x-tcl              tcl             
application/x-tcl-subst		subst
application/x-tcl-template	tml
application/x-tcl-auth		auth
application/x-tcl-snmp		snmp
application/x-tcl-connect	xtcl
application/x-tex              tex             
application/x-texinfo          texinfo texi   
application/x-troff            t tr roff       
application/x-troff-man        man             
application/x-troff-me         me              
application/x-troff-ms         ms              
application/x-wais-source      src             
application/x-imagemap		map
application/zip                zip             
application/x-bcpio            bcpio           
application/x-cpio             cpio            
application/x-gtar             gtar            
application/x-shar             shar            
application/x-sv4cpio          sv4cpio         
application/x-sv4crc           sv4crc          
application/x-tar              tar             
application/x-ustar            ustar           
application/x-patch		patch
application/x-shockwave-flash swf
audio/basic                    au snd          
audio/x-aiff                   aif aiff aifc
audio/x-wav                    wav             
image/gif                      gif GIF        
image/ief                      ief             
image/jpeg                     jpeg jpg jpe
image/tiff                     tiff tif        
image/x-cmu-raster             ras
image/x-portable-anymap        pnm             
image/x-portable-bitmap        pbm             
image/x-portable-graymap       pgm             
image/x-portable-pixmap        ppm             
image/x-rgb                    rgb
image/x-xbitmap                xbm             
image/x-xpixmap                xpm             
image/x-xwindowdump            xwd             
message/external-body
message/news
message/partial
message/rfc822
multipart/alternative
multipart/appledouble
multipart/digest
multipart/mixed
multipart/parallel
text/html                      html htm
text/plain                     txt
text/richtext                  rtx             
text/tab-separated-values      tsv             
text/x-setext                  etx             
text/xml		       xml
application/xhtml+xml    xhtml
text/css                       css
video/mpeg                     mpeg mpg mpe    
video/quicktime                qt mov          
video/x-msvideo                avi             
video/x-sgi-movie              movie           
text/vnd.wap.wml                wml
text/vnd.wap.wmlscript          wmls
application/vnd.wap.wmlc        wmlc
application/vnd.wap.wmscriptc   wmlsc
image/vnd.wap.wbmp              wbmp
audio/mpeg	mp3
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































Deleted lib/mtype.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# mimetype.tcl --
# Code to deal with mime types
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: mtype.tcl,v 1.9 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::mtype 1.1

#package require httpd::utils	;# file

# Convert the file suffix into a mime type

# global MimeType is a mapping from file extension to mime-type

proc Mtype {path} {
    global MimeType

    set ext [string tolower [file extension $path]]
    if {[info exist MimeType($ext)]} {
	return $MimeType($ext)
    } else {
	return text/plain
    }
}

# Read a mime types file into the mimeType array.
# Set up some minimal defaults if no file is available.

proc Mtype_ReadTypes {file} {
    global MimeType

    array set MimeType {
	{}	text/plain
	.txt	text/plain
	.htm	text/html
	.html	text/html
	.tml	application/x-tcl-template
	.gif	image/gif
	.thtml	application/x-safetcl
	.shtml	application/x-server-include
	.cgi	application/x-cgi
	.map	application/x-imagemap
	.subst	application/x-tcl-subst
    }
    if {[catch {open $file} in]} {
	return
    }

    while {[gets $in line] >= 0} {
	if {[regexp {^( 	)*$} $line]} {
	    continue
	}
	if {[regexp {^( 	)*#} $line]} {
	    continue
	}
	if {[regexp {([^ 	]+)[ 	]+(.+)$} $line match type rest]} {
	    foreach item [split $rest] {
		if {[string length $item]} {
		    set MimeType([string tolower .$item]) $type
		}
	    }
	}
    }
    close $in
}

# Mtype_Accept --
#
#	This returns the Accept specification from the HTTP headers.
#	These are a list of MIME types that the browser favors.
#
# Arguments:
#	sock	The socket connection
#
# Results:
#	The Accept header, or a default.
#
# Side Effects:
#	None

proc Mtype_Accept {sock} {
    upvar #0 Httpd$sock data
    if {![info exist data(mime,accept)]} {
	return */*
    } else {
	return $data(mime,accept)
    }
}

# Mtype_Match --
#
# 	This compares a document type with the Accept values.
#
# Arguments:
#	accept	The results of Mtype_Accept
#	type	A MIME Content-Type.
#
# Results:
#	1	If the content-type matches the accept spec, 0 otherwise.
#
# Side Effects:
#	None

proc Mtype_Match {accept type} {
    foreach t [split $accept ,] {
	regsub {;.*} $t {} t	;# Nuke quality parameters
	set t [string trim [string tolower $t]]
	if {[string match $t $type]} {
	    return 1
	}
    }
    return 0
}

# Mtype_Add --
#
# 	Add a MIME type mapping
#
# Arguments:
#	suffix	A file suffix
#	type	The corresponding MIME Content-Type.
#
# Results:
#       None

proc Mtype_Add {suffix type} {
    global MimeType

    set suffix [string trimleft $suffix .]
    set MimeType([string tolower .$suffix]) $type
}

# Mtype_Reset --
#
# 	Clear all MIME type mappings
#
# Arguments:
#	None
#
# Side Effects:
#       Unsets the MimeType array

proc Mtype_Reset {} {
    global MimeType
    if {[info exist MimeType]} {
        unset MimeType
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































































Deleted lib/objects.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# objects.tcl
#
# Provides a hook for objects to process URLs
# Object that are connected are expected to expose the method:
#
# httpdMarshallArguments [suffix] [cgiList]
#
# Returns a command that is immediately evaluated, usually in the
# form of [object] [method] [key/value list]
#
# For an example of this system in action, see custom/objects.tcl
# in the distribution
#
# Copyright
# Sean Woods (c) 2008
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: objects.tcl,v 1.1 2008/05/06 00:17:47 eviltwinskippy Exp $


package provide httpd::objects 1.0


# Object_Url
#	Define a subtree of the URL hierarchy that is implemented by
#	direct Tcl calls to a Tao Object.
#
# Arguments
#	virtual The name of the subtree of the hierarchy, e.g., /device
#	object	The Tcl object to use when constructing calls,
#		e.g. Device
#	inThread	True if this should be dispatched to a thread.
#
# Side Effects
#	Register an object

proc ::Object_Url {virtual object {inThread 0}} {
    global Direct
    set Direct($object) $virtual    ;# So we can reconstruct URLs
    Url_PrefixInstall $virtual [list ObjectDomain $object] $inThread
}

# Object_UrlRemove
#       Remove a subtree of the URL hierarchy that is implemented by
#       direct Tcl calls.
#
# Arguments
#       object  The Tcl object used when constructing calls,
#
# Side Effects
#
       
proc ::Object_UrlRemove {object} {
    global Direct
    catch { Url_PrefixRemove $Direct($object) }
    catch { unset Direct($object) }
}
        
# Main handler for Object domains (i.e. tcl commands)
# object: the object registered with Object_Url 
# sock: the socket back to the client
# suffix: the part of the url after the object.
#
# This calls out to the Object with the suffix being either
# a direct method to this object, a reference to an object
# and a method to call to the referered object.
#
# All parameters from the form are fed into a Dict
# All object method called must be prefixed with "httpd"
#
# Example:
# Object_Url /device Device
# if the URL is /device/a/display, then the Tcl command to handle it
# should be
# proc [Device /node a] httpdDisplay
#
# You can define the content type for the results of your procedure by
# modifying the global ::page(content-type) field
#
# ::page(content-type) is reset to text/html every pageview

proc ::ObjectDomain {object sock suffix} {
    global Direct
    global env
    upvar #0 Httpd$sock data
    global page
    set page(content-type) text/html

    # Set up the environment a-la CGI.

    Cgi_SetEnv $sock $object
    #$suffix

    # Prepare an argument data from the query data.

    Url_QuerySetup $sock
    set cmd [$object httpdMarshallArguments $suffix [::ncgi::nvlist]]
    
    if {$cmd == ""} {
	Doc_NotFound $sock
	return
    }
    set code [catch $cmd result]
    
    ::Object_Respond $sock $code $result $page(content-type)
}

# Object_Respond --
#
#	This function returns the result of evaluating the object
#	url.  Usually, this involves returning a page, but a redirect
#	could also occur.
#
# Arguments:
# 	sock	The socket back to the client.
#	code	The return code from evaluating the direct url.
#	result	The return string from evaluating the direct url.
#	type	The mime type to use for the result.  (Defaults to text/html).
#
# Notes: Cargo Culted from Direct_Url Code. May start to differ later.
#
# Results:
#	None.
#
# Side effects:
#	If code 302 (redirect) is passed, calls Httpd_Redirect to 
#	redirect the current request to the url in result.
#	If code 0 is passed, the result is returned to the client.
#	If any other code is passed, an exception is raised, which
#	will cause a stack trace to be returned to the client.
#

proc ::Object_Respond {sock code result {type text/html}} {
    switch $code {
	0 {
	    # Fall through to Httpd_ReturnData.
	}
	302	{
	    # Redirect.

	    Httpd_Redirect $result $sock
	    return ""
	}
	default {
	    # Exception will cause error page to be returned.

	    global errorInfo errorCode
	    return -code $code -errorinfo $errorInfo -errorcode $errorCode \
		    $result
	}
    }

    # See if a content type has been registered for the URL.

    # Save any return cookies which have been set.
    # This works with the Doc_SetCookie procedure that populates
    # the global cookie array.
    ::Cookie_Save $sock

    ::Httpd_ReturnData $sock $type $result
    return ""
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































Deleted lib/open.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# opentrace.tcl --
#
# This is a wrapper around the open command that keeps track of what
# file (or pipe) was opened for a particular channel.  Useful for
# debugging file descriptor leaks.
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: open.tcl,v 1.3 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::opentrace 1.0

#package require httpd::utils	;# file

if {[info commands "open-orig"] == ""} {
    rename open open-orig
    proc open {path {mode r} {perms {}}} {
	global OpenFiles
	if {[catch {
	    if {[string length $perms]} {
		set io [open-orig $path $mode $perms]
	    } else {
		set io [open-orig $path $mode]
	    }
	} err]} {
	    return -code error $err
	}
	set OpenFiles($io) $path
	return $io
    }
}

if {[info commands "close-orig"] == ""} {
    rename close close-orig
    proc close {io} {
	global OpenFiles
	if {[info exist OpenFiles($io)]} {
	    set OpenFiles($io) "CLOSED $OpenFiles($io)"
	}
	close-orig $io
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































Deleted lib/passcheck.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# passcheck.tcl
# 
package provide httpd::passcheck 1.0

namespace eval passcheck { }

# Copyright(c) Genesys Software Romania srl., 2000
#
# License is granted here to use this code for any purpose, 
# No warranties included.
#
# 
# 
# Provides password checking against various systems.
# Useful with TCLHTTPD server, available from http://www.tcl.tk/
#
# The purpose is to avoid maintaining duplicate password tables
# for tclhttpd, and re-use instead existing systems available in your local net.
# This way users dont need to remember many passwords - just use known passwords.
#
#
# Currently implemented are pop3 and odbc checkers. 
#
# Use pop3 pass checker to authenticate users against an pop mail server
# it requires pop3 package 
# 
# Use odbc pass checker to perform authentication against a ODBC datasource 
# available locally to the web server. 
# 
# 
# You can add your passcheckers by providing procedures with the following
# syntax and name conventioni: (we consider thi will authenticate against LDAP:
#
# proc ::passcheck::verify_ldap {sock realm user pass {config {}}} { .... return 1 or 0 }
# 
# the sock, realm, user, pass arguments are the same as received by a .tclaccess "callback"
# command.
#
# the config argument should provide significant configuration options for the checker.
# e.g. for pop3 it should be a mail server machine name, running pop3 service, 
# and for odbc - a datasource name.
#
# Other usefull commands are here - to see wich types of checkers are available, 
# to clear password caches
# for specific or all realms, to see wich realms and how are configured. 
# Author: Cezar Totth <[email protected]>
#
set ::passcheck::comment {

 #
 # You'll probably need to add these in your tclhttpd.rc file..
 #
 package require httpd::passcheck
 #
 ################# POP3 example 
 # Configure checker to use pop3 authentication for the realm named "LocalMail" against 
 # an existing local pop server. 

 set pop3server 192.168.50.5 
 ::passcheck::setChecker LocalMail pop3 $pop3server

 #
 ######################## 
 #Then  you can specify within any .tclaccess file:
 realm LocalMail
 callback ::passcheck::Verify

 ########################
 
 ################# ODBC example ##########################
 # Configure it to authenticate against a datasource.
 # The realm will be named "DbServer"
 ::passcheck::setChecker DbServer odbc $datasource

 ###### and in .tclaccess files: 
 realm DbServer
 callback ::passcheck::Verify

}

################################  End of comment here ...

proc ::passcheck::setChecker {realm passcheckerName {confopt {}}} {
  set ::passcheck::_Config($realm) [list verify_$passcheckerName $confopt]
}

proc ::passcheck::unsetConf {realm} {
  catch {unset ::passcheck::_Config($realm)}
}
#
# The pass checker configuration for all realms. 
#
set ::passcheck::DefaultChecker [list verify_deny {}]

proc ::passcheck::getChecker realm { 
  upvar #0 ::passcheck::_Config($realm) myConf
  if {[info exists myConf]} { return $myConf }
  return ${::passcheck::DefaultChecker}
}

proc ::passcheck::getCheckerConf {realm} { return  [lindex [::passcheck::getChecker $realm] 1] }
proc ::passcheck::getCheckerName {realm} { return  [lindex [::passcheck::getChecker $realm] 0] }

#
# Returns the available types of passcheckers (e.g. pop3, odbc, never, allways..)
proc ::passcheck::getCheckerTypes {} {
  set toR {}
  foreach cname [info commands ::passcheck::verify_*] {
    lappend toR [lindex [split $cname _] 1]
  }
  return $toR
}

#
# returns wich realms are controlled by our pass checkers
proc ::passcheck::getRealms {} {
  return [array names ::passcheck::_Config] 
}

#
# Use this to clear password caches. Needed after users changed their passwords.
# No realm specified means to clear all caches of all realms.
proc ::passcheck::clearCache {{realm {}}} {
  if {![llength $realm]} { 
     set rlist [info vars ::passcheck::_passCache_*]
  } else { set rlist ::passcheck::_passCache_$realm } 
  foreach carr $rlist {
     catch { unset $carr } 
  }
}

#
# this is to be specified from .tclaccess files on tclhttpd.
# add lines:
# 
# set realm ARealmName
# set callback ::passcheck::Verify
# 
proc ::passcheck::Verify {socket realm user pass}  {
   upvar #0 ::passcheck::_passCache_$realm pcache
   set kpass [crypt $pass 91] 
   if {[info exists pcache($user)]} {
     if { "$kpass" == "$pcache($user)" } { 
       set ::env(REMOTE_USER) $user
       return 1 
     } else { unset pcache($user) }
   } 
   set pcheck [::passcheck::getChecker $realm]
   set tocall [list [lindex $pcheck 0] $socket $realm $user $pass [lindex $pcheck 1]]
   # puts "will call: $tocall"
   set rez 0 
   catch { set rez [eval $tocall] } 
   if {$rez} {
       set pcache($user) $kpass
       set ::env(REMOTE_USER) $user 
   }
   return $rez
}

############################## Basic Auth --> Pop3 authentication ######################
#
# By default the tcl server is considered to run on the email server.
# On most Unix-like systems this means authentication is made against
# the local system
proc ::passcheck::verify_pop3 {socket realm user pass {conf localhost}} {
   if {[catch {::pop3::close [::pop3::open $conf $user $pass]}] } { 
       return 0 
   } 
   return 1
}

############################# TCLODBC Datasource authentication #######################
proc ::passcheck::verify_odbc {socket realm user pass {conf passcheck}} {
  if {[catch {
         database _passCheck_db$conf$user $conf $user $pass
      } ] } { return 0 }
  _passCheck_db$conf$user disconnect
  return 1
}
#
############################ Dummy pass checkers ######################################
# These are dummy pass checkers. Usefull in automated tests, or to temporarly lock/unlock
# realms
proc ::passcheck::verify_deny  {socket realm user pass {conf {}}} { return 0 }
proc ::passcheck::verify_allow {socket realm user pass {conf {}}} { return 1 }

########################### external packages availability #######################
# 
# warning messages. Shall it go to server's log too? 
proc ::passcheck::warning message { 
    puts "passcheck: $message" 
}
#
#
# Is better to have crypt handy  to cache passwords with more confidence. 
if { [catch { package require crypt } ] } {
  # we provide a dummy crypt...
  package require tclcrypt
  #::passcheck::warning {no crypt package available! passwords cached in cleartext!}
  #proc crypt {word salt} { return "${word}$salt" }
}

#
# checking for POP3 
if { [catch { package require pop3 } ] } { 
  ::passcheck::warning {no POP3 pass check available! verify pop3 package}
  # rename pop3_verify pop3_notAvail 
}

#
# checking for TCLODBC 
if { [catch { package require tclodbc } ] } {
  ::passcheck::warning {no ODBC pass check available! verify tclodbc package}
  # rename odbc_verify odbc_notAvail 
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































Deleted lib/passgen.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# password generator
# generate a password according to the passgen_rules array
#
# Source: http://mini.net/tcl/Password%20Generator
# Author: Mark Oakden http:/wiki.tcl.tk/MNO
# Version: 1.0

# no sanity checks on the supplied rules are done.

package provide httpd::passgen 1.0

# datasets for password generation:-
# separate lowercase and UPPERCASE letters so we can demand minimum
# number of each separately.
array set passgen {
    letters "abcdefghijklmnopqrstuvwxyz"
    LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    numbers "0123456789"
    punctuation "!\"\x{00A3}$%^&*()_+-={};':@#~<>,.?/\\|"
}

# a simpler set might be, for example:-
#
# set passgen(letters) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
# set passgen(numbers) "0123456789"
# set passgen(punctuation) "!\"\x{00A3}$%^&*()_+-={};':@#~<>,.?/\\|"
    
# the rules determine characteristics of the randomly generated passwords
# presently available are:-
# passgen_rules(len) password length
# passgen_rules(<dataset_name>,min) minimum number of characters from <dataset_name>
# entry on the passgen array

# example rules:-
# password 7 chars long, with at least one U/C char, one l/c char,
# one number and one punctuation.
array set passgen_rules {
    len 7
    letters,min 1
    LETTERS,min 1
    numbers,min 1
    punctuation,min 1
}

# example rules appropriate to the commented "simpler" datasets above:-
#
# set passgen_rules(len) 7
# set passgen_rules(numbers,min) 1
# set passgen_rules(punctuation,min) 1

# picks a (pseudo)random char from str
proc PassgenOneCharFrom { str } {
    set len [string length $str]
    set indx [expr int(rand()*$len)]
    return [string index $str $indx]
}

# given a string, and integers i and j, swap the ith and jth chars of str
# return the result
proc PassgenSwap { str i j } {
    if { $i == $j } {
	return $str
    }
    if { $i > $j } {
	set t $j
	set j $i
	set i $t
    }
    set pre [string range $str 0 [expr $i - 1]]
    set chari [string index $str $i]
    set mid [string range $str [expr $i + 1] [expr $j - 1]]
    set charj [string index $str $j]
    set end [string range $str [expr $j + 1] end]
    
    set ret ${pre}${charj}${mid}${chari}${end}
    return $ret
}

# for a string of length n,  swap random pairs of chars n times
# and return the result
proc PassgenShuffle { str } {
    set len [string length $str]
    for { set i 1 } { $i <= $len } { incr i 1 } {
	set indx1 [expr int(rand()*$len)]
	set indx2 [expr int(rand()*$len)]
	set str [PassgenSwap $str $indx1 $indx2]
    }
    return $str
}

# generate a password
proc Passgen_Generate {} {
    variable passgen
    variable passgen_rules

    # Algorithm
    # 1. foreach dataset with a min parameter, choose exactly min
    #    random chars from it
    # 2. concatenate results of above into password
    # 3. concatenate all datasets into large dataset
    # 4. choose desired_length-password_length chars from large
    # 5. concatenate (4) and (2)
    # 6. shuffle (5)
    
    set password {}
    foreach indx [array names passgen_rules *,min] {
	set ds_name [lindex [split $indx ,] 0]
	set num $passgen_rules($indx)
	for {set i 1} {$i <= $num} {incr i 1} {
	    append password [PassgenOneCharFrom $passgen($ds_name)]
	}
    }
    
    set all_data {}
    foreach set [array names passgen] {
	append all_data $passgen($set)
    }
    
    set rem_len [expr $passgen_rules(len) - [string length $password]]
    for {set i 1} {$i <= $rem_len} {incr i 1} {
	append password [PassgenOneCharFrom $all_data]
    }
    
    return [PassgenShuffle $password]
}

set passgen(saltstr) "$passgen(LETTERS)$passgen(letters)$passgen(numbers)"
proc Passgen_Salt {} {
    global passgen
    set slen [string len $passgen(saltstr)]
    return "[string index $passgen(saltstr) [expr round(rand() * $slen)]][string index $passgen(saltstr) [expr round(rand() * $slen)]]"
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































Deleted lib/pkgIndex.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex -direct" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd 1.7 [list source [file join $dir httpd.tcl]]
package ifneeded httpd::admin 1.0 [list source [file join $dir admin.tcl]]
package ifneeded httpd::auth 2.0 [list source [file join $dir auth.tcl]]
package ifneeded httpd::cgi 1.1 [list source [file join $dir cgi.tcl]]
package ifneeded httpd::compat 3.3 [list source [file join $dir compat.tcl]]
package ifneeded httpd::config 1.0 [list source [file join $dir config.tcl]]
package ifneeded httpd::cookie 1.0 [list source [file join $dir cookie.tcl]]
package ifneeded httpd::counter 2.0 [list source [file join $dir counter.tcl]]
package ifneeded httpd::debug 1.0 [list source [file join $dir debug.tcl]]
package ifneeded httpd::digest 1.0 [list source [file join $dir digest.tcl]]
package ifneeded httpd::direct 1.1 [list source [file join $dir direct.tcl]]
package ifneeded httpd::dirlist 1.1 [list source [file join $dir dirlist.tcl]]
package ifneeded httpd::doc 1.1 [list source [file join $dir doc.tcl]]
package ifneeded httpd::doc_error 1.0 [list source [file join $dir doc_error.tcl]]
package ifneeded httpd::doctools 1.0 [list source [file join $dir doctools.tcl]]
package ifneeded httpd::fallback 1.0 [list source [file join $dir fallback.tcl]]
package ifneeded httpd::imagemap 1.0 [list source [file join $dir imagemap.tcl]]
package ifneeded httpd::include 1.0 [list source [file join $dir include.tcl]]
package ifneeded httpd::ismaptcl 1.0 [list source [file join $dir maptcl.tcl]]
package ifneeded httpd::ismaptk 1.0 [list source [file join $dir maptk.tcl]]
package ifneeded httpd::log 1.1 [list source [file join $dir log.tcl]]
package ifneeded httpd::logstd 1.0 [list source [file join $dir logstd.tcl]]
package ifneeded httpd::mail 1.0 [list source [file join $dir mail.tcl]]
package ifneeded httpd::md5hex 1.0 [list source [file join $dir md5hex.tcl]]
package ifneeded httpd::mtype 1.1 [list source [file join $dir mtype.tcl]]
package ifneeded httpd::opentrace 1.0 [list source [file join $dir open.tcl]]
package ifneeded httpd::passcheck 1.0 [list source [file join $dir passcheck.tcl]]
package ifneeded httpd::passgen 1.0 [list source [file join $dir passgen.tcl]]
package ifneeded httpd::redirect 1.0 [list source [file join $dir redirect.tcl]]
package ifneeded httpd::safecgio 1.0 [list source [file join $dir safecgio.tcl]]
package ifneeded httpd::session 1.0 [list source [file join $dir session.tcl]]
package ifneeded httpd::srvui 1.0 [list source [file join $dir srvui.tcl]]
package ifneeded httpd::status 1.0 [list source [file join $dir status.tcl]]
package ifneeded httpd::stdin 1.1 [list source [file join $dir stdin.tcl]]
package ifneeded httpd::subst 1.0 [list source [file join $dir subst.tcl]]
package ifneeded httpd::template 1.0 [list source [file join $dir template.tcl]]
package ifneeded httpd::threadmgr 1.0 [list source [file join $dir thread.tcl]]
package ifneeded httpd::upload 1.0 [list source [file join $dir upload.tcl]]
package ifneeded httpd::url 1.2 [list source [file join $dir url.tcl]]
package ifneeded httpd::utils 1.0 [list source [file join $dir utils.tcl]]
package ifneeded httpd::version 3.5 [list source [file join $dir version.tcl]]
package ifneeded tclcrypt 1.0 [list source [file join $dir tclcrypt.tcl]]
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































Deleted lib/prodebug.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# prodebug.tcl --
#
#	This file contains the public routines used to start debugging user
#	code in a remote application.
#
# Copyright (c) 1998-2000 by Ajuba Solutions
# All rights reserved.
#
# RCS: @(#) $Id: prodebug.tcl,v 1.1 2000/08/02 07:06:53 welch Exp $


#
# This file comprises the public interface to the TclPro Debugger for use
# by applications that are not launched directly from the debugger.  The
# public interface consists of the two commands "debugger_init" and
# "debugger_eval".  A typical application will source this file then invoke
# "debugger_init" to initiate the connection to the debugger.  Once
# connected, the application can use the "debugger_eval" command to
# evaluate scripts that the debugger will be able to step through.
# Additionally, various other Tcl commands including "source" and "proc"
# will automatically instrument code.  Any blocks of code (e.g. procedure
# bodies) that existed before "debugger_init" was invoked will execute
# without any instrumentation.
#


# debugger_init --
#
#	This function initiates a connection to the TclPro Debugger.  Files
#	that are sourced and procedures that are defined after this
#	function completes will be instrumented by the debugger.
#
# Arguments:
#	host	Name of the host running the debugger.
#	port	TCP port that the debugger is using.
#
# Results:
#	Returns 1 on success and 0 on failure.


proc debugger_init {{host 127.0.0.1} {port 2756}} {
    global tcl_version

    if {[catch {set socket [socket $host $port]}] != 0} {
	return 0
    }
    fconfigure $socket -blocking 1 -translation binary

    # Send the loader and tcl library version

    set msg [list HELLO 1.0 $tcl_version]
    puts $socket [string length $msg]
    puts -nonewline $socket $msg
    flush $socket

    # Get the rest of the nub library and evaluate it in the current scope.
    # Note that the nub code assumes there will be a "socket" variable that
    # contains the debugger socket channel.

    if {[gets $socket bytes] == -1} {
	close $socket
	return 0
    }
    set msg [read $socket $bytes]
    eval [lindex $msg 1]
    return 1
}

# debugger_eval --
#
#	Instrument and evaluate a script.  This routine is a trivial
#	implementation that is replaced when the nub is downloaded.
#
# Arguments:
#	args		One or more arguments, the last of which must
#			be the script to evaluate.
#
# Results:
#	Returns the result of evaluating the script.

proc debugger_eval {args} {
    global errorInfo errorCode
    set length [llength $args]
    if {$length < 1} {
	error "wrong # args: should be \"debugger_eval ?options? script\""
    }
    set code [catch {uplevel 1 [lindex $args [expr {$length - 1}]]} result]
    return -code $code -errorcode $errorCode -errorinfo $errorInfo $result
}


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































Deleted lib/redirect.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# redirect.tcl
#
# Support for redirecting URLs.
# You can either do a single redirect (Redirect_Url)
# or you can redirect a whole subtree elsewhere (Redirect_UrlTree)
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: redirect.tcl,v 1.7 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::redirect 1.0

package require httpd	;# Httpd_Redirect Httpd_RedirectSelf Httpd_SelfUrl
package require httpd::direct	;# Direct_Url
package require httpd::url	;# Url_AccessInstall Url_Dispatch Url_PrefixInstall Url_Unwind
#package require httpd::utils	;# file

# Redirect_To --
#
# Trigger a page redirect
#
# Arguments:
#	newurl	The new URL
#
# Results:
#	None
#
# Side Effects:
#	Raises a special error that is caught by Url_Unwind

proc Redirect_To {newurl} {
    return -code error \
	    -errorcode  [list HTTPD_REDIRECT $newurl] \
	    "Redirect to $newurl"
}

# Redirect_Self --
#
#	Like Redirect_To, but to a URL that is relative to this server.
#
# Arguments:
#	newurl	Server-relative URL
#
# Results:
#	None
#
# Side Effects:
#	See Redirect_To

proc Redirect_Self {newurl} {
    set thispage [ncgi::urlStub]
    set thisurl [Httpd_SelfUrl $thispage]
    set newurl [uri::resolve $thisurl $newurl]
    Redirect_To $newurl
}


# Redirect_QuerySelf --
#
#	Like Redirect_Self, but preserves query data
#
# Arguments:
#	newurl	Server-relative URL
#
# Results:
#	None
#
# Side Effects:
#	See Redirect_To

proc Redirect_QuerySelf {sock newurl} {
    upvar #0 Httpd$sock data

    # Preserve query data when bouncing among pages.
    if {[info exist data(query)] && [string length $data(query)]} {
	append newurl ? $data(query)
    }

    Redirect_Self $newurl	;# offer what we have to the client
}

# Redirect_Dir --
#
# Generate a redirect because the trailing slash isn't present
# on a URL that corresponds to a directory.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generate a redirect page.

proc Redirect_Dir {sock} {
    global Httpd
    upvar #0 Httpd$sock data

    set url  $data(url)/
    if {[info exist data(query)] && [string length $data(query)]} {
	# maintain the query data
	append url ? $data(query)
    }
    Httpd_Redirect $url $sock
}

# Redirect_Init
#
#	Initialize the redirect module.
#
# Arguments:
#	url	(optional) Direct URL for redirect control.
#
# Side Effects:
#	Registers access hook to implement redirects.
#	May register direct domain

proc Redirect_Init {{url {}}} {
    if {[string length $url]} {
	Direct_Url $url Redirect
    }
    # The [list] makes the eval in Url_Dispatch run slightly faster
    Url_AccessInstall [list RedirectAccess]

    # Load the default redirect file
    Redirect/reload
}

# Redirect_UrlTree
#
#	Map a whole URL hierarchy to a new place
#
# Arguments:
#	old	Old location, (e.g., /olddir)
#	new	New location, (e.g., /newdir)
#
# Side Effects:
#	Future requests to old/a/b/c will redirect to new/a/b/c

proc Redirect_UrlTree {old new} {
    Url_PrefixInstall $old [list RedirectDomain $new]
}

# RedirectDomain
#
#	Set up a domain that redirects requests elsewhere
#	To use, make a call like this:
#
#	Url_PrefixInstall /olddir [list RedirectDomain /newdir]
#
# Arguments:
#	prefix	The Prefix of the domain
#	url	The other URL to which to redirect
#
# Results:
#	This always raises a redirect error

proc RedirectDomain {url sock suffix} {
    set newurl $url$suffix
    Httpd_Redirect $newurl $sock
}

# Redirect_Url
#
#	Redirect a single URL to another, fully-qualified URL.
#
# Arguments:
#	old	Old location, (e.g., /olddir/file.html)
#	new	New location, (e.g., http://www.foo.bar/newdir/newfile.html)
#
# Side Effects:
#	Future requests to $old will redirect to $new

proc Redirect_Url {old new} {
    global Redirect
    set Redirect($old) $new
}

# Redirect_UrlSelf
#
#	Redirect a single URL to another location on the same server.
#
# Arguments:
#	old	Old location, (e.g., /olddir/file.html)
#	new	New location, (e.g., /newdir/newfile.html)
#
# Side Effects:
#	Future requests to $old will redirect to $new

proc Redirect_UrlSelf {old new} {
    global RedirectSelf

    # Cannot make the "self" computation until we have
    # a socket and know the protocol and server name for sure

    set RedirectSelf($old) $new
}

# RedirectAccess
#
#	This is invoked as an "access checker" that will simply
#	redirect a URL to another location.
#
# Arguments:
#	sock	Current connection
#	url	The url of the connection
#
# Results:
#	Returns "denied" if it triggered a redirect.  This stops URL processing.
#	Returns "skip" otherwise, so other access control checks can be made.

proc RedirectAccess {sock url} {
    global Redirect
    global RedirectSelf

    if {[info exist RedirectSelf($url)]} {
	
	# Note - this is not an "internal" redirect, but in this case
	# the server simply qualifies the url with its own name

	Httpd_RedirectSelf $RedirectSelf($url) $sock
	return denied
    }
    if {[info exist Redirect($url)]} {
	Httpd_Redirect $Redirect($url) $sock
	return  denied
    }
    return skip
}

# Redirect/reload
#
#	Direct URL to reload the redirect configuration file.
#
# Arguments:
#	none
#
# Side Effects:
#	Sources "redirect" from the document root.

proc Redirect/reload {} {
    global Doc
    set path [file join $Doc(root) redirect]
    if { ! [file exists $path]} {
	return
    }
    source $path
    set html "<h3>Reloaded redirect file</h3>"
    append html [Redirect/status]
    return $html
}

# Redirect/status
#
#	Display the Redirection tables
#
# Arguments:
#	none
#
# Results:
#	An HTML table

proc Redirect/status {} {
    global Redirect
    global RedirectSelf
    global Url	;# hack alert

    append html "<h3>Redirect Table</h3>\n"
    append html "<table>\n"
    append html "<tr><th colspan=2>Single URLs</th></tr>\n"
    foreach old [lsort [array names RedirectSelf]] {
	append html "<tr><td>$old</td><td>$RedirectSelf($old)</td></tr>\n"
    }
    foreach old [lsort [array names Redirect]] {
	append html "<tr><td>$old</td><td>$Redirect($old)</td></tr>\n"
    }
    append html "<tr><th colspan=2>URL Subtrees</th></tr>\n"
    foreach prefix [lsort [array names Url command,*]] {
	if {[string match RedirectDomain* $Url($prefix)]} {
	    set new [lindex $Url($prefix) 1]
	    regsub command, $prefix {} prefix
	    append html "<tr><td>$prefix</td><td>$new</td></tr>\n"
	}
    }
    append html </table>\n
    return $html
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































































































































































































































































































































Deleted lib/safecgio.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# safecgio.tcl
# Brent Welch (c) 1996 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
#
# RCS: @(#) $Id: safecgio.tcl,v 1.8 2004/10/22 03:43:06 coldstore Exp $
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

# Safe Tcl security policy for server-side CGI-like processing.
# The HTTPD will "subst" an html page in the context of a safecgio interpreter
# in order to efficiently compute a page.  This security policy gives the
# safe interpreter limited access to files within a specified directory.
#
#  The script has access to the "env" array, which contains the same
#  information as for a CGI bin script.
#
#  Any query information, either from a POST or GET query is available
#  as a name-value list in the "Query" variable.

package provide httpd::safecgio 1.0

package require httpd::log	;# Log
package require httpd::utils	;# Stderr file

# start a safe CGI server 

proc SafeCGI_Server {port} {
    if {[catch {socket -server SafeCGI_Accept $port} oops]} {
	Stderr "SafeCGI_Server: $oops"
	exit 1
    }
}

# Accept a connection from Httpd server.

proc SafeCGI_Accept {sock addr port} {
    fconfigure $sock -blocking off
    fileevent $sock readable [list SafeCGIRead $sock]
}

# Read and execute commands from the Http server

proc SafeCGIRead {sock} {
    global Env Query

    if {[eof $sock]} {
	close $sock
    } else {
	set command {}
	foreach {command value} [gets $sock] break
	switch -- $command {
	    SetEnv	{ catch {array set Env $value} }
	    SetQuery	{ set Query $value }
	    DoFile	{ SafeCGIDo $sock $value }
	    Exit	{ exit }
	}
    }
}

# Create a safe interpreter to "subst" a data file.

proc SafeCGIDo {sock filename} {
    global Query Env argv0

    if {![catch {open $filename} fd]} {
	append Query {}
	set child child$sock		;# Name of child interpreter
	SafeCGI_Create $child 
	interp transfer {} $fd $child
	interp eval $child {
	    proc DoCGI {fd Query envlist} {
		global env
		array set env $envlist
		subst [read $fd]
	    }
	}

	if {![catch {
	    interp eval $child [list DoCGI $fd $Query [array get Env]]
	} result]} {
	    puts -nonewline $sock $result
	} else {
	    Log $sock SafeCGIDo "$argv0 Error in $filename\n\t<$result>"
	}
	interp delete $child		;# Does close of transferred fd
    }
    close $sock
}

# security policy defined below.
#####################################################################
#
# Create a child that is limted to a few open files within
# a given directory.  If they open for writing, limit the size
# of the output file.

proc SafeCGI_Create {name {directory .} {maxopen 4} {maxsize 4096}} {
    global interpState
    interp create -safe $name
    interp alias $name open {} SafeCGI_Open $name $maxopen $directory
    interp eval  $name {rename puts {}}
    interp alias $name puts {} SafeCGI_Puts $name $maxsize
    interp eval  $name {rename close _close}	;# would rather "hide" this
    interp alias $name close {} SafeCGI_Close $name
    interp alias $name exit {} SafeCGI_Cleanup $name
    set interpState(channels,$name) {}
}

# Open files in a given directory.
# Paramters set by the definition of the alias:
# 	interp is a child interperter
# 	maxopen is the max number of open files for the child
# 	directory is the directory
# Parameters from the child's call
# 	file is the name of the file
# 	access is the I/O mode

proc SafeCGI_Open {interp maxopen directory file {access r}} {
    global interpState

    if {[llength $interpState(channels,$interp)] >= $maxopen} {
	error "couldn't open \"$file\": too many open files"
    }
    if {[regexp "^\[ \t\]*|" $file]} {
	error "no pipes allowed"
    }
    # Constrain the pathname to a one-component relative name
    if {([llength [file split $file]] != 1) ||
	    [file pathtype $file] != "relative"} {
	error "couldn't open \"$file\": permission denied"
    }
    # Disallow symbolic links and other non-file types
    set path [file join $directory $file]
    if {[file exists $path]} {
	file lstat $path stat		;# lstat here prevents symlinks
	if {$stat(type) != "file"} {
	    error "couldn't open \"$file\": not a plain file"
	}
    }
    set out [open $path $access]
    lappend interpState(channels,$interp) $out
    interp share {} $out $interp
    return $out
}
    # This is an alias to clean up children that exit
    # interp is the exiting child
    # interpState records open files for the child
    # We share them, so we must close our references.

proc SafeCGI_Cleanup {interp} {
    global interpState

    interp delete $interp
    foreach out $interpState(channels,$interp) {
	catch {close $out}
    }
    unset interpState(channels,$interp)
}

# This is an alias for puts that limits file size
# Parameters set by the alias definition:
# 	interp is the child interpreter
# 	max is the file size limit, in bytes
# Parameters set in the call to the alias
#   args is ?-nonewline? chan string
# 		chan is the I/O channel
# 		string is the output data

proc SafeCGI_Puts {interp max args} {
    if {[string match "-nonewline" [lindex $args 0]]} {
	set flag -nonewline
	set args [lrange $args 1 end]
    } else {
	set flag ""
    }
    if {[llength $args] == 1} {
	# Flag output to stdout as coming from the unsafe interpreter
	set chan stdout
	set string "Untrusted code $name says: [lindex $args 0]"
    } elseif {[llength $args] == 2} {
	set chan [lindex $args 0]
	set string [lindex $args 1]
    } else {
	error "wrong # args: should be \"puts ?-nonewline? ?channelId? string\""
    }
    if {[string match "stdout" $chan"]} {
	set size [string length $string]	;# Tell makes no sense
    } else {
	set size [expr [tell $chan] + [string length $string]]
    }
    if {$size > $max} {
	    interp eval $interp [list close $chan]
	    error "File size exceeded"
    } else {
	    eval puts $flag {$chan $string}
    }
}

# An alias for close that lets the parent clean up its reference

proc SafeCGI_Close {interp chan} {
	global interpState
	set ix [lsearch $interpState(channels,$interp) $chan]
	if {$ix >= 0} {
	    catch {close $chan}
	    set interpState(channels,$interp) \
		    [lreplace $interpState(channels,$interp) $ix $ix]
	}
	$interp eval _close $chan	;# Need "invoke" hidden close
}

    proc bgerror {msg} {
	global errorInfo
	Stderr $errorInfo
    }
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































Deleted lib/session.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
 # session.tcl -- 
# Session management support.
#
# A session is implemented as a safe slave interpreter that holds its state.
#
# Creating a session with Session_Create returns either a 4 character ID
# (if MD5 is missing or Session(short) is true) or an unforgeable MD5
# hash.
#
# Use Session_Match to find and/or create a session based on query data.
#
# Use Session_Destroy to delete one session, and Session_Reap to
# clean up "old" sessions.
#
# A session has a type, which is used to automatically create aliases for
# the slave.  If the type is Foo, then every Tcl procedure named Foo_*
# in the master will be created as an alias.  The Foo_ prefix gets
# stripped off the alias name in the slave.
#
# Certain first arguments are treated specially for the aliases:
# if the first argument is "session", then the alias automatically
# gets called with the current session ID as the first argument.
# if the first argument is "interp", then the alias automatically
# gets called with the interp name as the first argument.
# (From a session you get also get the interp name).
#
# In addition, a few aliases are defined for all types:
# session - returns the session identifier
# sequence - returns an increasing sequence number used to chain together
# 	pages and detect bookmarks and "backs" that screw things up.
# group - set or get the current session "group".
# value - get a value from the current "group", or a default value
#
# Session state can be organized in "groups", which are just Tcl arrays
# in the safe interpreters.  The master keeps track of the current group
# for a session, and the slave can change the group and query group
# values with the "value" alias.  There is no standard for setting
# group values, but typically query data is copied into them by
# the module that uses the sessions.
#
# Stephen Uhler  (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: session.tcl,v 1.16 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::session 1.0

package require httpd::cookie	;# Cookie_GetSock Cookie_Make
package require httpd::doc	;# Doc_Root
package require httpd::utils	;# Stderr file iscommand randomx

# use long session IDs
if {![info exists Session(short)]} {
    set Session(short) 0
}

# how long do session cookies last?
if {![info exists Session(expires)]} {
    set Session(expires) "now + 10 years"	;# should be long enough
}

# if an MD5 package is available, we use it to make
# an unforgeable session ID, otherwise default to 
# the old 4-digit session ID
if {($Session(short) == 1) || [catch {package require httpd::md5hex}]} {
    # we have no usable md5 or have elected short session IDs
    proc SessionGenId {} {
	return [randomx]
    }
} else {
    # generate a long and unforgeable session id
    proc SessionGenId {} {
	return [md5hex [randomx]]
    }
}

proc Session_Authorized {id} {
    upvar #0 Session:$id session
    if {![info exists session(interp)]} {
	set interp [SessionCreate $id]
	SessionAuthorizedAliases $interp $id
    }
    return $session(interp)
}

proc SessionAuthorizedAliases {interp id} {
    upvar #0 Session:$id session
    interp alias $interp require {} Session_Require $id
    interp alias $interp exit {} Session_Destroy $id
}

proc Session_Require {id tag} {
    upvar #0 Session:$id session
    if {![info exists session(init)]} {
	if {![iscommand ${tag}_Init]} {
	    set html "
		<h4>No ${tag}_Init proc</h4>
	    "
	} else {
	    set html [${tag}_Init Session:$id]
	}
    } else {
	set html "<-- Session $id -->"
    }
    return $html
}
proc Dummy_Init {name} {
    upvar #0 $name session
    return "<-- Dummy_Init was here -->"
}

# Create a new session as a safe slave interpreter.
# Populate it with the useful aliases.
#   Type:  An arbitrary session type, used for automatic alias creation.

proc Session_Create {type {isSafe 1}} {

    # Pick a unique session id, create the interpreter and global state.

    while {[info globals *[set id [SessionGenId]]*] != ""} {}
    Session_CreateWithID $type $id $isSafe
}

proc Session_CreateWithID {type id {isSafe 1}} {
    set interp [SessionCreate $id $isSafe]
    SessionTypeAliases $interp $id $type
}

proc SessionCreate {id {isSafe 1}} {
    upvar #0 Session:$id session
    if {$isSafe} then {
	set interp [interp create -safe interp$id]
    } else {
        set interp [interp create interp$id]
    }
    set session(start) [clock seconds]
    set session(current) $session(start)
    set session(count) 0
    set session(interp) $interp
    return $interp
}

proc SessionTypeAliases {interp id type} {
    upvar #0 Session:$id session
    set session(type) $type

    # Set up the  document specific aliases for this interp  This
    # looks for all procedures in the master interpreter that start
    # with "<type>_".  Since some of them might be auto-loaded, look
    # in the auto index array.  The names get stored in an array to
    # remove duplicates.

    global auto_index
    foreach name "[info commands ${type}_*] [array names auto_index ${type}_*]" {
    	set procs($name) {}
    }

    # Look at the *name* of the first argument to each alias-able proc.
    # Some names are treated specally.

    foreach proc [array names procs] {
	regexp -- ${type}_(.*) $proc {} alias
	catch {lindex [info args $proc] 0} arg0
	switch -- $arg0 {
	    session {interp alias $interp $alias {} $proc $id}
	    interp  {interp alias $interp $alias {} $proc $interp}
	    default {interp alias $interp $alias {} $proc}
	}
    }

    # Set up the common aliases for all session interpreters.

    interp alias $interp session {} Session_Session $id
    interp alias $interp sequence {} Session_Sequence $id
    interp alias $interp group {} Session_Value $id group
    interp alias $interp value {} Session_Variable $id

    return $id
}

# Destroy all sessions older than a certain age (in seconds)
#    age:  time (in seconds) since the most recent access
#    type: a regexp to mach session types with (defaults to all)

proc Session_Reap {age {type .*}} {
    foreach id [info globals Session:*] {
	upvar #0 $id session
	set old [expr {[clock seconds] - $age}]
	if {[regexp -- $type $session(type)] && $session(current) < $old} {
	    catch {interp delete $session(interp)}
	    Stderr "Reaping session $id"
	    unset session
	}
    }
}

# Destroy a single session

proc Session_Destroy {id} {
    upvar #0 Session:$id session
    if {[info exists session]} {
	interp delete $session(interp)
	unset session
	SessionDiscard $id
	return 1
    } else {
    	return 0
    }
}


# Find the correct session, and return the proper interp or error.
# This is identical to Session_Match, but uses cookies to store
# session id.
# If the session is "new", then create a new one.
# - query: optional alist containing the form and/or url query
# - type:  The type of this session
# - error_name:  The variable holding the error result (if any)

proc Session_Cookie {{querylist {}} {type {}} {error_name error} {isSafe 1}} {
    upvar $error_name error
    global Httpd
    set sock $Httpd(currentSocket)

    # fetch cookies pertaining to session
    set old 0
    foreach {key var} {session session session_sequence sequence} {
	set x [Cookie_GetSock $sock ${type}_$key]
	if {$x != ""} {
	    incr old
	    lappend querylist $var [lindex $x 0]
	}
    }

    # try to find an existing or saved session
    set error ""
    array set query $querylist
    set id [Session_Match [array get query] $type error $isSafe]

    # we must have lost the old session. lose the cookies and try again
    if {$error == "Session: Invalid session id."} {
	set query(session) new
	set error ""
	set id [Session_Match [array get query] $type error $isSafe]
	set old 0
    }

    # set the session cookies
    if {!$old} {
	global Session
	upvar #0 Session:$id session

	foreach {key var} {session id
	    session_sequence session(sequence)
	    session_type session(type)} {
	    if {[info exists $var]} {
		Httpd_SetCookie $sock [Cookie_Make -expires $Session(expires) -path / -name ${type}_$key -value [set $var]] 1
	    }
	}
    }

    # we accept an additional session_cmd argument to manipulate sessions
    if {[info exists query(session_cmd)]} {
	switch $query(session_cmd) {
	    save {
		Session_Save $id
	    }
	}
    }

    return $id
}

# Create and return the session directory for saved sessions
proc SessionDir {} {
    if {![info exists Session(dir)]} {
	# I'm not keen on this default location, as it could
	# be exposed to URL fetches
	set Session(dir) [file join [Doc_Root] .sessions]
    }
    file mkdir $Session(dir)
    return $Session(dir)
}

# Destroy the session cookie for this type
# note, this won't take immediate effect,
# you may have to reload the page to get the new cookies
proc Session_CookieDestroy {{type {}}} {
    global Httpd
    set sock $Httpd(currentSocket)
    
    foreach key {session session_sequence} {
	Httpd_RemoveCookies $sock ${type}_*
    }
}

# Save session state in a file under $Session(dir),
# for later reconstruction
proc Session_Save {id} {
    upvar #0 Session:$id session

    # create a session save file, write state
    set sfile [file join [SessionDir] ${id}.sess]
    set fd [open $sfile w]
    puts $fd $session(type)
    puts $fd [interp issafe interp$id]
    puts $fd [array get session]

    # add Self Vars
    set vars ""
    set arrays ""
    foreach sv [interp eval $session(interp) info vars] {
	switch -regexp -- $sv {
	    tcl_* -
	    env -
	    errorCode -
	    errorInfo -
	    arg[cv] -
	    auto_* {}
	    default {
		if {[interp eval $session(interp) array exists $sv]} {
		    append arrays "array set $sv [list [interp eval $session(interp) array get $sv]]" \n
		} else {
		    append vars "set $sv [list [interp eval $session(interp) set $sv]]" \n
		}
	    }
	}
    }
    puts $fd $vars
    puts $fd $arrays

    close $fd
}

# SessionDiscard - destroy persistent record of session $id
proc SessionDiscard {id} {
    set sfile [file join [SessionDir] ${id}.sess]
    if {[file exists $sfile]} {
	# delete the session save file
	file delete $sfile
    }
}

# SessionFetch - fetch persistent record of session $id
proc SessionFetch {id} {
    upvar #0 Session:$id session
    set sfile [file join [SessionDir] ${id}.sess]
    if {[file exists $sfile]} {
	# open a session save file, read state
	set fd [open $sfile r]
	set type [gets $fd]
	set isSafe [gets $fd]
	set sarray [gets $fd]
	set script [read $fd]
	close $fd
	
	# create the interpreter
	Session_CreateWithID $type $id $isSafe
	array set session $sarray	;# set session vars
	interp eval $session(interp) $script

	# consistency check
	if {$type != {} && $type != $session(type)} {
	    return "Session: Invalid session type."
	}

	return ""
    } else {
	# there's no stored session
	return "Session: Invalid session id."
    }
}

# Find the correct session, and return the proper interp or error.
# If the session is "new", then create a new one.
# - query:       The array containing the form and/or url query
#    session:	Either an ID or "new".  
#               an ID will return that ID to confirm that the session is valid
#                 or will return an empty string if session is invalid.
#               "new" will create a new session.
#    sequence:   Sequence position if this is a sequential set of pages.
# - type:        The type of this session
# - error_name:  The variable holding the error result (if any)
# - isSafe:      True to create a safe interp, false for normal.

proc Session_Match {querylist {type {}} {error_name error} {isSafe 1}} {
    upvar $error_name error

    # Check the session informatioin provided in the query data.

    if {[catch {
	array set query $querylist
    }]} {
	Stderr "Bogus querylist\n$querylist"
    }

    if {![info exists query(session)]} {
	set error "Session: no session id provided."
	return {}
    }

    set id $query(session)
    if {$id == "new"} {
	set id [Session_Create $type $isSafe]
    } elseif {[regexp "kill(.+)" $id x id]} {
	Session_Destroy $id
	set id [Session_Create $type $isSafe]
    } elseif {[regexp "save(.+)" $id x id]} {
	Session_Save $id
    }

    upvar #0 Session:$id session
    if {![array exists session]} {
	# see if there's a session to be instantiated
	set error [SessionFetch $id]
	if {$error != ""} {
	    return {}
	}
    } else {
	# session's already instantiated
    }

    # Check sequence number (if any).
    if {[info exists session(sequence)]} {
    	if {![info exists query(sequence)]} {
	    set error "Session: Sequence number required, not provided."
	    return $id
    	}
    	if {$query(sequence) != $session(sequence)} {
	    set error "Session: Sequence number invalid."
	    return $id
    	}
    	unset session(sequence)
    }

    # Update the session access time and count, and return the session id.

    set session(current) [clock seconds]
    incr session(count)
    return $id
}

# Import variables from a global array into the local scope.
#  valid:  The array containing the legal values to import.  If valid
#          is {}, then all names in "array" will be imported.
#  array:  The name of the global array  in "Interp" to import from.
#  Interp: The interpreter to import it from.

proc Session_Import {valid array {interp {}}} { 
    upvar $valid ok
    foreach {name value} [interp eval $interp [list array get $array]] {
    	if {$valid == {} || [info exists ok(-$name)]} {
	    upvar $name var
	    set var $value
	}
    }
}

###################################
# Common Aliases for interpreters

# Return the (constant) session id.  The id is a constant created at 
# alias time.

proc Session_Session {arg} {
    return $arg
}    

# set up a sequence number.  Id is the session id, passed in at alias time.

proc Session_Sequence {id} {
    upvar #0 Session:$id session
    set session(sequence)  $session(count)
}

# Set or return a session variable.  The slave alias may be set up to allow
# read access only.

proc Session_Variable {id var {value ""}} {
    upvar #0 Session:$id state
    if {$value != {}} {
    	set state($var) $value
    } 
    if {[info exists state($var)]} {
    	return $state($var)
    } else {
    	return ""
    }
}

# Get a group variable, specify a default if not set

proc Session_Value {id var {default {}}} {
    upvar #0 Session:$id session
    set group $session(group)
    if {[catch {interp eval $session(interp) set ${group}($var)} value]} {
	set value $default
    }
    return $value
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/srvui.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# srvui.tcl
# Trivial Tk control panel for the server.
#
# Brent Welch  (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: srvui.tcl,v 1.9 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::srvui 1.0

package require httpd	;# Httpd_Shutdown
package require httpd::counter	;# Count CountVarName
package require httpd::utils	;# file

proc SrvUI_Init {title} {
    global Httpd Doc
    option add *font 9x15
    
    wm title . $Httpd(name):$Httpd(port)
    wm protocol . WM_DELETE_WINDOW {Httpd_Shutdown; exit}
    wm iconname . $Httpd(name):$Httpd(port)
	set msgText "$title\n$Httpd(name):$Httpd(port)"
    if {[info exists Httpd(https_listen)]} {
    	append msgText "\n$Httpd(name):$Httpd(https_port) (Secure Server)"
    }
    append msgText "\n$Doc(root)"
    message .msg -text $msgText -aspect 1000
    grid .msg -columnspan 2 -sticky news

    foreach {url label} {
	    / "Home Page"
	    } {
	label .l$url -text $label
	label .n$url -textvariable counterhit($url) -width 0
	grid .l$url .n$url -sticky w
	grid configure .n$url -sticky e
    }
    foreach {counter label} {
	    urlhits "URL Requests"
	    urlreply "URL Replies"
	    cgihits "CGI Hits"
	    maphits "Image Map Hits"
	    errors	"Errors"
	    } {
	label .l$counter -text $label
	label .n$counter -textvariable [CountVarName $counter] -width 0
	grid .l$counter .n$counter -sticky w
	grid configure .n$counter -sticky e
    }
    # Expose webmaster and debug passwords
    foreach {varname label} {
        webmaster_password "webmaster Password"
        DebugPassword     "debug Password"
    } {
	label .l$varname -text $label
	label .n$varname -textvariable $varname -width 0
	grid .l$varname .n$varname -sticky w
	grid configure .n$varname -sticky e
    }
    button .quit -text Quit -command {Httpd_Shutdown ; exit}
    grid .quit -columnspan 2
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































Deleted lib/status.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# status.tcl --
#
#	Application-direct URLs to give out status of the server.
# 	Tcl procedures of the form Status/hello implement URLS
#	of the form /status/hello
#
# Brent Welch (c) Copyright 1997 Sun Microsystems, Inc.
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: status.tcl,v 1.29 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::status 1.0

package require httpd	;# Httpd_ReturnData Httpd_ReturnFile
package require httpd::counter	;# Count Counter_StartTime
package require httpd::direct	;# Direct_Url
package require httpd::log	;# Log
package require httpd::subst	;# Subst_ReturnFile
package require httpd::threadmgr	;# Thread_Enabled Thread_Id Thread_IsFree Thread_List Thread_Send Thread_SendAsync
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_Dispatch
package require httpd::utils	;# K file setmax

proc Status_Url {dir {imgdir /images}} {
    global _status
    set _status(dir) $dir
    set _status(images) $imgdir
    Direct_Url $dir Status
}

# Status/hello --
#
#	Show the string "hello".
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns the string "hello".

proc Status/hello {args} {return hello}

# StatusHeader --
#
#       Standard HTML header for status pages.
#
# Arguments:
#       title - also used as <h1>
#
# Results:
#       Html for head and <body>

proc StatusHeader {title} {
    return "<html><head>
    <title>$title</title>
    </head>
    <body bgcolor=white text=black>
    <h1>$title</h1>
"
}

# Status/threads --
#
#	Show the list of threads running in the server.
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns the list of threads running in the server.

proc Status/threads {args} {
    append html [StatusHeader "Thread List"]
    append html [StatusMenu]\n
    if {[catch {Thread_List} x]} {
	append html "No thread support\n"
    } else {
	append html $x
    }
    return $html
}

proc StatusSortForm {action label {pattern *} {sort number}} {
    if {[string compare $sort "number"] == 0} {
	set numcheck checked
	set namecheck ""
    } else {
	set numcheck ""
	set namecheck checked
    }
    append result "<form action=$action>"
    append result "Pattern <input type=text name=pattern value=$pattern><br>"
    append result "Sort by $label <input type=radio name=sort value=number $numcheck> or Name <input type=radio name=sort value=name $namecheck><br>"
    append result "<input type=submit name=submit value=\"Again\">"
    append result "</form>"
}

proc StatusMenu {} {
    global _status
    set sep ""
    set html "<p>\n"
    foreach {url label} [list \
	/		"Home" \
	$_status(dir)/	"Graphical Status" \
	$_status(dir)/text	"Text Status" \
	$_status(dir)/domain	"Domains" \
	$_status(dir)/doc	"Documents" \
	$_status(dir)/notfound	"Not Found" \
	$_status(dir)/threads	"Threads" \
	$_status(dir)/size	"Memory Size" \
    ] {
	append html "$sep<a href=$url>$label</a>\n"
	set sep " | "
    }
    append html "</p>\n"
    return $html
}

# Status/doc --
#
#	Show the number of hits for documents matching the pattern.
#
# Arguments:
#	pattern	(optional) the glob pattern of the URL to report on.
#	sort	(optional) how to sort the output.  If the default "number" is
#		not given, output is sorted by url alphabetically.
#
# Results:
#	Returns HTML code that displays document hit info.

proc Status/doc {{pattern *} {sort number}} {
    global _status
    set result ""
    append result [StatusHeader "Document Hits"]
    append result [StatusMenu]
    append result [StatusSortForm $_status(dir)/doc "Hit Count" $pattern $sort]
    append result [StatusPrintArray [counter::get hit -histVar] * $sort Hits Url]
}

# Status/domain --
#
#	Show the number of hits for documents in different domains.
#
# Arguments:
#	pattern	(optional) the glob pattern of the domain to report on.
#	sort	(optional) how to sort the output.  If the default "number" is
#		not given, output is sorted by url alphabetically.
#
# Results:
#	Returns HTML code that displays document hit info.

proc Status/domain {{pattern *} {sort number}} {
    global _status
    set result ""
    append result [StatusHeader "Domain Hits"]
    append result [StatusMenu]
    append result [StatusSortForm $_status(dir)/domain "Hit Count" $pattern $sort]
    append result [StatusPrintArray [counter::get domainHit -histVar] * $sort Hits Domain]
}

proc StatusPrintArray {aname pattern sort col1 col2} {
    upvar #0 $aname a
    set result ""
    append result <pre>\n
    append result [format "%6s %s\n" $col1 $col2]
    set list {}
    set total 0
    foreach name [lsort [array names a $pattern]] {
	set value $a($name)
	lappend list [list $value $name]
	incr total $value
    }
    if {[string compare $sort "number"] == 0} {
	if {[catch {lsort -index 0 -integer -decreasing $list} newlist]} {
	    set newlist [lsort -command StatusSort $list]
	}
    } else {
	if {[catch {lsort -index 1 -integer -decreasing $list} newlist]} {
	    set newlist [lsort -command StatusSortName $list]
	}
    }
    append result [format "%6d %s\n" $total Total]
    foreach k $newlist {
	set url [lindex $k 1]
	append result [format "%6d %s\n" [lindex $k 0] $url]
    }
    append result </pre>\n
    return $result
}
proc StatusSort {a b} {
    set 1 [lindex $a 0]
    set 2 [lindex $b 0]
    if {$1 == $2} {
	return [string compare $a $b]
    } elseif {$1 < $2} {
	return 1
    } else {
	return -1
    }
}
proc StatusSortName {a b} {
    set 1 [lindex $a 1]
    set 2 [lindex $b 1]
    return [string compare $1 $2]
}

# Status/notfound --
#
#	Show the number of hits for nonexistent documents matching the pattern.
#
# Arguments:
#	pattern	(optional) the glob pattern of the URL to report on.
#	sort	(optional) how to sort the output.  If the default "number" is
#		not given, output is sorted by url alphabetically.
#
# Results:
#	Returns HTML code that displays document hit info for docs that were
#	not found.

proc Status/notfound {{pattern *} {sort number}} {
    global Doc Referer _status
    set result ""
    append result [StatusHeader "Documents Not Found"]
    append result [StatusMenu]
    append result [StatusSortForm $_status(dir)/notfound "Hit Count" $pattern $sort]
    append result [StatusPrintNotFound $pattern $sort]
}

proc StatusPrintNotFound {{pattern *} {sort number}} {
    global Doc Referer _status
    upvar #0 [counter::get notfound -histVar] histogram
    append result <pre>\n
    append result [format "%6s %s\n" Miss Url]
    set list {}
    foreach i [lsort [array names histogram $pattern]] {
	lappend list [list $histogram($i) $i]
    }
    if {[catch {lsort -index 0 -integer -decreasing $list} newlist]} {
	set newlist [lsort -command StatusSort $list]
    }
    foreach k $newlist {
	set url [lindex $k 1]
	append result [format "%6d <a href=%s>%s</a>\n" \
	    [lindex $k 0] [lindex $k 1] [lindex $k 1]]
	if {[info exists Referer($url)]} {
	    set i 0
	    append result <ul>
	    foreach r $Referer($url) {
		append result "<li> <a href=\"$r\">$r</a>\n"
	    }
	    append result </ul>\n
	}
    }
    append result </pre>\n
#    append result "<a href=$_status(dir)/notfound/reset>Reset counters</a>"
    return $result
}

# Status/notfound/reset --
#
#	Reset the number of hits for nonexistent documents to 0.
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns HTML code that confirms that the reset occurred.

proc Status/notfound/reset {args} {
    global Referer
    counter::reset notfound
    catch {unset Referer}
    return [StatusHeader "Reset Notfound Counters"]
}

# Status/size --
#
#	Show both the code size and data size.
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns HTML.

proc Status/size {args} {
    global StatusDataSize StatusCodeSize
    append top_html [StatusHeader "Memory Size"]
    append top_html [StatusMenu]\n
    append html [Status/datasize]\n
    append html [Status/codesize]\n
    append top_html "<h2>Grand Total</h3>"
    append top_html "Bytes [expr $StatusDataSize(bytes) + $StatusCodeSize(bytes)]"
    return $top_html$html
}

# Status/datasize --
#
#	Show the data size for the entire server or for a particular namespace.
#
# Arguments:
#	ns	(optional) if given, show the data size for this namespace
#
# Results:
#	Returns HTML.

proc Status/datasize {{ns ::}} {
    global StatusDataSize
    array set StatusDataSize {
	vars	0
	values	0
	bytes	0
    }
    append html [StatusHeader "Data Size"]
    append html [StatusDataSize $ns]
    append top_html "<h2>Total Data Size</h2>\n
	Num Variables $StatusDataSize(vars)<br>\n\
	Num Values $StatusDataSize(values)<br>\n\
	Data Bytes $StatusDataSize(bytes)"
    return $top_html$html
}
proc StatusDataSize {ns} {
    global StatusDataSize
    set ng 0
    set nv 0
    set size 0
    foreach g [info vars ${ns}::*] {
	incr ng
	if {[array exists $g]} {
	    foreach {name value} [array get $g] {
		set size [expr {$size + [string length $name] + [string length $value]}]
		incr nv
	    }
	} elseif {[info exist $g]} {
	    # info vars returns declared but undefined namespace vars
	    set size [expr {$size + [string length $g] + [string length [set $g]]}]
	    incr nv
	}
    }
    set html "<h3>$ns</h3>\n\
		Num Variables $ng<br>\n\
		Num Values $nv<br>\n\
		Data Bytes $size"
    incr StatusDataSize(vars) $ng
    incr StatusDataSize(values) $nv
    incr StatusDataSize(bytes) $size

    append html "<ul>"
    foreach child [namespace children $ns] {
	append html [StatusDataSize $child]
    }
    append html "</ul>"
    return $html
}

# Status/codesize --
#
#	Show the code size for the entire server or for a particular namespace.
#
# Arguments:
#	ns	(optional) if given, show the code size for this namespace
#
# Results:
#	Returns HTML.

proc Status/codesize {{ns ::}} {
    global StatusCodeSize
    array set StatusCodeSize {
	procs	0
	bytes	0
    }
    set html [StatusHeader "Code Size"]
    append html [StatusCodeSize $ns]
    append top_html "<h2>Total Code Size</h2>\n
	Num Procs $StatusCodeSize(procs)<br>\n\
	Code Bytes $StatusCodeSize(bytes)"
    return $top_html$html
}
proc StatusCodeSize {{ns ::}} {
    global StatusCodeSize
    set np 0
    set size 0
    foreach g [info procs ${ns}::*] {
	incr np
	set size [expr {$size + [string length $g] +
			    [string length [info args $g]] +
			    [string length [info body $g]]}]
    }
    set html "<h3>$ns</h3>\n\
		Num Procs $np<br>\n\
		Code Bytes $size"
    incr StatusCodeSize(procs) $np
    incr StatusCodeSize(bytes) $size
    append html "<ul>"
    foreach child [namespace children $ns] {
	append html [StatusCodeSize $child]
    }
    append html "</ul>"
}

# StatusMainTable --
#
#	Display the main status counters. This gathers information
#	from worker threads, if possible.
#
# Arguments
#	None
#
# Results
#	Html

proc StatusMainTable {} {
    global Httpd Doc status tcl_patchLevel tcl_platform Thread
    global StatusThreadTable

    set html "<H1>$Httpd(name):$Httpd(port)</h1>\n"
    append html "<H2>Server Info</h2>"
    append html "<table border=0>"
    append html "<tr><td>Start Time</td><td>[clock format [Counter_StartTime]]</td></tr>\n"
    append html "<tr><td>Current Time</td><td>[clock format [clock seconds]]</td></tr>\n"
    append html "<tr><td>Server</td><td>$Httpd(server)</td></tr>\n"
    append html "<tr><td>Tcl Version</td><td>$tcl_patchLevel</td></tr>"
    switch $tcl_platform(platform) {
	unix {
	    append html "<tr><td colspan=2>[exec uname -a]</td></tr>"
	}
	macintosh -
	windows {
	    append html "<tr><td colspan=2>$tcl_platform(os) $tcl_platform(osVersion)</td></tr>"
	}
    }

    append html </table>

    append html "<br><br><br>\n"

    append html "<p>[StatusTable]<p>\n"

    # Per thread stats
    if {[Thread_Enabled]} {
        set self [Thread_Id]
	foreach id [lsort -integer [Thread_List]] {
	    if {$id == $self} {
		continue
	    }
	    append html "<h4>Thread $id</h4>\n"
	    global counter_thread_$id
	    if {[Thread_IsFree $id]} {
		set StatusThreadTable($id) \
		    [Thread_Send $id StatusTable]
	    } else {
		# Use cached version of the other threads counters,
		# but update our stats for next time.
		append html "<i>busy, using cached values</i>\n"
		Thread_SendAsync $id [list StatusThreadUpdate $id $self]
	    }
	    if {[info exist StatusThreadTable($id)]} {
		append html $StatusThreadTable($id)
	    }
	}
    }
    return $html
}

proc StatusThreadUpdate {self master} {
    Thread_SendAsync $master [list array set ::counter_thread_$self \
	[array get ::counter]]
}

proc StatusTable {} {
    append html "<table bgcolor=#eeeeee>\n"

    set hit 0
    foreach {c label} {
	    / "Home Page Hits"
	    } {
	set N [counter::get hit -hist $c]
	if {$N > 0} {
	    append html "<tr><td>$label</td><td>$N</td>\n"
	    set hit 1
	    append html </tr>\n
	}
    }
    foreach {c label} {
	    urlhits "URL Requests"
	    Url_Dispatch "URL Dispatch"
	    UrlToThread "Thread Dispatch"
	    UrlEval "Direct Dispatch"
	    UrlCacheHit "UrlCache eval"
	    urlreply "URL Replies"
	    accepts "Total Connections"
	    accept_https "HTTPS Connections"
	    keepalive "KeepAlive Requests"
	    http1.0 "OneShot Connections"
	    http1.1 "Http1.1 Connections"
	    threads "Worker Threads"
	    sockets "Open Sockets"
	    cgihits "CGI Hits"
	    tclhits "Tcl Safe-CGIO Hits"
	    maphits "Image Map Hits"
	    cancel	"Timeouts"
	    notfound	"Not Found"
	    errors	"Errors"
	    Status	"Status"
	    } {
	if {[counter::exists $c]} {
	    set t [counter::get $c -total]
	    if {$t > 0} {
		append html "<tr><td>$label</td><td>$t</td>\n"
		set hit 1
		set resetDate [counter::get $c -resetDate]
		if {[string length $resetDate]} {
		    append html "<td>[clock format $resetDate -format "%B %d, %Y"]</td>"
		}
		append html </tr>\n
	    }
	}
    }
    if {!$hit} {
	foreach c [counter::get "" -allTagNames] {
	    append html "<tr><td>$name</td><td>[counter::get $c -total]</td>\n"
	    set resetDate [counter::get $c -resetDate]
	    if {[string length $resetDate]} {
		append html "<td>[clock format $resetDate -format "%B %d, %Y"]</td>"
	    }
	    append html </tr>\n
	}
    }
    append html </table>\n

    return $html
}

proc StatusTclPower {{align left}} {
    global _status
    set html "<img src=$_status(images)/pwrdLogo150.gif align=$align width=97 height=150>\n"
}

# Status/all --
#
#	Show the page hist per minute, hour, and day using images.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status/all {args} {
    global _status page
    set html [StatusHeader "Tcl HTTPD Status"]
    append html [StatusMenu]
    append html [StatusTclPower left]
    append html [StatusMainTable]
    append html "<br><a href=/status/text>Text only view.</a>\n"

    append html "<p>\n<table border=0 cellpadding=0 cellspacing=0>\n"
    append html [counter::histHtmlDisplayRow serviceTime \
	    -title "Service Time" -unit seconds \
	    -width 1 -skip 10 -min 0 -max 400 \
	    -images $_status(images)]

    append html [counter::histHtmlDisplayRow urlhits \
	    -title "Url Hits" -unit minutes \
	    -min 0 -max 60 \
	    -images $_status(images)]
    append html [counter::histHtmlDisplayRow urlhits \
	    -title "Url Hits" -unit hours \
	    -min 0 -max 24 \
	    -images $_status(images)]
    append html [counter::histHtmlDisplayRow urlhits \
	    -title "Url Hits" -unit days \
	    -images $_status(images)]
    
    append html </table>
    return $html
}

# Status/text --
#
#	Show the page hist per minute, hour, and day in text format.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status/text {args} {
    global _status
    set html [StatusHeader "Tcl HTTPD Status"]
    append html [StatusMenu]
    append html [StatusTclPower left]
    append html [StatusMainTable]
    append html "<p><a href=$_status(dir)/all>Bar Chart View.</a>"
    catch {
	append html [counter::histHtmlDisplay serviceTime \
		-title "Service Time" -unit seconds -max 100 -text 1]
    }
    catch {
	append html [counter::histHtmlDisplay urlhits \
		-title "Per Minute Url Hits" -unit minutes -text 1]
	append html [counter::histHtmlDisplay urlhits \
		-title "Hourly Url Hits" -unit hours -text 1]
	append html [counter::histHtmlDisplay urlhits \
		-title "Daily Url Hits" -unit days -text 1]
    }
    return $html
}

# Status/ --
#
#	Same as Status/all.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status/ {args} {
    eval Status/all $args
}

# Status --
#
#	Same as Status/all.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status {args} {
    eval Status/all $args
}

proc Version {} {
    global tcl_patchLevel Httpd
    append html "$Httpd(server)"
    append html "<br>Tcl version $tcl_patchLevel"
    return $html
}

# NOTUSED

proc StatusTimeText {array title unit what time} {
    global counter
    upvar #0 $array data
    regsub ^Cnt $array Age agebitName
    upvar #0 $agebitName agebit
    set total 0
    set max 0
    set base 100
    foreach {name value} [array get data] {
	setmax max $value
    }
    switch $unit {
	Min	{set delta 60 ; set fmt %R}
	Hour	{set delta 3600 ; set fmt "%h %e %R"}
	Day	{set delta 86400 ; set fmt %D}
    }

    append result "<h3>$title ($max max)</h3>"
    append result <ul>
    append result "<h4>Starting at [clock format $time]</h4>"
    append result "<table cellpadding=2 cellspacing=2 border><tr>\n"
    append result "<tr><th>$unit</th><th>$what</th></tr>"
    foreach t [lsort -integer [array names data]] {
	set value $data($t)

	# Minutes time we infer from the starting time and the agebits,
	# which indicate minute buckets for the previous hour.

	if {[info exists agebit($t)]} {
	    set tt [expr $time - 3600]
	} else {
	    set tt $time
	}

	# Hours have their own base time in counter(hour,$hour)

	if {$unit == "Hour"} {
	    set tt $counter(hour,$t)
	}

	# Wrap separator

	if {[info exists lasttime] && ($lasttime > $tt)} {
	    append result "<tr><td><hr></td><td><hr></td></tr>"
	}
	set lasttime $tt
	append result "<tr><td>[clock format $tt -format $fmt]</td><td>$value</td></tr>"
	incr time $delta
    }
    append result "</table>"
    append result </ul>
    return $result
}

# Handle .stat templates. (NOTUSED)
# First process the incoming form data in an Status-specific way,
# then do a normal Subst into a safe interpreter
#   path:	The path name of the document
#   suffix:     The file suffix
#   sock:	The name of the socket, and a handle for the socket state

# It turns out this is not used, but you could use it as a template
# for your own application's template processor.

proc Doc_application/x-tcl-status {path suffix sock} {
    global status
    upvar #0 Httpd$sock data

    append data(query) ""
    set queryList [Url_DecodeQuery $data(query)]

    # Put the query data into an array.
    # If a key appears multiple times, the resultant array value will
    # be a list of all the values.

    foreach {name value} $queryList {
    	lappend query($name) $value
    }

    if {![info exists status(session)]} {
	set status(session) [session_create Status]
    }

    # Process the query data from the previous page.

    if {[catch {StatusProcess $session $queryList} result]} {
	Httpd_ReturnData $sock text/html $result
	return
    } 

    # Expand the page in the correct session interpreter, or treat
    # the page as ordinary html if the session has ended.

    if {$result} {
	Subst_ReturnFile $sock $path interp$session
    } else {
	Httpd_ReturnFile $sock text/html $path
    }
}

if {0} {
    proc StatusPrintHits {aname {pattern *} {sort number}} {
	append result [StatusPrintArray [counter::get hit -histVar] *\
		$sort Hits Url]
    }
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/stdin.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# stdin.tcl
#
# (c) 1997 Sun Microsystems Laboratories (Stephen Uhler)
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: stdin.tcl,v 1.5 2004/10/22 03:43:06 coldstore Exp $

# The following is an event-driven command loop for testing with tclsh
# with command history:
#	!<pattern> run 1st command matching pattern
#	!<pattern>/xxx/yyy/ as above, but substitute yyy for xxx
# Nb: history doesn't work, too many changes to the tcl api to track.

package provide httpd::stdin 1.1

package require httpd::log	;# Log Log_Flush
#package require httpd::utils	;# file

set Stdin(maxHistory) 100
append Stdin(history) {}
proc StdinRead {prompt} {
    global Stdin
    if {[eof stdin]} {
	set Stdin(Wait) 1
	fileevent stdin readable {}
	return
    }
    append Stdin(command) [gets stdin]
    if {[info complete $Stdin(command)]} {
	set s1 ""; set s2 ""
	if {[regexp {^!([^/]+)(/([^/]+)/([^/]*))?} $Stdin(command) \
		    {} history {} s1 s2]} {
	    set match [lsearch -regexp $Stdin(history) "^ *$history"]
	    if {$match >= 0} {
	    	set Stdin(command) [lindex $Stdin(history) $match]
		if {$s1 != ""} {
		    catch {regsub -- $s1 $Stdin(command) $s2 Stdin(command)}
		}
		puts stderr $Stdin(command)
	    } else {
	    	puts -nonewline "No \"$history\" in history list\n$prompt"
		set Stdin(command) ""
		flush stdout
		return
	    }
	}
	if {$Stdin(command) != "" && \
		$Stdin(command) != [lindex $Stdin(history) 0]} {
	    set Stdin(history) [lrange "[list $Stdin(command)] \
		    $Stdin(history)" 0 $Stdin(maxHistory)]
	}
        catch {uplevel #0  $Stdin(command)} result
        puts -nonewline "$result\n$prompt"
        flush stdout
        set Stdin(command) ""
    } else {
    	append Stdin(command) \n
    }
}

proc Stdin_Start {{prompt "% "}} {
    global Stdin
    set Stdin(command) ""
    puts -nonewline $prompt
    flush stdout
    fileevent stdin readable [list StdinRead $prompt]
    vwait Stdin(wait)
}

if {[info procs bgerror] == ""} {
    proc bgerror {args} {
	global errorInfo
	Log {} bgerror $errorInfo ; Log_Flush
	puts stderr $errorInfo
    }
}					
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































Deleted lib/subst.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# subst.tcl
#@c Subst support
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: subst.tcl,v 1.10 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::subst 1.0

package require httpd	;# Httpd_RequestAuth Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::session	;# Session_Authorized
#package require httpd::utils	;# file

# Subst_ReturnFile --
#
# Subst a file and return the result to the HTTP client.
# Note that ReturnData has no Modification-Date so the result is not cached.
#
# Arguments:
#	sock	The socket connection.
#	path	The template file pathname.
#	interp 	The Tcl intepreter in which to subst.
#
# Results:
#	None
#
# Side Effects:
#	Returns a page to the client.

proc Subst_ReturnFile {sock path {interp {}}} {
    Httpd_ReturnData $sock text/html [Subst_File $path $interp]
}

# SubstCleanScope --
#
# Substitute the data in this clean (no vars set) scope.
#
# Arguments:
#	_html_data	The data to substitute.
#
# Results:
#	The subst'ed data.
#
# Side Effects:
#	None

proc SubstCleanScope {_html_data} {
    return [subst $_html_data]
}

# Subst_Scope --
#
# When processing templates in the current interpreter, decide whether to
# use the global or local scope (that of DocSubst) to process templates.
#
# Arguments:
#	scope	0 means global and non-zero means local.
#
# Results:
#	None
#
# Side Effects:
#	Sets the scope for all Doc domain substs.

proc Subst_Scope {scope} {
    global Subst
    set Subst(templateScope) $scope
}
if {![info exists Subst(templateScope)]} {
    set Subst(templateScope) 0
}

# SubstFile --
#
# Subst a file in an interpreter context.  If no interp is given, use the
# current interp.  If using the current interp, use the scope
# variable to decide whether to use the global or current scope.
#
# Arguments:
#	path	The file pathname of the template.
#	interp  The interpreter in which to subst.
#
# Results:
#	The subst'ed page.
#
# Side Effects:
#	None

proc SubstFile {path {interp {}}} {
    global Subst

    set in [open $path]
    set script [read $in]
    close $in

    if {[string length $interp] == 0} {
        # Substitution occurs in the current interp.
        if {$Subst(templateScope) == 0} {
            # Substitution occurs at the global level.
            set result [uplevel #0 [list subst $script]]
        } else {
            # Substitution occurs at a clean level, one-off from global.
            set result [uplevel [list SubstCleanScope $script]]
        }
    } else {
        # Substitution occurs in the given interp.
        set result [interp eval $interp [list subst $script]]
    }

    # Perform the post-processing of the output, as installed via Subst_Install.
    foreach hook $Subst(substHooks) {
        set result [$hook $result]
    }
    return $result
}

# Subst_File --
#
# Subst a file or directory in an interpreter context.
# As SubstFile except that a path which is a directory is evaluated
# by evaluating a file $path/index.tml, and returning that as the substituted
# value of the $path directory.
#
proc Subst_File {path {interp {}}} {
    global Subst

    switch [file type $path] {
	file {
	    return [uplevel 1 [list SubstFile $path $interp]]
	}
	link {
	    set link [file readlink $path]
	    if {[file pathtype $link] == "relative"} {
		set link [file join [file dirname $path] $link]
	    }
	    return [uplevel 1 [list Subst_File $link $interp]]
	}
	directory {
	    return [uplevel 1 [list SubstFile [file join $path index.tml] $interp]]
	}
	default {
	    error "Can't process [file type $path] files."
	}
    }
}

# Subst_Install
#
#	Install a subst hook.  Each installed hook will be performed over the
#	substituted template.
#
# Arguments
#	proc	This is a command prefix that is invoked with one additional
#		arguments to process:
#			text	The text to process.
#		The subst hook returns the HTML that will be returned by the server.
#
# Results:
#	None
#
# Side Effects
#	Save the subst hook.

proc Subst_Install {proc} {
    global Subst
    if {[lsearch $Subst(substHooks) $proc] < 0} {
	lappend Subst(substHooks) $proc
    }
    return
}

if {![info exist Subst(substHooks)]} {
    set Subst(substHooks) {}
}

# Doc_application/x-tcl-auth --
#
# Like tcl-subst, but a basic authentication cookie is used for session state
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Returns a page to the client.

proc Doc_application/x-tcl-auth {path suffix sock} {
    upvar #0 Httpd$sock data

    if {![info exists data(session)]} {
	Httpd_RequestAuth $sock Basic "Random Password"
	return
    }
    set interp [Session_Authorized $data(session)]

    # Need to make everything look like a GET so the Cgi parser
    # doesn't read post data from stdin.  We've already read it.

    set data(proto) GET

    Doc_application/x-tcl-subst $path $suffix $sock
}

# Doc_application/x-tcl-subst --
#
# Tcl-subst a template that mixes HTML and Tcl.
# This subst is just done in the context of the specified
# interpreter with not much other support.
# See x-tcl-template for something more sophisticated
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#	interp	The interp to use for subst'ing.
#
# Results:
#	None
#
# Side Effects:
#	Sets the env array in interp and calls Subst_ReturnFile.

proc Doc_application/x-tcl-subst {path suffix sock {interp {}}} {
    upvar #0 Httpd$sock data

    Cgi_SetEnv	$sock $path pass
    interp eval $interp [list uplevel #0 [list array set env [array get pass]]]
    Subst_ReturnFile $sock $path $interp
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































































































































































































































































































Deleted lib/tclcrypt.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# tclcrypt.tcl
#
# Unix crypt in pure tcl
# From http://mini.net/tcl/crypt by Michael A. Cleverly (23/Nov/2000)
#
# Used as a fallback for installations without libcrypt.so compiled.
# It's always better to have the compiled C version available, of course
# This package provides two implementations of crypt, and will choose
# the fastest possible depending upon Tcl version

package provide tclcrypt 1.0

proc crypt {password salt} {

    array set IP {
	0 58  1 50  2 42  3 34  4 26  5 18  6 10  7 2
	8 60  9 52 10 44 11 36 12 28 13 20 14 12 15 4
	16 62 17 54 18 46 19 38 20 30 21 22 22 14 23 6
	24 64 25 56 26 48 27 40 28 32 29 24 30 16 31 8
	32 57 33 49 34 41 35 33 36 25 37 17 38  9 39 1
	40 59 41 51 42 43 43 35 44 27 45 19 46 11 47 3
	48 61 49 53 50 45 51 37 52 29 53 21 54 13 55 5
	56 63 57 55 58 47 59 39 60 31 61 23 62 15 63 7}
    
    array set FP {
	0 40  1 8  2 48  3 16  4 56  5 24  6 64  7 32
	8 39  9 7 10 47 11 15 12 55 13 23 14 63 15 31
	16 38 17 6 18 46 19 14 20 54 21 22 22 62 23 30
	24 37 25 5 26 45 27 13 28 53 29 21 30 61 31 29
	32 36 33 4 34 44 35 12 36 52 37 20 38 60 39 28
	40 35 41 3 42 43 43 11 44 51 45 19 46 59 47 27
	48 34 49 2 50 42 51 10 52 50 53 18 54 58 55 26
	56 33 57 1 58 41 59  9 60 49 61 17 62 57 63 25}
    
    array set PC1_C {
	0 57  1 49  2 41  3 33  4 25  5 17  6  9
	7  1  8 58  9 50 10 42 11 34 12 26 13 18
	14 10 15  2 16 59 17 51 18 43 19 35 20 27
	21 19 22 11 23  3 24 60 25 52 26 44 27 36}
    
    array set PC1_D {
	0 63  1 55  2 47  3 39  4 31  5 23  6 15
	7  7  8 62  9 54 10 46 11 38 12 30 13 22
	14 14 15  6 16 61 17 53 18 45 19 37 20 29
	21 21 22 13 23  5 24 28 25 20 26 12 27  4}
    array set shifts {
	0 1 1 1  2 2  3 2  4 2  5 2  6 2  7 2
	8 1 9 2 10 2 11 2 12 2 13 2 14 2 15 1}
    
    array set PC2_C {
	0 14  1 17  2 11  3 24  4  1  5  5
	6  3  7 28  8 15  9  6 10 21 11 10
	12 23 13 19 14 12 15  4 16 26 17  8
	18 16 19  7 20 27 21 20 22 13 23  2}
    
    array set PC2_D {
	0 41  1 52  2 31  3 37  4 47  5 55
	6 30  7 40  8 51  9 45 10 33 11 48
	12 44 13 49 14 39 15 56 16 34 17 53
	18 46 19 42 20 50 21 36 22 29 23 32}
    
    array set e {
	0 32  1  1  2  2  3  3  4  4  5  5
	6  4  7  5  8  6  9  7 10  8 11  9
	12  8 13  9 14 10 15 11 16 12 17 13
	18 12 19 13 20 14 21 15 22 16 23 17
	24 16 25 17 26 18 27 19 28 20 29 21
	30 20 31 21 32 22 33 23 34 24 35 25
	36 24 37 25 38 26 39 27 40 28 41 29
	42 28 43 29 44 30 45 31 46 32 47  1}
    
    array set S {
        0,0  14 0,1   4 0,2  13 0,3   1 0,4   2 0,5  15 0,6  11 0,7   8
        0,8   3 0,9  10 0,10  6 0,11 12 0,12  5 0,13  9 0,14  0 0,15  7
        0,16  0 0,17 15 0,18  7 0,19  4 0,20 14 0,21  2 0,22 13 0,23  1
        0,24 10 0,25  6 0,26 12 0,27 11 0,28  9 0,29  5 0,30  3 0,31  8
        0,32  4 0,33  1 0,34 14 0,35  8 0,36 13 0,37  6 0,38  2 0,39 11
        0,40 15 0,41 12 0,42  9 0,43  7 0,44  3 0,45 10 0,46  5 0,47  0
        0,48 15 0,49 12 0,50  8 0,51  2 0,52  4 0,53  9 0,54  1 0,55  7
        0,56  5 0,57 11 0,58  3 0,59 14 0,60 10 0,61  0 0,62  6 0,63 13
        1,0  15 1,1   1 1,2   8 1,3  14  1,4  6 1,5  11 1,6   3 1,7   4
        1,8   9 1,9   7 1,10  2 1,11 13 1,12 12 1,13  0 1,14  5 1,15 10
        1,16  3 1,17 13 1,18  4 1,19  7 1,20 15 1,21  2 1,22  8 1,23 14
        1,24 12 1,25  0 1,26  1 1,27 10 1,28  6 1,29  9 1,30 11 1,31  5
        1,32  0 1,33 14 1,34  7 1,35 11 1,36 10 1,37  4 1,38 13 1,39  1
        1,40  5 1,41  8 1,42 12 1,43  6 1,44  9 1,45  3 1,46  2 1,47 15
        1,48 13 1,49  8 1,50 10 1,51  1 1,52  3 1,53 15 1,54  4 1,55  2
        1,56 11 1,57  6 1,58  7 1,59 12 1,60  0 1,61  5 1,62 14 1,63  9
	
        2,0  10 2,1   0 2,2   9 2,3  14 2,4   6  2,5  3 2,6  15 2,7   5
        2,8   1 2,9  13 2,10 12 2,11  7 2,12 11 2,13  4 2,14  2 2,15  8
        2,16 13 2,17  7 2,18  0 2,19  9 2,20  3 2,21  4 2,22  6 2,23 10
        2,24  2 2,25  8 2,26  5 2,27 14 2,28 12 2,29 11 2,30 15 2,31  1
        2,32 13 2,33  6 2,34  4 2,35  9 2,36  8 2,37 15 2,38  3 2,39  0
        2,40 11 2,41  1 2,42  2 2,43 12 2,44  5 2,45 10 2,46 14 2,47  7
        2,48  1 2,49 10 2,50 13 2,51  0 2,52  6 2,53  9 2,54  8 2,55  7
        2,56  4 2,57 15 2,58 14 2,59  3 2,60 11 2,61  5 2,62  2 2,63 12
	
        3,0   7 3,1  13 3,2  14 3,3   3  3,4  0  3,5  6 3,6   9 3,7  10
        3,8   1 3,9   2 3,10  8 3,11  5 3,12 11 3,13 12 3,14  4 3,15 15
        3,16 13 3,17  8 3,18 11 3,19  5 3,20  6 3,21 15 3,22  0 3,23  3
        3,24  4 3,25  7 3,26  2 3,27 12 3,28  1 3,29 10 3,30 14 3,31  9
        3,32 10 3,33  6 3,34  9 3,35  0 3,36 12 3,37 11 3,38  7 3,39 13
        3,40 15 3,41  1 3,42  3 3,43 14 3,44  5 3,45  2 3,46  8 3,47  4
        3,48  3 3,49 15 3,50  0 3,51  6 3,52 10 3,53  1 3,54 13 3,55  8
        3,56  9 3,57  4 3,58  5 3,59 11 3,60 12 3,61  7 3,62  2 3,63 14
	
        4,0   2 4,1  12 4,2   4 4,3   1 4,4   7 4,5  10 4,6  11 4,7   6
        4,8   8 4,9   5 4,10  3 4,11 15 4,12 13 4,13  0 4,14 14 4,15  9
        4,16 14 4,17 11 4,18  2 4,19 12 4,20  4 4,21  7 4,22 13 4,23  1
        4,24  5 4,25  0 4,26 15 4,27 10 4,28  3 4,29  9 4,30  8 4,31  6
        4,32  4 4,33  2 4,34  1 4,35 11 4,36 10 4,37 13 4,38  7 4,39  8
        4,40 15 4,41  9 4,42 12 4,43  5 4,44  6 4,45  3 4,46  0 4,47 14
        4,48 11 4,49  8 4,50 12 4,51  7 4,52  1 4,53 14 4,54  2 4,55 13
        4,56  6 4,57 15 4,58  0 4,59  9 4,60 10 4,61  4 4,62  5 4,63  3
	
        5,0  12 5,1   1 5,2  10 5,3  15 5,4   9 5,5   2 5,6   6 5,7   8
        5,8   0 5,9  13 5,10  3 5,11  4 5,12 14 5,13  7 5,14  5 5,15 11
        5,16 10 5,17 15 5,18  4 5,19  2 5,20  7 5,21 12 5,22  9 5,23  5
        5,24  6 5,25  1 5,26 13 5,27 14 5,28  0 5,29 11 5,30  3 5,31  8
        5,32  9 5,33 14 5,34 15 5,35  5 5,36  2 5,37  8 5,38 12 5,39  3
        5,40  7 5,41  0 5,42  4 5,43 10 5,44  1 5,45 13 5,46 11 5,47  6
        5,48  4 5,49  3 5,50  2 5,51 12 5,52  9 5,53  5 5,54 15 5,55 10
        5,56 11 5,57 14 5,58  1 5,59  7 5,60  6 5,61  0 5,62  8 5,63 13
	
        6,0   4 6,1  11 6,2   2 6,3  14 6,4  15 6,5   0 6,6   8 6,7  13
        6,8   3 6,9  12 6,10  9 6,11  7 6,12  5 6,13 10 6,14  6 6,15  1
        6,16 13 6,17  0 6,18 11 6,19  7 6,20  4 6,21  9 6,22  1 6,23 10
        6,24 14 6,25  3 6,26  5 6,27 12 6,28  2 6,29 15 6,30  8 6,31  6
        6,32  1 6,33  4 6,34 11 6,35 13 6,36 12 6,37  3 6,38  7 6,39 14
        6,40 10 6,41 15 6,42  6 6,43  8 6,44  0 6,45  5 6,46  9 6,47  2
        6,48  6 6,49 11 6,50 13 6,51  8 6,52  1 6,53  4 6,54 10 6,55  7
        6,56  9 6,57  5 6,58  0 6,59 15 6,60 14 6,61  2 6,62  3 6,63 12
	
        7,0  13 7,1   2 7,2   8 7,3   4 7,4   6 7,5  15 7,6  11 7,7   1
        7,8  10 7,9   9 7,10  3 7,11 14 7,12  5 7,13  0 7,14 12 7,15  7
        7,16  1 7,17 15 7,18 13 7,19  8 7,20 10 7,21  3 7,22  7 7,23  4
        7,24 12 7,25  5 7,26  6 7,27 11 7,28  0 7,29 14 7,30  9 7,31  2
        7,32  7 7,33 11 7,34  4 7,35  1 7,36  9 7,37 12 7,38 14 7,39  2
        7,40  0 7,41  6 7,42 10 7,43 13 7,44 15 7,45  3 7,46  5 7,47  8
        7,48  2 7,49  1 7,50 14 7,51  7 7,52  4 7,53 10 7,54  8 7,55 13
        7,56 15 7,57 12 7,58  9 7,59  0 7,60  3 7,61  5 7,62  6 7,63 11}
    
    array set P {
	0 16  1  7  2 20  3 21
	4 29  5 12  6 28  7 17
	8  1  9 15 10 23 11 26
	12  5 13 18 14 31 15 10
	16  2 17  8 18 24 19 14
	20 32 21 27 22  3 23  9
	24 19 25 13 26 30 27  6
	28 22 29 11 30  4 31 25}
    
    for {set i 0} {$i < 66} {incr i} {
        set block($i) 0
    }
    
    set pw [split $password ""]
    set pw_pos 0
    for {set i 0} \
	{[scan [lindex $pw $pw_pos] %c c] != -1 && $i < 64} \
	{incr pw_pos} {
	    for {set j 0} {$j < 7} {incr j ; incr i} {
		set block($i) [expr {($c >> (6 - $j)) & 01}]
	    }
	    incr i
	}

    for {set i 0} {$i < 28} {incr i} {
        set C($i) $block([expr {$PC1_C($i) - 1}])
        set D($i) $block([expr {$PC1_D($i) - 1}])
    }

    for {set i 0} {$i < 16} {incr i} {
        for {set k 0} {$k < $shifts($i)} {incr k} {
            set t $C(0)
            for {set j 0} {$j < 27} {incr j} {
                set C($j) $C([expr {$j + 1}])
            }
            set C(27) $t
            set t $D(0)
            for {set j 0} {$j < 27} {incr j} {
                set D($j) $D([expr {$j + 1}])
            }
            set D(27) $t
        }
	
        for {set j 0} {$j < 24} {incr j} {
            set KS($i,$j) $C([expr {$PC2_C($j) - 1}])
            set KS($i,[expr {$j + 24}]) $D([expr {$PC2_D($j) - 28 - 1}])
        }
    }
    
    for {set i 0} {$i < 48} {incr i} {
        set E($i) $e($i)
    }
    
    for {set i 0} {$i < 66} {incr i} {
        set block($i) 0
    }
    
    set salt [split $salt ""]
    set salt_pos 0
    set val_Z 90
    set val_9 57
    set val_period 46
    for {set i 0} {$i < 2} {incr i} {
        scan [lindex $salt $salt_pos] %c c
        incr salt_pos
        set iobuf($i) $c
        if {$c > $val_Z} {
            incr c -6
        }
        if {$c > $val_9} {
            incr c -7
        }
        incr c -$val_period
        for {set j 0} {$j < 6} {incr j} {
            if {[expr {($c >> $j) & 01}]} {
                set temp $E([expr {6 * $i + $j}])
                set E([expr {6 * $i + $j}]) $E([expr {6 * $i + $j + 24}])
                set E([expr {6 * $i + $j + 24}]) $temp
            }
        }
    }
    
    set edflag 0
    for {set h 0} {$h < 25} {incr h} {
        for {set j 0} {$j < 64} {incr j} {
            set L($j) $block([expr {$IP($j) - 1}])
        }
	
        for {set ii 0} {$ii < 16} {incr ii} {
            if {$edflag} {
                set i [expr {15 - $ii}]
            } else {
                set i $ii
            }
	    
            for {set j 0} {$j < 32} {incr j} {
                set tempL($j) $L([expr {$j + 32}])
            }
	    
            for {set j 0} {$j < 48} {incr j} {
                set preS($j) [expr {$L([expr {$E($j) - 1 + 32}]) ^ $KS($i,$j)}]
            }

            for {set j 0} {$j < 8} {incr j} {
	set t [expr {6 * $j}]
	set k $S($j, [expr {
			    ($preS($t) << 5) + 
			    ($preS([expr {$t + 1}]) << 3) + 
			    ($preS([expr {$t + 2}]) << 2) + 
			    ($preS([expr {$t + 3}]) << 1) + 
			    $preS([expr {$t + 4}])       + 
			    ($preS([expr {$t + 5}]) << 4)
			}])

                set t [expr {4 * $j}]
                set f($t) [expr {($k >> 3) & 01}]
                set f([expr {$t + 1}]) [expr {($k >> 2) & 01}]
                set f([expr {$t + 2}]) [expr {($k >> 1) & 01}]
                set f([expr {$t + 3}]) [expr { $k       & 01}]
            }

            for {set j 0} {$j < 32} {incr j} {
                set L([expr {$j + 32}]) [expr {$L($j) ^ $f([expr {$P($j) - 1}])}]
            }

            for {set j 0} {$j < 32} {incr j} {
                set L($j) $tempL($j)
            }
        }

        for {set j 0} {$j < 32} {incr j} {
            set t $L($j)
            set L($j) $L([expr {$j + 32}])
            set L([expr {$j + 32}]) $t
        }

        for {set j 0} {$j < 64} {incr j} {
            set block($j) $L([expr {$FP($j) - 1}])
        }
    }

    for {set i 0} {$i < 11} {incr i} {
        set c 0
        for {set j 0} {$j < 6} {incr j} {
            set c [expr {$c << 1}]
            set c [expr {$c | $block([expr {6 * $i + $j}])}]
        }
        incr c $val_period
        if {$c > $val_9} {
            incr c 7
        }
        if {$c > $val_Z} {
            incr c 6
        }
        set iobuf([expr {$i + 2}]) $c
    }
    
    if {$iobuf(1) == 0} {
        set iobuf(1) $iobuf(0)
    }
    
    set elements [lsort -integer [array names iobuf]]
    set encrypted ""
    
    foreach element $elements {
        append encrypted [format %c $iobuf($element)]
    }
    
    return $encrypted
}

if {[package present Tcl] < 8.4} {
    # we must use the slower non lset version
    return
}

#This version uses the [lset] command introduced in Tcl 8.4.
#It seems to result in a 40-45% improvement in speed over the original version which uses [array]s.

proc crypt {password salt} {
    set IP {58 50 42 34 26 18 10  2 60 52 44 36 28 20 12  4 62 54 46 38 30
	22 14  6 64 56 48 40 32 24 16  8 57 49 41 33 25 17  9  1 59 51
	43 35 27 19 11  3 61 53 45 37 29 21 13  5 63 55 47 39 31 23 15 7}

    set FP {40  8 48 16 56 24 64 32 39  7 47 15 55 23 63 31 38  6 46 14 54
	22 62 30 37  5 45 13 53 21 61 29 36  4 44 12 52 20 60 28 35  3
	43 11 51 19 59 27 34  2 42 10 50 18 58 26 33  1 41  9 49 17 57 25}
    
    set PC1_C {57 49 41 33 25 17  9  1 58 50 42 34 26 18 10  2 59 51 43 35 27
	19 11  3 60 52 44 36}
    
    set PC1_D {63 55 47 39 31 23 15  7 62 54 46 38 30 22 14  6 61 53 45 37 29
	21 13  5 28 20 12  4}
    
    set shifts {1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1}
    
    set PC2_C {14 17 11 24 1 5 3 28 15 6 21 10 23 19 12 4 26 8 16 7 27 20 13 2}
    
    set PC2_D {41 52 31 37 47 55 30 40 51 45 33 48 44 49 39 56 34 53 46 42 50
	36 29 32}
    
    set e {32  1  2  3  4  5  4  5  6  7  8  9  8  9 10 11 12 13 12 13 14 15
	16 17 16 17 18 19 20 21 20 21 22 23 24 25 24 25 26 27 28 29 28 29
	30 31 32 1}
    
    set S {{14  4 13  1  2 15 11  8  3 10  6 12  5  9  0  7  0 15  7  4 14  2
	13  1 10  6 12 11  9  5  3  8  4  1 14  8 13  6  2 11 15 12  9  7
	3 10  5  0 15 12  8  2  4  9  1  7  5 11  3 14 10  0  6 13}
	
	{15  1  8 14  6 11  3  4  9  7  2 13 12  0  5 10  3 13  4  7 15  2
	    8 14 12  0  1 10  6  9 11  5  0 14  7 11 10  4 13  1  5  8 12  6
	    9  3  2 15 13  8 10  1  3 15  4  2 11  6  7 12  0  5 14 9}
	
	{10  0  9 14  6  3 15  5  1 13 12  7 11  4  2  8 13  7  0  9  3  4
	    6 10  2  8  5 14 12 11 15  1 13  6  4  9  8 15  3  0 11  1  2 12
	    5 10 14  7  1 10 13  0  6  9  8  7  4 15 14  3 11  5  2 12}
	
	{ 7 13 14  3  0  6  9 10  1  2  8  5 11 12  4 15 13  8 11  5  6 15
	    0  3  4  7  2 12  1 10 14  9 10  6  9  0 12 11  7 13 15  1  3 14
	    5  2  8  4  3 15  0  6 10  1 13  8  9  4  5 11 12  7  2 14}
	
	{ 2 12  4  1  7 10 11  6  8  5  3 15 13  0 14  9 14 11  2 12  4  7
	    13  1  5  0 15 10  3  9  8  6  4  2  1 11 10 13  7  8 15  9 12  5
	    6  3  0 14 11  8 12  7  1 14  2 13  6 15  0  9 10  4  5  3}
	
	{12  1 10 15  9  2  6  8  0 13  3  4 14  7  5 11 10 15  4  2  7 12
	    9  5  6  1 13 14  0 11  3  8  9 14 15  5  2  8 12  3  7  0  4 10
	    1 13 11  6  4  3  2 12  9  5 15 10 11 14  1  7  6  0  8 13}
	
	{ 4 11  2 14 15  0  8 13  3 12  9  7  5 10  6  1 13  0 11  7  4  9
	    1 10 14  3  5 12  2 15  8  6  1  4 11 13 12  3  7 14 10 15  6  8
	    0  5  9  2  6 11 13  8  1  4 10  7  9  5  0 15 14  2  3 12}
	
	{13  2  8  4  6 15 11  1 10  9  3 14  5  0 12  7  1 15 13  8 10  3
	    7  4 12  5  6 11  0 14  9  2  7 11  4  1  9 12 14  2  0  6 10 13
	    15  3  5  8  2  1 14  7  4 10  8 13 15 12  9  0  3  5  6 11}}
    
    set P {16  7 20 21 29 12 28 17  1 15 23 26  5 18 31 10  2  8 24 14 32 27
	3  9 19 13 30  6 22 11  4 25}
    
    set block {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	0 0 0 0 0 0}
    
    set KS {{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}}
    
    set iobuf {0 0 0 0 0 0 0 0 0 0 0 0 0}
    set f {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
    
    set pw [split $password ""]
    set pw_pos 0
    for {set i 0} {[scan [lindex $pw $pw_pos] %c c] != -1 && $i < 64} \
	{incr pw_pos} {
	    
	    for {set j 0} {$j < 7} {incr j ; incr i} {
		lset block $i [expr {($c >> (6 - $j)) & 01}]
	    }
	    incr i
	    
	}
    
    set C [list]
    set D [list]
    for {set i 0} {$i < 28} {incr i} {
	lappend C [lindex $block [expr {[lindex $PC1_C $i] - 1}]]
	lappend D [lindex $block [expr {[lindex $PC1_D $i] - 1}]]
    }
    
    for {set i 0} {$i < 16} {incr i} {
	for {set k 0} {$k < [lindex $shifts $i]} {incr k} {
	    set t [lindex $C 0]
	    for {set j 0} {$j < 27} {incr j} {
		lset C $j [lindex $C [expr {$j + 1}]]
	    }

	    lset C 27 $t
	    set t [lindex $D 0]
	    for {set j 0} {$j < 27} {incr j} {
		lset D $j [lindex $D [expr {$j + 1}]]
	    }
	    lset D 27 $t
	}
	
	for {set j 0} {$j < 24} {incr j} {
	    lset KS $i $j [lindex $C [expr {[lindex $PC2_C $j] - 1}]]
	    lset KS $i [expr {$j + 24}] \
		[lindex $D [expr {[lindex $PC2_D $j] - 28 - 1}]]
	}
    }
    
    set E [list]
    for {set i 0} {$i < 48} {incr i} {
	lappend E [lindex $e $i]
    }
    
    for {set i 0} {$i < 66} {incr i} {
	lset block $i 0
    }
    
    set salt [split $salt ""]
    set salt_pos 0
    set val_Z 90
    set val_9 57
    set val_period 46
    
    for {set i 0} {$i < 2} {incr i} {
	scan [lindex $salt $salt_pos] %c c
	incr salt_pos
	lset iobuf $i $c
	
	if {$c > $val_Z} {
	    incr c -6
	}
	if {$c > $val_9} {
	    incr c -7
	}
	incr c -$val_period
	for {set j 0} {$j < 6} {incr j} {
	    if {[expr {($c >> $j) & 01}]} {
		set temp [lindex $E [expr {6 * $i + $j}]]
		lset E [expr {6 * $i + $j}] \
		    [lindex $E [expr {6 * $i + $j + 24}]]
		lset E [expr {6 * $i + $j + 24}] $temp
	    }
	}
    }
    
    set edflag 0
    for {set h 0} {$h < 25} {incr h} {
	set L [list]
	for {set j 0} {$j < 64} {incr j} {
	    lappend L [lindex $block [expr {[lindex $IP $j] - 1}]]
	}
	
	for {set ii 0} {$ii < 16} {incr ii} {
	    if {$edflag} {
		set i [expr {15 - $ii}]
	    } else {
		set i $ii
	    }
	    
	    set tempL [list]
	    for {set j 0} {$j < 32} {incr j} {
		lappend tempL [lindex $L [expr {$j + 32}]]
	    }
	    
	    set preS [list]
	    for {set j 0} {$j < 48} {incr j} {
		lappend preS \
		    [expr {[lindex $L [expr {[lindex $E $j] - 1 + 32}]] ^ [lindex $KS $i $j]}]
	    }

	    for {set j 0} {$j < 8} {incr j} {
		set t [expr {6 * $j}]
		set k [lindex $S $j [expr {
				([lindex $preS $t] << 5) +
				([lindex $preS [expr {$t + 1}]] << 3) +
				([lindex $preS [expr {$t + 2}]] << 2) +
				([lindex $preS [expr {$t + 3}]] << 1) +
				[lindex $preS [expr {$t + 4}]] +
				([lindex $preS [expr {$t + 5}]] << 4)
			    }]]

		set t [expr {4 * $j}]
		lset f $t              [expr {($k >> 3) & 01}]
		lset f [expr {$t + 1}] [expr {($k >> 2) & 01}]
		lset f [expr {$t + 2}] [expr {($k >> 1) & 01}]
		lset f [expr {$t + 3}] [expr { $k       & 01}]
	    }
	    
	    for {set j 0} {$j < 32} {incr j} {
		lset L [expr {$j + 32}] \
		    [expr {[lindex $L $j] ^ [lindex $f [expr {[lindex $P $j] - 1}]]}]
	    }
	    
	    for {set j 0} {$j < 32} {incr j} {
		lset L $j [lindex $tempL $j]
	    }
	}
	
	for {set j 0} {$j < 32} {incr j} {
	    set t [lindex $L $j]
	    lset L $j [lindex $L [expr {$j + 32}]]
	    lset L [expr {$j + 32}] $t
	}
	
	for {set j 0} {$j < 64} {incr j} {
	    lset block $j [lindex $L [expr {[lindex $FP $j] - 1}]]
	}
    }
    
    for {set i 0} {$i < 11} {incr i} {
	set c 0
	for {set j 0} {$j < 6} {incr j} {
	    set c [expr {$c << 1}]
	    set c [expr {$c | [lindex $block [expr {6 * $i + $j}]]}]
	}
	incr c $val_period
	if {$c > $val_9} {
	    incr c 7
	}
	if {$c > $val_Z} {
	    incr c 6
	}
	lset iobuf [expr {$i + 2}] $c
    }
    
    if {[lindex $iobuf 1] == 0} {
	lset iobuf 1 [lindex $iobuf 0]
    }
    
    set encrypted ""
    foreach element $iobuf {
	append encrypted [format %c $element]
    }
    
    return $encrypted
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/template.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
# template.tcl
#@c Template support
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: template.tcl,v 1.20 2004/10/22 08:32:56 coldstore Exp $

package provide httpd::template 1.0

package require httpd	;# Httpd_PostDataSize Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv Cgi_SetEnvInterp
package require httpd::cookie	;# Cookie_Save
package require httpd::doc	;# Doc_GetPath
package require httpd::log	;# Log
package require httpd::mtype	;# Mtype
package require httpd::subst	;# Subst_File
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_ReadPost
package require httpd::utils	;# file file_latest lappendOnce

# Set the file extension for templates

if {![info exists Template(tmlExt)]} {
    set Template(tmlExt) .tml
}
if {![info exists Template(env)]} {
    set Template(env) 1
}

if {![info exists Template(htmlExt)]} {
    switch $tcl_platform(platform) {
	windows {
	    set Template(htmlExt) .htm
	}
	default {
	    set Template(htmlExt) .html
	}
    }
}

set Template(htmlMatch) {([.]html?)}

# Template_Check --
#
# Allow or disable automatic template checking
#
# Arguments:
#	how 	A boolen that enables or disables template handling.
#
# Results:
#	None
#
# Side Effects:
#	Sets the checkTemplates variable.

proc Template_Check {{how 1}} {
    global Template
    set Template(checkTemplates) $how
}
if {![info exists Template(checkTemplates)]} {
    set Template(checkTemplates) 0
}

# Template_Interp --
#
# Choose an alternate interpreter in which to process templates
#
# Arguments:
#	interp	The Tcl interpreter in which to process templates.
#
# Results:
#	None
#
# Side Effects:
#	Sets the interpreter for all Doc domain templates.

proc Template_Interp {interp} {
    global Template
    if {[string length $interp] && ![interp exists $interp]} {
	interp create $interp
    }
    set Template(templateInterp) $interp
}
if {![info exists Template(templateInterp)]} {
    set Template(templateInterp) {}
}

# Template_Library --
#
# Define the auto_load library for template support
#
# Arguments:
#	dir	The directory to add to the auto_path
#
# Results:
#	None
#
# Side Effects:
#	Updates the auto_path variable in the interpreter used
#	for templates.

proc Template_Library {dir} {
    global Template auto_path
    set Template(templateLibrary) $dir
    if {$Template(templateInterp) != {}} {
	interp eval $Template(templateInterp) [list lappendOnce ::auto_path $dir]
    } else {
	lappendOnce auto_path $dir
    }
}

# Doc_application/x-tcl-template --
#
# Tcl-subst a template that mixes HTML and Tcl.
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Sets up the interpreter context and subst's the page,
#	which is returned to the client.

proc Doc_application/x-tcl-template {path suffix sock} {
    upvar #0 Httpd$sock data
    global Template

    # This is always dynamic (ReturnData has no modification date)
    # so the result is not cached at the remote end, nor is a local
    # .html file cached.

    set content [TemplateInstantiate $sock $path {} $suffix {} $Template(templateInterp)]
    # If the content type was set, use it.  Otherwise, use the default.
    if {[info exists data(contentType)]} {
	set ctype $data(contentType)
    } else {
	set ctype text/html
    }
    return [Httpd_ReturnData $sock $ctype $content]
}

# TemplateInstantiate --
#
# Generate a .html file from a template
# and from any .tml files in directories leading up to the root.
# The processing is done in the specified interpreter.
# State set in the global array "page":
#	url		The URL past the document root
#	template	The filename of the template file
#	filename	The filename of the associated htmlfile
#	root		The ../ path up to the root
#	dynamic		If 1, then this page is dynamically generated
#			on every fetch.  Otherwise the page has a cached
#			static representation.
#
# Arguments:
#	sock		The client socket.
#	template	The file name of the template.
#	htmlfile	The file name of the corresponding .html file.
#	suffix		The URL suffix.
#	dynamicVar	Name of var to set to dynamic property of the page.
#	interp		The interp to use for substing.
#
# Results:
#	html, or an error generated by the template
#
# Side Effects:
#	Generates a page.  Will set up the CGI environment via the ncgi
#	module, and will do environment variable settings.
#	data(contentType) contains the mime type of generated content.

proc TemplateInstantiate {sock template htmlfile suffix dynamicVar {interp {}}} {
    upvar #0 Httpd$sock data
    upvar $dynamicVar dynamic
    global Template

    # Compute a relative path back to the root.

    set dirs [lreplace [split [string trimleft $data(url) /] /] end end]
    set root ""
    foreach d $dirs {
	append root ../
    }

    # Populate the global "page" array with state about this page
    if {[string length $htmlfile]} {
	set filename $htmlfile
	set dynamic 0
    } else {
	set filename $template
	set dynamic 1
    }
    interp eval $interp {uplevel #0 {catch {unset page}}}

    interp eval $interp [list uplevel #0 [list array set page [list \
	url		$data(url)	\
	template 	$template	\
	includeStack 	[list [file dirname $template]]	\
	filename	$filename	\
	root		$root		\
	dynamic		$dynamic	\
    ]]]

    # Populate the global "env" array similarly to the CGI environment
    if {$Template(env)} {
	Cgi_SetEnvInterp $sock $filename $interp
    }

    # Check query data.

    if {[Httpd_PostDataSize $sock] > 0 && ![info exists data(query)]} {
	set data(query) {}
    }
    if {[info exist data(query)]} {
	if {![info exist data(mime,content-type)] || $data(proto) == "GET"} {
	    
	    # The check against GET is because IE 5 has the following bug.
	    # If it does a POST with content-type multipart/form-data and
	    # keep-alive reuses the connection for a subsequent GET request,
	    # then the GET request erroneously has a content-type header
	    # that is a copy of the one from the previous POST!

	    set type application/x-www-urlencoded
	} else {
	    set type $data(mime,content-type)
	}

	# Read and append the pending post data to data(query).

	Url_ReadPost $sock data(query)

	# Initialize the Standard Tcl Library ncgi package so its
	# ncgi::value can be used to get the data.  This replaces
	# the old Url_DecodeQuery interface.

	interp eval $interp [list ncgi::reset $data(query) $type]
	interp eval $interp [list ncgi::parse]
	interp eval $interp [list ncgi::urlStub $data(url)]

	# Define page(query) and page(querytype)
	# for compatibility with older versions of TclHttpd
	# This is a bit hideous because it reaches inside ::ncgi
	# to avoid parsing the data twice.

	interp eval $interp [list uplevel #0 [list set page(querytype) \
		[string trim [lindex [split $type \;] 0]]]]
	interp eval $interp [list uplevel #0 {
	    set page(query) {}
	    foreach n $ncgi::varlist {
		foreach v $ncgi::value($n) {
		    lappend page(query) $n $v
		}
	    }
	}]

    } else {
	interp eval $interp [list ncgi::reset ""]
	interp eval $interp [list uplevel #0 [list set page(query) {}]]
	interp eval $interp [list uplevel #0 [list set page(querytype) {}]]
    }

    # Source the .tml files from the root downward.

    foreach libdir [Doc_GetPath $sock $template] {
	set libfile [file join $libdir $Template(tmlExt)]
	if {[file exists $libfile]} {
	    interp eval $interp [list uplevel #0 [list source $libfile]]
	}
    }

    # Process the template itself

    set code [catch {Subst_File $template $interp} html]

    if {$code != 0} {
	# pass errors up - specifically Redirect return code

	# stash error information so Cookie_Save doesn't interfere
	global errorCode errorInfo
	set ec $errorCode
	set ei $errorInfo

	# Save return cookies, if any
	Cookie_Save $sock $interp

	return -code $code -errorcode $ec -errorinfo $ei
    }

    # Save return cookies, if any
    Cookie_Save $sock $interp

    set dynamic [interp eval $interp {uplevel #0 {set page(dynamic)}}]
    if {!$dynamic} {

	# Cache the result

	catch {file delete -force $htmlfile}

	# process any filters
	if {[info exists data(filter)]} {
	    while {[llength $data(filter)]} {
		set cmd [lindex $data(filter) end]
		set data(filter) [lrange $data(filter) 0 end-1]
		catch {
		    set html [eval $cmd $sock [list $html]]
		}
	    }
	}

	if {[catch {open  $htmlfile w} out]} {
	    set dynamic 1
	    Log $sock "Template" "no write permission"
	} else {
	    puts -nonewline $out $html
	    close $out
	}
    }
    return $html
}

# Template_Dynamic
#	Supress generation of HTML cache
#
# Arguments:
#
# Results:
#	None
#
# Side Effects:
#	Sets the dynamic bit so the page is not cached.

proc Template_Dynamic {} {
    global page
    set page(dynamic) 1
    return "<!-- DynamicOnly -->\n"
}

# TemplateCheck --
#
# Check modify times on all templates that affect a page
#
# Arguments:
#	sock		The client connection
#	template	The file pathname of the template.
#	htmlfile	The file pathname of the cached .html file.
#
# Results:
#	1 if the template or any dependent .tml file are newer than
#	the cached .html file.
#
# Side Effects:
#	None

proc TemplateCheck {sock template htmlfile} {
    global Template

    if {[file exists $htmlfile]} {
	set mtime [file mtime $htmlfile]
    } else {
	return 1
    }

    # Look for .tml library files down the hierarchy.
    global Doc
    set rlen [llength [file split $Doc(root)]]
    set dirs [lrange [file split [file dirname $template]] $rlen end]
	
    foreach libdir [Doc_GetPath $sock $template] {
	set libfile [file join $libdir $Template(tmlExt)]
	if {[file exists $libfile] && ([file mtime $libfile] > $mtime)} {
	    return 1
	}
    }

    # make index.html regeneration depend upon the whole directory's
    # modification time, not just the modification time of index.tml
    global dirlist
    if {[file root [file tail $htmlfile]] == [file root $dirlist(indexpat)]} {
	if {[file mtime [file dirname $htmlfile]] > $mtime} {
	    return 1
	}
    }

    return [expr {[file mtime $template] > $mtime}]
}


# Template_try --
# process a template file which is newer than the path (if path exists).
#
# Arguments:
#	sock	The client connection
#	path	The file system pathname of the file.
#	suffix	The URL suffix.
#
# Results:
#	1 if the request has been completed (by a dynamic template)
#	0 if the request hasn't been handled, either because there is
#	  no template, or because cache file is (now) newer and can be
#	  handled by caller
#
# Side Effects:
#	May have generated a page - 
#	data(contentType) contains the mime type of generated content.

proc Template_Try {sock path suffix} {
    upvar #0 Httpd$sock data
    global Template

    if {!$Template(checkTemplates)} {
	return 0
    }

    set template ${path}$Template(tmlExt)

    if {![file exists $template]} {
	# special case, x.tml generates x.html
	set template [file root $path]$Template(tmlExt)
	
	# ensure request was for *.htm[l]? and .tml exists
	if {![regexp $Template(htmlMatch) [file extension $path]]
	    || ![file exists $template]} {
	    # no template found
	    return 0
	}
    }

    # we have a matching template and extension for path
    # See if the cached result is up-to-date
    if {[TemplateCheck $sock $template $path]} {
	# Template file is newer than its cached version
	# Do the subst and cache the result in the .html file
        # We set a provisional type based on the file extension, but
        # the template processing can override that
        set data(contentType) [Mtype $path]
	set html [TemplateInstantiate $sock $template $path $suffix dynamic \
		      $Template(templateInterp)]

	if {$dynamic} {
	    # return the data directly
	    Httpd_ReturnData $sock $data(contentType) $html
	    return 1
	} else {
	    # we have generated a cached file from the template.
	    # leave it to caller to return newly generated file
	    return 0
	}
    } else {
	# cache file is newer
	return 0
    }
}

# Template_Choose - what mime-type does this file
# represent, or generate?
# a.x.tml is considered to return/match .x
proc Template_Choose {accept choices} {
    global Template

    # generate a map map from mime_type -> choices
    foreach f $choices {
	# get first of two extensions eg .css.tml
	set type [file extension [file root $f]]	;# use .css in .css.tml
	if {$type == ""} {
	    set type [file extension $f]	;# path has only a single extension
	    if {$type == $Template(tmlExt)} {
		# we've found a .tml file - x.tml matches x.html
		set type $Template(htmlExt)
	    }
	}
	lappend mtype([Mtype $type]) $f
    }

    # array mtype is now a mapping from mime types to files
    # for the collection of files we can offer.

    # look at what mime types the client accepts, in order of presentation
    # (nb FIXME: the spec says we should accept them in q= order)
    foreach t [split $accept ,] {
	# find something that matches 
	regsub {;.*} $t {} t	;# Nuke quality parameters
	set t [string trim [string tolower $t]]

	# collect string-matching mtypes we can offer
	set hits {}
	foreach {mime files} [array get mtype $t] {
            set hits [concat $hits $files]
	}

	# if some file choices match on type, choose the most recent
	if {[llength $hits] > 1} {
	    set hit [file_latest $hits]
	} else {
	    set hit [lindex $hits 0]
	}

	if {[string length $hit]} {
	    # we have a matching file
	    if {[file extension $hit] == $Template(tmlExt)} {
		# our candidate is a template file
		# return the name of the file as it will be.
		if {[file extension [file root $hit]] == ""} {
		    # we're about to offer a .tml - as an .html
		    return "[file root $hit]$Template(htmlExt)"
		} else {
		    # strip the .tml and return for redirection
		    return [file root $hit]
		}
	    }
	    return $hit	;# not a templated match
	}
    }

    return {}	;# no acceptable matches
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/thread.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# threadmgr.tcl
#	Wrappers around basic thread commands
#
#	"Thread" is the C-based Tcl extension
#	"threadmgr" is the TclHttpd thread manager
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: thread.tcl,v 1.16 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::threadmgr 1.0

package require httpd	;# Httpd_GetPostData
package require httpd::config	;# Config
package require httpd::counter	;# Count
package require httpd::log	;# Log
package require httpd::url	;# Url_Unwind
package require httpd::utils	;# Stderr file ldelete

# The "Thread" package is implemented by a C extension.
# We let the main .rc script do the appropriate package
# require, and then fall back to the testthread command if necessary.

# Default is no threading until Thread_Init is called

if {![info exist Thread(enable)]} {
    set Thread(enable) 0
}

# Thread_Init
#
#	Initialize the thread dispatcher
#
# Arguments
#	max	Maximum number of threads to create.
#
# Side Effects
#	Initializes variables used by the thread dispatcher

proc Thread_Init {{max 4}} {
    global Thread
    package require Thread 2.0
    set Thread(maxthreads) $max	;# Number of threads we can create
    set Thread(threadlist) {}	;# List of threads we have created
    set Thread(freelist) {}	;# List of available threads
    set Thread(deletelist) {}	;# List of running threads to delete when done
    set Thread(queue) {}	;# List of queued requests, ?socket? cmd
    set Thread(enable) 1
}

# Thread_IsMaster
#
#	Find out if this thread is the master.
#
# Arguments
#	none
#
# Results
#	Returns true iff this thread is the master.

proc Thread_IsMaster {} {
    return [expr {![info exists ::Thread_MasterId]}]
}

# Thread_Enabled
#
#	Find out if the threading system is turned on
#
# Arguments
#	none
#
# Results
#	none

proc Thread_Enabled {} {
    global Thread
    return $Thread(enable)
}

# Thread_List
#
#	Return the list of threads
#
# Arguments
#	none
#
# Results
#	a list

proc Thread_List {} {
    global Thread
    if {$Thread(enable)} {
        return [thread::names]
    }
    return ""
}


# Thread_Start --
#	This starts a worker thread.  The big pain here is that a
#	virgin thread has none of our Tcl scripts, so we have to
#	bootstrap into a useful state.
#
# Arguments:
#	None
#
# Results:
#	The ID of the created thread

proc Thread_Start {} {
    global auto_path tcl_library
    set id [Thread_Create]
    Thread_Send $id \
	{puts stderr "Thread  starting."}

    # Set up auto_loading.  These steps may become redundent once the
    # TclpSetLibraryPath code works correctly in threads.

    Thread_Send $id \
	[list set tcl_library $tcl_library]
    Thread_Send $id \
	{source $tcl_library/init.tcl}
    Thread_Send $id \
	[list set auto_path $auto_path]

    # Suck up all the necessary packages
    # Most state comes from the initialization in the config file.
    # There is just a bit of info in the Httpd array that is set up
    # when the main server is started, which we need (e.g., the name)

    global Httpd Config
    Thread_Send $id \
	[list array set Httpd [array get Httpd]]
    Thread_Send $id \
	[list array set Config [array get Config]]

    # Let the new thread know its master's Id.  Only slave threads have
    # the "Thread_MasterId" global varaible set.
    Thread_Send $id [list set Thread_MasterId [Thread_Id]]

    Thread_Send $id [list source $Config(main)]

    return $id
}

# Thread_Dispatch --
#	This dispatches the HTTP request to a worker thread.
#	That thread should use Thread_Respond or raise an error
#	to complete the request.
#
# Arguments:
#	sock	Client connection
#	cmd	Command to invoke in a worker
#
# Side Effects:
#	Allocate a thread or queue the command/sock for later execution

proc Thread_Dispatch {sock cmd} {
    global Thread Url
    upvar #0 Httpd$sock data
    if {!$Thread(enable) || $Thread(maxthreads) == 0} {
	eval $cmd
    } else {
	if {[llength $Thread(freelist)] == 0} {
	    if {[llength $Thread(threadlist)] < $Thread(maxthreads)} {

		# Add a thread to the free pool

		set id [Thread_Start]
		lappend Thread(threadlist) $id
		lappend Thread(freelist) $id
	    } else {

		# Queue the request until a thread is available

		lappend Thread(queue) [list $sock $cmd]
		Count threadqueue
		return
	    }
	}
	set id [lindex $Thread(freelist) 0]
	set Thread(freelist) [lrange $Thread(freelist) 1 end]
	set data(master_thread) [Thread_Id]

	# Until we can pass sockets, read the post data here

	if {[info exist Url(postlength)]} {
	    while {$Url(postlength) > 0} {
		set Url(postlength) [Httpd_GetPostData $sock data(query)]
	    }
	    unset Url(postlength)
	}
	Thread_SendAsync $id [list Thread_Invoke $sock [array get data] $cmd]
    }
}

# Thread_Dispatch_General --
#	This dispatches the command to a worker thread.
#	That thread should use Thread_Respond_General or raise an error
#	to complete the request.
#
# Arguments:
#	cmd	Command to invoke in a worker
#
# Side Effects:
#	Allocate a thread or queue the command/sock for later execution

proc Thread_Dispatch_General {cmd} {
    global Thread Url
    if {!$Thread(enable) || $Thread(maxthreads) == 0} {
	eval $cmd
    } else {
	if {[llength $Thread(freelist)] == 0} {
	    if {[llength $Thread(threadlist)] < $Thread(maxthreads)} {

		# Add a thread to the free pool

		set id [Thread_Start]
		lappend Thread(threadlist) $id
		lappend Thread(freelist) $id
	    } else {

		# Queue the request until a thread is available

		lappend Thread(queue) [list $cmd]
		Count threadqueue
		return
	    }
	}
	set id [lindex $Thread(freelist) 0]
	set Thread(freelist) [lrange $Thread(freelist) 1 end]

	Thread_SendAsync $id [list Thread_Invoke_General $cmd]
    }
}

# Thread_Invoke --
#	This is invoked in a worker thread to handle an HTTP request.
#
# Arguments:
#	sock	The name of the socket connection.  Probably is not
#		an actual I/O socket.
#	datalist The contents of the connection state in array get format
#	cmd	Tcl command to eval in this thread
#
# Results:
#	None

proc Thread_Invoke {sock datalist cmd} {
    upvar #0 Httpd$sock data
    if {[info exist data]} {
	unset data
    }
    Count urlhits
    array set data $datalist

    # Make sure the thread knows which socket it's currently processing.
    # This is needed for redirects from within doc templates.
    set ::Httpd(currentSocket) $sock

    if {[catch $cmd result]} {
	global errorInfo errorCode
	Count errors
	Thread_Respond $sock [list Url_Unwind $sock $errorInfo $errorCode]
    } else {
	return $result
    }
}

# Thread_Invoke_General --
#	This is invoked in a worker thread to handle general eval request.
#
# Arguments:
#	cmd	Tcl command to eval in this thread
#
# Results:
#	None

proc Thread_Invoke_General {cmd} {
    if {[catch $cmd result]} {
	global errorInfo errorCode
	Count errors

        # An error occurred, so log it.
        Log {} bgerror "Error with code $errorCode in thread [Thread_Id]:\n$errorInfo"
    }

    Thread_MasterEvalAsync [list Thread_Free [Thread_Id]]
    return
}

# Thread_Respond --
#	This is invoked in a worker thread to respond to a request
#
# Arguments:
#	sock	Client connection
#	cmd	Command to invoke to complete the request
#
# Results:
#	1 if the request was passed to the master thread, else 0

proc Thread_Respond {sock cmd} {
    upvar #0 Httpd$sock data
    if {[info exist data(master_thread)] &&
	    $data(master_thread) != [Thread_Id]} {

	# Pass request back to the master thread
	# This includes a copy of the Httpd state (e.g., cookies)

	Thread_SendAsync $data(master_thread) [list Thread_Unwind \
		 [Thread_Id] $sock [array get data] $cmd]

        # The next iteration of the thread should not have access to
        # past connection data.
	unset data
	return 1
    } else {
	return 0
    }

}

# Thread_Unwind --
#	Invoke a response handler for a thread that handled an HTTP request.
#	This cleans up the connection in the main thread.
#
# Arguments:
#	id	The ID of the worker thread.
#	sock	The ID of the socket connection
#	datalist name, value list for the Httpd state array
#	cmd	The command to eval in the main thread
#
# Side Effects:
#	Invoke the response handler.

proc Thread_Unwind {id sock datalist cmd} {
    upvar #0 Httpd$sock data
    array set data $datalist
    if {[catch $cmd err]} {
	global errorCode errorInfo
	Url_Unwind $sock $errorInfo $errorCode
    }
    Thread_Free $id
}

# Thread_Free --
#	Mark a thread as available
#
# Arguments:
#	id	The ID of the worker thread.
#
# Side Effects:
#	Reap the thread, put it on the freelist, or perhaps handle
#	a queued request.

proc Thread_Free {id} {
    global Thread

    if {[ldelete Thread(deletelist) $id]} {
        # This thread was marked for deletion, so tell it to exit.
        Thread_SendAsync $t thread::exit
        ldelete Thread(threadlist) $id
    } elseif {[llength $Thread(queue)] > 0} {
	set state [lindex $Thread(queue) 0]
	set Thread(queue) [lrange $Thread(queue) 1 end]
        if {[llength $state] == 1} {
            # No socket was given, so just eval the command in the thread.
            set cmd [lindex $state 0]
            Thread_SendAsync $id [list Thread_Invoke_General $cmd]
        } else {
            set sock [lindex $state 0]
            set cmd [lindex $state 1]
            upvar #0 Httpd$sock data
            set data(master_thread) [Thread_Id]
            Thread_SendAsync $id [list Thread_Invoke $sock [array get data] $cmd]
        }
    } else {
	lappend Thread(freelist) $id
    }
}

# Thread_Create --
#	thread create
#
# Arguments:
#	Optional startup script
#
# Results:
#	The ID of the created thread

proc Thread_Create {{script {}}} {
    Count threads
    if {[string length $script]} {
	return [thread::create $script]
    } else {
	return [thread::create]
    }
}

# Thread_Send --
#	thread send
#
# Arguments:
#	id	Target thread
#	script	Script to send
#
# Results:
#	The results of the script

proc Thread_Send {id script} {
    if {[catch {thread::send $id $script} result]} {
	return -code error $result
    } else {
	return $result
    }
}

# Thread_MasterEval
#
#	Evaluate the given script synchronously in the master thread.
#
# Arguments
#	script	The script to evaluate.
#
# Results
#	Returns the result of evaluating the script in the master.

proc Thread_MasterEval {script} {
    if {[info exists ::Thread_MasterId]} {
        return [Thread_Send $::Thread_MasterId $script]
    } else {
        return [eval $script]
    }
}

# Thread_SendAsync --
#	thread send -async
#
# Arguments:
#	id	Target thread
#	script	Script to send
#
# Results:
#	The results of the script

proc Thread_SendAsync {id script} {
    if {[catch {thread::send -async $id $script} result]} {
	return -code error $result
    } else {
	return $result
    }
}

# Thread_MasterEvalAsync
#
#	Evaluate the given script asynchronously in the master thread.
#
# Arguments
#	script	The script to evaluate.
#
# Results
#	none.

proc Thread_MasterEvalAsync {script} {
    if {[info exists ::Thread_MasterId]} {
        return [Thread_SendAsync $::Thread_MasterId $script]
    } else {
        after 0 [list eval $script]
        return
    }
}

# Thread_Id --
#	thread::id
#
# Arguments:
#	none
#
# Results:
#	The thread ID

proc Thread_Id {} {
    thread::id
}

# Thread_IsFree --
#	Find out if a thread is on the free list.
#
# Arguments:
#	id	The thread ID
#
# Results:
#	1 or 0

proc Thread_IsFree {id} {
    global Thread
    return [expr {[lsearch $Thread(freelist) $id] >= 0}]
}

# Thread_ReapAll --
#	The master thread should reap all free threads and mark all busy
#	threads for deletion upon completion of their task.
#
# Arguments:
#	None.
#
# Results:
#	None.

proc Thread_ReapAll {} {
    if {![Thread_IsMaster]} {
        # This proc should only be called by the master thread.
        return
    }

    global Thread
    set Thread(deletelist) {}

    foreach id $Thread(threadlist) {
        if {[lsearch $Thread(freelist) $id] != -1} {
            # Free threads are told to exit and removed from the freelist.
            Thread_SendAsync $id thread::exit
        } else {
            # Busy threads are marked for deletion upon completion of their task.
            lappend Thread(deletelist) $id
        }
    }

    set Thread(threadlist) $Thread(deletelist)
    set Thread(freelist) {}
    return
}

# Thread_SendAll --
#	The master thread serially sends this script to all free threads,
#	including itself.
#
# Arguments:
#	cmd	The script to send to all threads.
#
# Results:
#	Returns the list of alternating thread id and result, or {} if
#	this thread is not the master.

proc Thread_SendAll {cmd} {
    if {![Thread_IsMaster]} {
        # This proc should only be called by the master thread.
        return {}
    }

    global Thread
    foreach id $Thread(threadlist) {
        if {[lsearch $Thread(freelist) $id] != -1} {
            # Send the same script to all free threads.
            lappend result $id [Thread_Send $id $cmd]
        }
    }
    # Also eval the script in this thread.
    catch {eval $cmd} res
    lappend result [thread::id] $res
    return $result
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/upload.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# upload.tcl
#
# File upload domain.  This implements a domain handler that
# specializes in file uploading of multipart/form-data.
# It uploads files into a particular directory and enforces
# limits on the number of files, their size, etc.
# It invokes handler procedures similar to application-direct
# handlers after doing the file upload.
#
# Brent Welch (c) 2001
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: upload.tcl,v 1.13 2004/09/05 05:10:14 coldstore Exp $

package require ncgi

package provide httpd::upload 1.0

package require httpd	;# Httpd_Error Httpd_Redirect Httpd_ReturnData Httpd_Suspend
package require httpd::url	;# Url_PostHook Url_PrefixInstall
package require httpd::utils	;# Incr K Stderr file

# Upload_Url
#	Define a subtree of the URL hierarchy that handles
#	file uploads.
#
# Arguments
#	virtual The URL prefix of the upload domain.
#	dir	The upload directory - files get placed here.	
#	command	The Tcl command to invoke after an upload.
#	args	option-value flags described below.
#		-thread <boolean>
#			If true, dispatch domain in a thread
#		-maxfiles <integer>
#			Maximum files in upload directory
#		-maxbytes <integer>
#			Maximum number of bytes in a file
#		-totalbytes <integer>
#			Limit on total bytes in all files
#			in the upload directory
#		-unique <boolean>
#			Give uploads unique names
#
# Side Effects
#	Register a prefix

proc Upload_Url {virtual dir command args} {
    global Upload
    array set opt {
	    -inThread 0
	    -maxfiles -1
	    -maxbytes -1
	    -totalbytes -1
	    -unique 0
    }
    array set opt $args
    Url_PrefixInstall $virtual [list UploadDomain $dir $command \
	$opt(-maxfiles) $opt(-maxbytes) $opt(-totalbytes) $opt(-unique)] \
	-thread $opt(-inThread) \
        -callback [list UploadTidyUp] \
	-readpost 0
}

# UploadDomain
# Main handler for Upload domains 
# This uploads the file, if it does not exceed the byte
# and file limits, then invokes the callback.
#
# Arguments
#	dir	Upload directory
#	cmd	Tcl command to call after upload
#	maxfiles	Max files per upload diretory
#	maxbytes	File byte limit
#	totalbytes	Total bytes per upload directory
#	sock	The socket back to the client
#	suffix	The part of the url after the domain prefix.
#

proc UploadDomain {dir cmd maxfiles maxbytes totalbytes unique sock suffix} {
    upvar #0 Httpd$sock data
    upvar #0 Upload$sock upload

    # Testing
    if {[string match *test* $suffix]} {
	set fd [open $dir/test w]
	fconfigure $fd -trans binary
	puts -nonewline $fd [read $sock $data(mime,content-length)]
	close $fd
	Httpd_ReturnData $sock text/html $dir/test
    }
    # Extract multi-part boundary from the headers

    if {![info exist data(mime,content-type)] || $data(proto) == "GET"} {
	set type application/x-www-urlencoded
    } else {
	set type $data(mime,content-type)
    }
    set parsedType [ncgi::parseMimeValue $type]
    if {![string match multipart/* [lindex $parsedType 0]]} {
	return -code error "Not a multipart Content-Type: [lindex $parsedType 0]"
    }
    array set options [lindex $parsedType 1]
    if {![info exists options(boundary)]} {
	return -code error "No boundary given for multipart document"
    }

    # Record upload instance data and set up a read event handler
    # so we can read large files without blocking.

    if {[info exist upload]} {
	unset upload
    }
    set upload(boundary) $options(boundary)
    set upload(dir) $dir
    set upload(cmd) $cmd
    set upload(maxfiles) $maxfiles
    set upload(totalbytes) $totalbytes
    set upload(maxbytes) $maxbytes
    set upload(suffix) $suffix
    set upload(count) $data(count)
    set upload(unique) $unique

    # These are temporary storage used when parsing the headers of each part

    set upload(headers) {}
    set upload(formName) {}
    set upload(formNames) {}

    if {$upload(maxfiles) != -1} {
	set files [glob -nocomplain -- [file join $upload(dir) *]]
	if {[llength $files] >= $upload(maxfiles)} {
	    Httpd_Error $sock 503 "Max files ($upload(maxfiles)) exceeded.<br>Unable to upload"
	    return
	}
    }

    if {$upload(maxbytes) != -1} {
	if {$upload(count) >= $upload(maxbytes)} {
	    Httpd_Error $sock 503 "File size limit ($upload(maxbytes) bytes) exceeded.<br>Unable to upload."
	    return
	}
    }

    if {$upload(totalbytes) != -1} {
	set tot $upload(count)
	foreach f [glob -nocomplain -- [file join $upload(dir) 0]] {
	    incr tot [file size $f]
	}
	if {$tot >= $upload(totalbytes)} {
	    Httpd_Error $sock 503 "Total size limit ($upload(totalbytes) bytes) exceeded.<br>Unable to upload."
	    return
	}
    }

    # Now that we are going to read the post data, clear out the
    # hook and the data count so noone else tries to read it

    Url_PostHook $sock 0
    set data(count) 0

    # Accept cr-lf endings in the headers
    fconfigure $sock -trans auto
    fileevent $sock readable [list UploadFindBoundary $sock]
}

# Look for the first boundary - should be the first line read,
# but done in a fileevent to avoid blocking.

proc UploadFindBoundary {sock} {
    upvar #0 Upload$sock upload
    if {[eof $sock]} {
	UploadDone $sock
	return
    }
    if {[gets $sock line] > 0} {
	if {[regexp ^--$upload(boundary) $line]} {
	    fileevent $sock readable [list UploadReadHeader $sock]
	} else {
	    Stderr "UploadFindBoundary Unexpected line $line"
	}
    }
}

# UploadReadHeader --
#	This is a fileeventhandler used to read the header
#	of each part in a multipart POST payload.

proc UploadReadHeader {sock} {
    upvar #0 Upload$sock upload

    if {[eof $sock]} {
	UploadDone $sock
	return
    }

    # Read through the POST data line-by-line looking for the
    # boundary and diverting file content into files in the
    # upload directory.  We read in binary mode to preserve whatever
    # line-ending mode is in the uploaded file.

    while {[gets $sock line] >= 0} {
        # Check for an empty or white-space only line.
	if {[string length [string trim $line]] == 0} {

	    # End of headers.  We should have seen a name header
	    # that is now in formName.  Keep a list of those, and 
	    # store the other headers under that key.

	    lappend upload(formNames) $upload(formName)
	    set upload(hdrs,$upload(formName)) $upload(headers)

	    # Now switch to reading the content of that part.

	    # Use binary mode so we don't corrupt the file
	    fconfigure $sock -trans binary -encoding binary

	    if {[info exist upload(fd)]} {
		fileevent $sock readable [list UploadReadFile $sock]
	    } else {
		fileevent $sock readable [list UploadReadPart $sock]
	    }
	    return
	}
	if {[regexp {([^:	 ]+):(.*)$} $line x hdrname value]} {
	    set hdrname [string tolower $hdrname]
	    set valueList [ncgi::parseMimeValue $value]
	    if {[string equal $hdrname "content-disposition"]} {

		# Promote Conent-Disposition parameters up to headers,
		# and look for the "name" that identifies the form element

		lappend upload(headers) $hdrname [lindex $valueList 0]
		foreach {n v} [lindex $valueList 1] {
		    lappend upload(headers) $n $v
		    switch -- $n {
			"name" {
			    set upload(formName) $v
			}
			"filename" {
			    # Open the upload file

			    # If the uploade file is empty string,
			    # then use a temporary name--this request
			    # will fail later.  Netscape allows you
			    # to upload dirnames like /a/b/, which
			    # end up as empty string here.
			    if {$v == ""} {
				set v "directory"
			    }

			    # I'm a bit suprised that "file tail"
			    # when run on a Unix box will not deal
			    # with c:\a\b\c.txt correctly...
			    regsub -all {\\} $v / v
			    set tail [file tail $v]
			    if {$upload(unique)} {
				# make the file a unique name
				set path [file join $upload(dir) ${tail}.[clock clicks]]
			    } else {
				set path [file join $upload(dir) $tail]
			    }

			    set upload(fd) [open $path w]
			    set upload(lastLineExists) 0

			    # always do binary transfers
			    fconfigure $upload(fd) -trans binary
			    set upload(file,$upload(formName)) $path
			}
		    }
		}
	    } else {
		lappend upload(headers) $hdrname $valueList
	    }
	}
    }

    if {[fblocked $sock]} {
	return
    }
}

# Look for the boundary at the end of a content part.

proc UploadReadPart {sock} {
    upvar #0 Upload$sock upload
    if {[eof $sock]} {
	UploadDone $sock
	return
    }
    if {[gets $sock line] > 0} {
	if {[regexp ^--$upload(boundary)(--)? $line x end]} {
	    if {$end == "--"} {
		UploadDone $sock
	    } else {
		set upload(formName) ""
		set upload(headers) ""
		fileevent $sock readable [list UploadReadHeader $sock]
	    }
	} else {
            # Trim the string to remove carriage returns.
	    append upload(data,$upload(formName)) [string trim $line]
	}
    }
}

# Read a content part and copy it to a file.
# Because the server is non-blocking, this may be called multiple times to
# process a file.

proc UploadReadFile {sock} {
    upvar #0 Upload$sock upload

    # Maximum size of the buffer, in characters, before we schedule
    # another read and update other waiting tasks.  Increasing this
    # number will probably make uploads a little faster at the expense
    # of some responsiveness on the part of other clients attempting
    # to connect to the server.
    set maxbuffersize 1000
    set buffersize 0

    if {[eof $sock]} {
	UploadDone $sock
	return
    }

    while {[gets $sock line] >= 0} {
	if {[regexp ^--$upload(boundary)(--)? $line x end]} {
	    if {$upload(lastLineExists)} {
		# At least 1 line was read.  Write the last line to the
		# file without the trailing newline character.
		puts -nonewline $upload(fd) [string range $upload(lastLine) 0 end-1]
	    }

	    set buffersize 0
	    close $upload(fd)
	    unset upload(fd)
	    if {$end == "--"} {
		UploadDone $sock
	    } else {
		set upload(formName) ""
		set upload(headers) ""
		fileevent $sock readable [list UploadReadHeader $sock]
	    }
	    return
	} else {
	    # Delay the writing of each line to make sure we don't add an
	    # extra trailing newline to the last line.
	    if {$upload(lastLineExists)} {
		puts $upload(fd) $upload(lastLine)
	    } else {
		set upload(lastLineExists) 1
	    }
	    set upload(lastLine) $line
	}
	incr buffersize [string bytelength $line]
	if { $buffersize > $maxbuffersize } {
	    set buffersize 0
	    fileevent $sock readable [list UploadReadFile $sock]
	    update idletasks
	    break
	}
    }
}

proc UploadDone {sock} {
    upvar #0 Upload$sock upload

    if {[catch {
	# The first argument is a list of file names that were uploaded
	# The second argument is a name-value list of the other data
	set flist {}
	set vlist {}
	foreach x $upload(formNames) {
	    if {[info exist upload(file,$x)]} {
		lappend flist $x $upload(file,$x)
	    } else {
		lappend vlist $x $upload(data,$x)
	    }
	}
	eval $upload(cmd) [list $flist $vlist]
    } result] == 1} {
	# handle special error codes
	set ec $::errorCode
	switch -- [lindex $ec 0] {
	    HTTPD_REDIRECT {
		Httpd_Redirect [lindex $ec 1] $sock
		return
	    }
	    HTTPD_SUSPEND {
		Httpd_Suspend $sock
		return
	    }
	}
    }

    Httpd_ReturnData $sock text/html $result
}

# This is called as the "final" completion callback to clean up

proc UploadTidyUp {sock errmsg} {
    upvar #0 Upload$sock upload

    unset upload
}

# UploadTest --
#	Sample callback procedure for an upload domain

proc UploadTest {flist vlist} {
    set html "<title>Upload Test</title>\n"
    append html "<h1>Upload Test</h1>\n"
    append html "<h2>File List</h2>\n"
    append html [html::tableFromList $flist]\n
    append html "<h2>Data List</h2>\n"
    append html [html::tableFromList $vlist]\n
    return $html
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/url.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
# url.tcl
#
# This is the URL dispatcher.  The URL hierarchy is divided into "domains"
# that are subtrees of the URL space with a particular type.  A domain is
# identified by the name of its root, which is a prefix of the URLs in
# that domain.  The dispatcher selects a domain by the longest matching
# prefix, and then calls a domain handler to process the URL.  Different
# domain handlers correspond to files (Doc), cgi-bin directories (Cgi),
# and things built right into the application (Direct).
#
# URL processing is divided into two parts: access control and
# url implementation.  You register access hooks with
# Url_AccessInstall, and you register URL implementations with
# Url_PrefixInstall.
#
# Brent Welch (c) 1997 Sun Microsystems, 1998-2000 Scriptics Corporation.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# SCCS: @(#) url.tcl 1.7 97/08/20 11:50:13

package provide httpd::url 1.2

package require httpd	;# Httpd_CompletionCallback Httpd_Error Httpd_Filter Httpd_GetPostData Httpd_ReadPostDataAsync Httpd_Redirect Httpd_RequestComplete Httpd_SockClose Httpd_Suspend
package require httpd::counter	;# Count CountName
package require httpd::doc_error	;# Doc_Error
package require httpd::threadmgr	;# Thread_Dispatch Thread_Enabled
package require httpd::utils	;# File_Reset file ldelete

# This pattern cannot occur inside a URL path component
# On windows we disallow : to avoid drive-letter attacks

switch $tcl_platform(platform) {
    windows	{ set Url(fsSep) {[/\\:]} }
    macintosh	{ set Url(fsSep) : }
    unix	-
    default	{ set Url(fsSep) / }
}

# Url_Dispatch
#
#	Dispatch to a type-specific handler for a URL
#
# Arguments
#	sock	THe client socket connection
#
# Side Effects
#	Handle the request

proc Url_Dispatch {sock} {
    global Url UrlCache
    upvar #0 Httpd$sock data

    catch {after cancel $data(cancel)}
    set url $data(url)

    CountName $url hit
    if {[catch {

	# INLINE VERSION OF Url_PrefixMatch

	# Collapse multiple // to avoid tricks like //cgi-bin that fail
	# to match the /cgi-bin prefix
	regsub -all /+ $url / url

	if {![regexp ^($Url(prefixset))(.*) $url x prefix suffix] ||
		([string length $suffix] && ![string match /* $suffix])} {

	    # Fall back and assume it is under the root
            if {[string match /* $url]} {
              set suffix [string trimleft $url /]
              set prefix /
            } else {
              # Requested URL doesn't start with slash - bad request
              Httpd_Error $sock 400
              return
            }
	}

	# END INLINE

	# Do access control before dispatch,
	# but after prefix/suffix determination

	set data(prefix) $prefix
	set data(suffix) $suffix
	CountName $prefix domainHit

	foreach hook $Url(accessHooks) {
	    switch -- [eval $hook [list $sock $url]] {
		ok	{ break }
                return  -
		denied	{
		    # A URL implementation should have generated the
		    # appropriate response, such as a 403, to request
		    # a retry. But, if it hasn't, we generate a default.

		    if {![Httpd_RequestComplete $sock]} {
			Httpd_Error $sock 403
		    }
		    return
		}
		skip	{ continue }
	    }
	}

	# Register a callback with the Httpd layer

	if {[info exist Url(callback,$prefix)]} {
	    Httpd_CompletionCallback $sock $Url(callback,$prefix)
	}

	if {[info exist Url(filter,$prefix)]} {
	    Httpd_Filter $sock $Url(filter,$prefix)
	}

	# Pre-read the post data, if the domain wants that

	if {$Url(readpost,$prefix) && $data(count) > 0} {
	    
	    Httpd_ReadPostDataAsync $sock \
		[list Url_DeferredDispatch $prefix $suffix]
	    return
	}

	# Invoke the URL domain handler either in this main thread
	# or in a worker thread

        if {[info exists Url(dispatch,$prefix)]} {
	    Count UrlCustom
	    $Url(dispatch,$prefix) $sock \
		    [concat $Url(command,$prefix) [list $sock $suffix]]
	} elseif {$Url(thread,$prefix)} {
	    Count UrlToThread
	    Thread_Dispatch $sock \
		    [concat $Url(command,$prefix) [list $sock $suffix]]
	} else {
	    Count UrlEval
	    eval $Url(command,$prefix) [list $sock $suffix]
	}
    } error] == 1} {

	# Only do this on uncaught errors.
	# Note that the return statement for the "denied" case of the
	# access hook will result in catch returning code == 2, not 1 (or zero)

	global errorInfo
	global errorCode
	Url_Unwind $sock $errorInfo $errorCode
    }
}

# Url_DeferredDispatch
#
#	Dispatch to a type-specific handler for a URL after the
#	post data has been read.
#
# Arguments
#	sock	The client socket connection
#
# Side Effects
#	Handle the request

proc Url_DeferredDispatch {prefix suffix sock varname errmsg} {
    global Url

    if {[string length $errmsg]} {
	Httpd_SockClose $sock 1 $errmsg
	return
    }
    Url_PostHook $sock 0	;# Turn of Url_ReadPost
    if {[catch {
	# Invoke the URL domain handler either in this main thread
	# or in a worker thread

	if {$Url(thread,$prefix)} {
	    Count UrlToThread
	    Thread_Dispatch $sock \
		    [concat $Url(command,$prefix) [list $sock $suffix]]
	} else {
	    Count UrlEval
	    eval $Url(command,$prefix) [list $sock $suffix]
	}
    } error] == 1} {
	global errorInfo
	global errorCode
	Url_Unwind $sock $errorInfo $errorCode
    }
}

# Url_PrefixMatch
#	Match the domain prefix of a URL
#
# Arguments
#	url	The input URL
#	suffixVar	Output variable, the suffix
#	prefixVar	Output variable, the prefix
#
# Results
#	Fills in prefix and suffix result variables

proc Url_PrefixMatch {url prefixVar suffixVar} {
    global Url
    upvar 1 $prefixVar prefix
    upvar 1 $suffixVar suffix

    # Prefix match the URL to get a domain handler
    # Fast check on domain prefixes with regexp
    # Check that the suffix starts with /, otherwise the prefix
    # is not a complete component.  E.g., "/tcl" vs "/tclhttpd"
    # where /tcl is a domain prefix but /tclhttpd is a directory
    # in the / domain.

    # IF YOU CHANGE THIS  - FIX in-line CODE IN URL_DISPATCH

    # Collapse multiple // to avoid tricks like //cgi-bin that fail
    # to match the /cgi-bin prefix
    regsub -all /+ $url / url

    if {![info exist Url(prefixset)] ||
	    ![regexp ^($Url(prefixset))(.*) $url x prefix suffix] ||
	    ([string length $suffix] && ![string match /* $suffix])} {
	# Fall back and assume it is under the root
        # We assume that Url_Dispatch has filtered out bad urls already
        set suffix [string trimleft $url /]
        set prefix /
    }
}

# Url_PrefixExists
#	Determine if a prefix has been registered.
#
# Arguments
#	prefix	The input URL
#
# Results
#	0 or 1

proc Url_PrefixExists {prefix} {
    global Url
    return [info exist Url(command,$prefix)]
}

# Url_Unwind
#	Do common error handling after a URL request
#
# Arguments
#	sock	The client connection
#	ei	The errorInfo from the command
#	ec	The errorCode from the command
#
# Side Effects
#	Clean up the connection and ensure a reply

proc Url_Unwind {sock ei ec} {

    # URL implementations can raise special errors to unwind their processing.

    set key [lindex $ec 0]
    set error [lindex [split $ei \n] 0]
    switch -- $key {
        HTTPD_REDIRECT {

	    # URL implementations can raise an error and put redirect info
	    # into the errorCode variable, which should be of the form
	    # HTTPD_REDIRECT $newurl

            Httpd_Redirect [lindex $ec 1] $sock
            return
        }
        HTTPD_SUSPEND {
	    
	    # The domain handler has until Httpd(timeout2) to complete this request
	    
            Httpd_Suspend $sock
            return
        }
    }

    switch -glob -- $ei {
	"*can not find channel*"  {
	    Httpd_SockClose $sock 1 $error
	}
	"*too many open files*" {
	    # this is lame and probably not necessary.
	    # Early bugs lead to file descriptor leaks, but
	    # these are all plugged up.
	    Count numfiles
	    Httpd_SockClose $sock 1 $error
	    File_Reset
	} 
	default {
	    Doc_Error $sock $ei
	}
    }
}

# Url_AccessInstall
#
#	Install an access check hook.
#
# Arguments
#	proc	This is a command prefix that is invoked with two additional
#		arguments to check permissions:
#			sock	The handle on the connection
#			url	The url being accessed
#		The access hook should return:
#			"ok"	Meaning access is allowed
#			"denied" Access is denied and the hook is responsible
#				for generating the Authenticate challenge
#			"skip"	Meaning the hook doesn't care about the URL,
#				but perhaps another access control hook does.
#
# Side Effects
#	Save the access control hook

proc Url_AccessInstall {proc} {
    global Url
    if {[lsearch $Url(accessHooks) $proc] < 0} {
	lappend Url(accessHooks) $proc
    }
    return
}

# Url_AccessInstallPrepend
#
#       Exactly like AccessInstall, but puts the hook first in the list

proc Url_AccessInstallPrepend {proc} {
    global Url
    if {[lsearch $Url(accessHooks) $proc] < 0} {
	set Url(accessHooks) [concat $proc $Url(accessHooks)]
    }
    return
}
# Url_AccessUnInstall
#
#       Remove an access control hook
#
# Arguments
#	proc	A procedure previously registered with Url_AccessInstall
#
# Side Effects
#	Remove the access control hook

proc Url_AccessUnInstall {proc} {
    global Url
    set ix [lsearch $Url(accessHooks) $proc]
    if {$ix >= 0} {
	set Url(accessHooks) [lreplace $Url(accessHooks) $ix $ix]
    }
    return
}

if {![info exist Url(accessHooks)]} {
    set Url(accessHooks) {}
}

# Url_PrefixInstall
#	Declare that a handler exists for a point in the URL tree
#	identified by the prefix of all URLs below that point.
#
# Arguments:
#	prefix	The leadin part of the URL, (e.., /foo/bar)
#	command	THe Domain handler command.  This is invoked with one
#		additional arument, $sock, that is the handle identifier
#		A well-known state array is available at
#		upvar #0 Httpd$sock 
#	args	This is either a single boolean that, for backwards
#		compatibility, indicates if the domain handler runs
#		in a thread, or an option-value list of:
#		-thread boolean
#			To indicate the domain handler runs in a thread
#		-callback cmd
#			A callback to make when the request completes
#			with or without error, timeout, etc.
#		-readpost boolean
#			To indicate we should pre-read POST data.
#		-filter cmd
#			A command filter to be run on dynamic content
#               -dispatch cmd
#                       A custom dispatcher.  The receiving command should
#                       accept arguments similar to Thread_Dispatch.

proc Url_PrefixInstall {prefix command args} {
    global Url

    # Add the url to the prefixset, which is a regular expression used
    # to pick off the prefix from the URL

    regsub -all {([][\\().*+?$|])} $prefix {\\\1} prefixquoted

    if {[string compare $prefix "/"] == 0} {
	# / is not in the prefixset because of some special cases.
	# See Url_Dispatch
    } elseif {![info exists Url(prefixset)]} {
	set Url(prefixset) $prefixquoted
    } else {
	set list [split $Url(prefixset) |]
	if {[lsearch $list $prefixquoted] < 0} {
	    lappend list $prefixquoted
	}
	set Url(prefixset) [join [lsort -command UrlSort $list] |]
    }

    # Install the unquoted prefix so the Url dispatch works right

    set Url(command,$prefix) $command

    # Most domains have small amounts of POST data so we read it
    # by default for them.  If you post massive amounts, create
    # a special domain that handles the post data specially.

    set readpost 1

    # Check for options on the domain

    if {[llength $args] == 1} {

	# Compatibility with early 3.* versions that didn't take
	# arbitrary flags

	set tothread [lindex $args 0]
    } else {
	set tothread 0
	foreach {n v} $args {
	    switch -- $n {
		-thread {
		    set tothread $v
		}
		-callback {
		    set Url(callback,$prefix) $v
		}
		-readpost {
		    set readpost $v
		}
		-filter {
		    set Url(filter,$prefix) $v
		}
		-dispatch {
		    set Url(dispatch,$prefix) $v
		}
		default {
		    return -code error "Unknown option $n.\
                        Must be -callback, -dispatch, -filter, -readpost or -thread"
		}
	    }
	}
    }
    set Url(readpost,$prefix) $readpost

    # The decision to use worker threads is done on a domain-by-domain basis
    #
    # Do the check against Thread_Enabled here instead of inside
    # Url_Dispatch.  This means you cannot easily turn
    # threading on and off without restarting the server.

    set Url(thread,$prefix) [expr {[Thread_Enabled] ? $tothread : 0}]
}

# Url_PrefixRemove
#
#	Undo a prefix registration
#
# Arguments:
#	prefix	The leadin part of the URL, (e.., /foo/bar)
#
# Side Effects:
#	Remove the prefix from the dispatch set.

proc Url_PrefixRemove {prefix} {
    global Url

    # Delete the prefix from the regular expression used to match URLs

    regsub -all {([][\\().*+?$|])} $prefix {\\\1} prefixquoted
    set list [split $Url(prefixset) |]
    ldelete list $prefixquoted
    set Url(prefixset) [join [lsort -command UrlSort $list] |]
    if {[info exist Url(command,$prefix)]} {
	unset Url(command,$prefix)
	unset Url(thread,$prefix)
    }
    if {[info exist Url(callback,$prefix)]} {
	unset Url(callback,$prefix)
    }
    if {[info exist Url(filter,$prefix)]} {
	unset Url(filter,$prefix)
    }
}

# UrlSort
#
#	Sort the URL prefixes so the longest ones are first.
#	The makes the regular expression match the longest
#	matching prefix.
#
# Arguments:
#	a, b	To URL prefixes
#
# Results:
#	1 if b should sort before a, -1 if a should sort before b, else 0

proc UrlSort {a b} {
    set la [string length $a]
    set lb [string length $b]
    if {$la == $lb} {
	return [string compare $a $b]
    } elseif {$la < $lb} {
	return 1
    } else {
	return -1
    }
}

# Url_Handle
#
#	Cache the handler for the url, then invoke it
#
# Arguments:
#	cmd	The command to eval to handle a URL
#	sock	The socket for the current connection.
#
# Side Effects:
#	None - used to "Caches the command used to handle the URL"

proc Url_Handle {cmd sock} {
#    upvar #0 Httpd$sock data
#    global UrlCache
#    set UrlCache($data(url)) $cmd
    eval $cmd [list $sock]
}

# Url_UnCache
#
#	Deleted the cached handler for a URL
#
# Arguments:
#	sock	The socket for the current connection.
#	force	If set, there is no special case for the redirect hack
#
# Side Effects:
#	Deletes the cached handler

proc Url_UnCache {sock {force 0}} {
    upvar #0 Httpd$sock data
    global UrlCache
    if {[info exists UrlCache($data(url))]} {
	set redirect [regexp Redirect $UrlCache($data(url))]
	if {$force || !$redirect} {
	    unset UrlCache($data(url))
	}
    }
}

# Url_PathCheck
#
#	Validate a pathname.  Make sure it doesn't sneak out of its domain.
#
# Arguments:
#	urlsuffix	The URL after the domain prefix
#
# Results:
#	Raises an error, or returns a list of components in the pathname

proc Url_PathCheck {urlsuffix} {
    global Url
    set pathlist ""
    foreach part  [split $urlsuffix /] {
	if {[string length $part] == 0} {

	    # It is important *not* to "continue" here and skip
	    # an empty component because it could be the last thing,
	    # /a/b/c/
	    # which indicates a directory.  In this case you want
	    # Auth_Check to recurse into the directory in the last step.

	}
	set part [Url_Decode $part]

	# Disallow Mac and UNIX path separators in components
	# Windows drive-letters are bad, too

	if {[regexp $Url(fsSep) $part]} {
	    error "URL components cannot include $Url(fsSep)"
	}
	switch -- $part {
	    .  { }
	    .. {
		set len [llength $pathlist]
		if {[incr len -1] < 0} {
		    error "URL out of range"
		}
		set pathlist [lrange $pathlist 0 [incr len -1]]
	    }
	    default {
		lappend pathlist $part
	    }
	}
    }
    return $pathlist
}

proc Url_PostHook {sock length} {
    global Url

    # Backdoor hack for Url_DecodeQuery compatibility
    # We remember the current connection so that Url_DecodeQuery
    # can read the post data if it has not already been read by
    # the time it is called.

    set Url(sock) $sock
    set Url(postlength) $length
}

# convert a x-www-urlencoded string into a list of name/value pairs

proc Url_DecodeQuery {query args} {
    global Url

    if {[info exist Url(sock)]} {
	Url_ReadPost $Url(sock) query
    }
    eval {Url_DecodeQueryOnly $query} $args
}

# Url_QuerySetup --
#
#	Grab any query data and pass it to the ncgi:: module.
#
# Arguments:
# 	sock	The socket back to the client.
#
# Results:
#	None
#
# Side effects:
#	ncgi::reset, ncgi::parse, ncgi::urlstup

proc Url_QuerySetup {sock} {
    upvar #0 Httpd$sock data

    set valuelist {}

    # search for comma separeted pair of numbers
    # as generated from server side map
    #      e.g 190,202
    # Bjorn Ruff.

    if { [regexp {^([0-9]+),([0-9]+)$} $data(query) match x y]} {
	set data(query) x=$x&y=$y
    }

    # Honor content type of the query data
    # Some browsers leave junk Content-Type lines in
    # non-post requests as a side effect of keep alive.

    if {[info exist data(mime,content-type)] &&
	    ("$data(proto)" != "GET")} {
	set type $data(mime,content-type)
    } else {
	set type application/x-www-urlencoded
    }

    # Grab POST data, if any, and initialize the ncgi:: interface

    Url_ReadPost $sock data(query)
    ncgi::reset $data(query) $type
    ncgi::parse
    ncgi::urlStub $data(url)
    return
}

proc Url_ReadPost {sock varname} {
    upvar 1 $varname query
    global Url

    append query ""
    if {[info exist Url(postlength)] && ($Url(postlength) > 0)} {
	
	# For compatibility with older versions of the Httpd module
	# that used to read all the post data for us, we read it now
	# if it hasn't already been read

	set result $Url(postlength)
	if {[string length $query]} {
	    # This merges query data from the GET/POST URL
	    append query &
	}
	while {$Url(postlength) > 0} {
	    set Url(postlength) [Httpd_GetPostData $sock query]
	}
	unset Url(postlength)
	return $result
    } else {
	return 0
    }
}

proc Url_DecodeQueryOnly {query args} {

    array set options {-type application/x-www-urlencoded -qualifiers {}}
    catch {array set options $args}
    if {[string length [info command Url_DecodeQuery_$options(-type)]] == 0} {
	set options(-type) application/x-www-urlencoded
    }
    return [Url_DecodeQuery_$options(-type) $query $options(-qualifiers)]
}

proc Url_DecodeQuery_application/x-www-urlencoded {query qualifiers} {

    # These foreach loops are structured this way to ensure there are matched
    # name/value pairs.  Sometimes query data gets garbled.

    set result {}
    foreach pair [split $query "&"] {
	foreach {name value} [split $pair "="] {
	    lappend result [Url_Decode $name] [Url_Decode $value]
	}
    }
    return $result
}
proc Url_Decode {data} {
    regsub -all {\+} $data " " data
    regsub -all {([][$\\])} $data {\\\1} data
    regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data  {[format %c 0x\1]} data
    return [subst $data]
}
if 0 {
    proc UrlDecodeData {data} {
	regsub -all {([][$\\])} $data {\\\1} data
	regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data  {[format %c 0x\1]} data
	return [subst $data]
    }
}


# Sharing procedure bodies doesn't work with compiled procs,
# so these call each other instead of doing
# proc xprime [info args x] [info body x]

proc Url_DecodeQuery_application/x-www-form-urlencoded {query qualifiers} {
    Url_DecodeQuery_application/x-www-urlencoded $query $qualifiers
}

# steve: 5/8/98: This is a very crude start at parsing MIME documents
# Return filename/content pairs
proc Url_DecodeQuery_multipart/form-data {query qualifiers} {

    array set options {}
    catch {array set options $qualifiers}
    if {![info exists options(boundary)]} {
	return -code error "no boundary given for multipart document"
    }

    # Filter query into a list
    # Protect Tcl special characters
    # regsub -all {([\\{}])} $query {\\\\\\1} query
    regsub -all {(\\)}  $query {\\\\\\001} query
    regsub -all {(\{)}  $query {\\\\\\002} query
    regsub -all {(\})}  $query {\\\\\\003} query
    regsub -all -- "(\r?\n?--)?$options(boundary)\r?\n?" $query "\} \{" data
    set data [subst -nocommands -novariables "\{$data\}"]

    # Remove first and last list elements, which will be empty
    set data [lrange [lreplace $data end end] 1 end]

    set result {}
    foreach element $data {

	# Get the headers from the element.  Look for the first empty line.
	set headers {}
	set elementData {}
	# Protect Tcl special characters
	# regsub -all {([\\{}])} $element {\\\\\\1} element
	regsub -all {(\\)}  $element {\\\\\\001} element
	regsub -all {(\{)}  $element {\\\\\\002} element
	regsub -all {(\})}  $element {\\\\\\003} element
	regsub \r?\n\r?\n $element "\} \{" element

	foreach {headers elementData} [subst -nocommands -novariables "\{$element\}"] break

	set headerList {}
	set parameterName {}
	regsub -all \r $headers {} headers
	foreach hdr [split $headers \n] {

	    if {[string length $hdr]} {

		set headerName {}
		set headerData {}
		if {![regexp {[ 	]*([^: 	]+)[ 	]*:[ 	]*(.*)} $hdr discard headerName headerData]} {
		    return -code error "malformed MIME header \"$hdr\""
		}

		set headerName [string tolower $headerName]
		foreach {major minor quals} [Url_DecodeMIMEField $headerData] break
		# restore Tcl special characters
	    regsub -all {(\\\001\001)} $quals {\\} quals
	    regsub -all {(\\\001\002)} $quals {\{} quals
	    regsub -all {(\\\001\003)} $quals {\}} quals

		switch -glob -- [string compare content-disposition $headerName],[string compare form-data $major] {

		    0,0 {

			# This is the name for this query parameter

			catch {unset param}
			array set param $quals
			set parameterName $param(name)

			# Include the remaining parameters, if any
			unset param(name)
			if {[llength [array names param]]} {
			    lappend headerList [list $headerName $major [array get param]]
			}

		    }

		    default {

			lappend headerList [list $headerName $major/$minor $quals]

		    }

		}

	    } else {
		break
	    }
	}
	# restore Tcl special characters
	regsub -all {(\\\001\001)} $elementData {\\} elementData
	regsub -all {(\\\001\002)} $elementData "{" elementData
	regsub -all {(\\\001\003)} $elementData "}" elementData
	lappend result $parameterName [list $headerList $elementData]
    }

    return $result
}

# Decode a MIME type
# This could possibly move into the MIME module

proc Url_DecodeMIMEField type {
    set qualList {}
    if {[regexp {([^;]+)[ 	]*;[ 	]*(.+)} $type discard type qualifiers]} {
	foreach qualifier [split $qualifiers \;] {
	    if {[regexp {[ 	]*([^=]+)="([^"]*)"} $qualifier discard name value]} {
	    } elseif {[regexp {[ 	]*([^=]+)='([^']*)'} $qualifier discard name value]} {
	    } elseif {[regexp {[ 	]*([^=]+)=([^ 	]*)} $qualifier discard name value]} {
	    } else {
		continue
	    }
	    lappend qualList $name $value
	}
    }
    foreach {major minor} [split $type /] break
    return [list [string trim $major] [string trim $minor] $qualList]
}

# do x-www-urlencoded character mapping
# The spec says: "non-alphanumeric characters are replaced by '%HH'"
 
for {set i 1} {$i <= 256} {incr i} {
    set c [format %c $i]
    if {![string match \[a-zA-Z0-9\] $c]} {
        set UrlEncodeMap($c) %[format %.2x $i]
    }
}
 
# These are handled specially
array set UrlEncodeMap {
    " " +   \n %0d%0a
}
 
# 1 leave alphanumerics characters alone
# 2 Convert every other character to an array lookup
# 3 Escape constructs that are "special" to the tcl parser
# 4 "subst" the result, doing all the array substitutions
 
proc Url_Encode {string} {
    global UrlEncodeMap 
    regsub -all \[^a-zA-Z0-9\] $string {$UrlEncodeMap(&)} string
    regsub -all \n $string {\\n} string
    regsub -all \t $string {\\t} string
    regsub -all {[][{})\\]\)} $string {\\&} string
    return [subst $string]
}
 
# Url_IsLinkToSelf
#	Compare the link to the URL of the current page.
#	If they seem to be the same thing, return 1
#
# Arguments:
#	url	The URL to compare with.
#
# Results:
#	1 if the input URL seems to be equivalent to the page's URL.
#
# Side Effects:
#	None

proc Url_IsLinkToSelf {url} {
    global page
    return [expr {[string compare $url $page(url)] == 0}]
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/utils.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
# utils.tcl
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: utils.tcl,v 1.14 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::utils 1.0

package require httpd::log	;# Log_SetFile

# Stderr - print to standard error

proc Stderr {string} {
    catch {puts stderr $string}
}

# iscommand - returns true if the command is defined  or lives in auto_index.

proc iscommand {name} {
    expr {([string length [info command $name]] > 0) || [auto_load $name]}
}

# lappendOnce - add to a list if not already there

proc lappendOnce {listName value} {
    upvar $listName list
    if {![info exists list]} {
	lappend list $value
    } else {
	set ix [lsearch $list $value]
	if {$ix < 0} {
	    lappend list $value
	}
    }
}

# setmax - set the variable to the maximum of its current value
# or the value of the second argument
# return 1 if the variable's value was changed.

proc setmax {varName value} {
    upvar $varName var
    if {![info exists var] || ($value > $var)} {
	set var $value
	return 1
    } 
    return 0
}

# setmin - set the variable to the minimum of its current value
# or the value of the second argument
# return 1 if the variable's value was changed.

proc setmin {varName value} {
    upvar $varName var
    if {![info exists var] || ($value < $var)} {
	set var $value
	return 1
    } 
    return 0
}

# Incr - version of incr that handles undefined variables.

proc Incr {varName {value 1}} {
    upvar $varName var
    if {![info exists var]} {
	set var $value
    }  else {
	set var [expr $var + $value]
    }
}

# Assign a set of variables from a list of values, a la TclX.
# If there are more values than variables, they are returned.
# If there are fewer values than variables, the variables get the empty string.

proc lassign {valueList args} {
    if {[llength $args] == 0} {
	error "wrong # args: lassign list varname ?varname..?"
    }
    if {[llength $valueList] == 0} {
	foreach x $args {
	    uplevel 1 [list set $x {}]
	}
    } else {
	uplevel 1 [list foreach $args $valueList {break}]
    }
    return [lrange $valueList [llength $args] end]
}
# Assign a set of variables from a list of values.
# If there are more values than variables, they are ignored.
# If there are fewer values than variables, the variables get the empty string.

proc lassign-brent {varList value} {
    if {[string length $value] == 0} {
	foreach var $varList {
	    uplevel [list set $var {}]
	}
    } else {
	uplevel [list foreach $varList $value { break }]
    }
}

# Delete a list item by value.  Returns 1 if the item was present, else 0

proc ldelete {varList value} {
    upvar $varList list
    if {![info exist list]} {
	return 0
    }
    set ix [lsearch $list $value]
    if {$ix >= 0} {
	set list [lreplace $list $ix $ix]
	return 1
    } else {
	return 0
    }
}

# Recursive make directory

if {$tcl_version < 7.6} {
proc makedir { pathname } {
    if {[file isdirectory $pathname]} {
	return [glob $pathname]	;# Handle ~
    } elseif {[file exists $pathname]} {
	error "Non-directory $pathname already exists."
    } else {
	# Recurse to create intermediate directories
	set parent [makedir [file dirname $pathname]]
	set pathname [file join $parent [file tail $pathname]]
	exec mkdir $pathname
	return $pathname
    }
}
} else {
proc makedir { pathname } {
    file mkdir $pathname
}
}

# see if an option matches a list of options
# return full option name if it does, otherwise ""
#  option:  the name of the option (or unique prefix)
#  list:    the list of valid options (e.g. -foo -bar ...)

proc matchOption {option list} {
    if {![regexp -- {-[a-zA-Z0-9:_-]+} $option]} {
    	error "Invalid option: \"$option\""
    }
    if {[regsub -all -- "$option\[^ \]*" $list {} {}] == 1} {
    	regexp -- "$option\[^ \]*" $list result
    	return $result
    } else {
    	return ""
    }
}

# Set local variables based on defaults - passed in as an array, and
# a set of name value pairs.  The "params" always override the current setting
# of the local variables; the defaults only get set if no vars exist.
#   array: name of the array (with default values)
#   params:  The "-name value" pairs to set

proc optionSet {array params} {
    upvar $array options
    set list [array names options -*]
    foreach {option value} $params {
	set realoption [matchOption $option $list]
	if {$realoption != ""} {
	    regexp -- {-(.*)} $realoption {} var
	    uplevel [list set $var $value]
	}
    }

    foreach {name value} [array get options -*] {
	regexp -- {-(.*)} $name {} var
	upvar $var set
	if {![info exists set]} {
	    uplevel [list set $var $value]
	}
    }
}

# "configure" for options in an array
#   name:  The name of the array containing the options
#   args:  The name value pairs

proc optionConfigure {name args} {
    upvar $name data

    set len [llength $args]
    set list [array names data -*]
    if {$len > 1 && ($len % 2) == 1} {
    	return -code error "optionConfigure Must have 1 or even number of arguments"
    }
    set result ""

    # return entire configuration list

    if {$len == 0} {
    	foreach option [lsort $list] {
	    lappend result $option $data($option)
	}

    # return a single configuration value

    } elseif {$len == 1} {
    	set option [matchOption $args $list]
    	if {$option == ""} {
	    return -code error "$args is an invalid option, should be one of: [join $list ", "]."
	}
	set result $data($option)

    # Set a bunch of options

    } else {
    	foreach {option value} $args {
	    set realoption [matchOption $option $list]
	    if {$realoption == ""} {
		return -code error "$option is an invalid option, should be one of: [join $list ", "]."
	    }
	    if {[info exists data(validate$realoption)]} {
	    	eval $data(validate$realoption) {data $realoption $value}
	    } else {
		set data($realoption) $value
	    }
	}
    }
    return $result
}


# print an import array 

proc poptions {array args} {
    upvar $array data
    puts "*** $array *** $args"
    foreach name [array names data] {
    	regexp -- {-(.*)} $name {} var
    	upvar $var value
    	if {[info exists value]} {
	    puts "${array}($var) = $value"
    	} else {
	    puts "${array}($var) = <unset>"
    	}
    }
}
# simple random number generator snagged from the net

set RNseed [pid]
proc randomx {} {
    global RNseed
    set RNseed [expr 30903*($RNseed&65535)+($RNseed>>16)]
    return [format %.4x [expr int(32767*($RNseed & 65535)/65535.0)]]
} 

# escape html characters (simple version)

proc protect_text {text} {
    array set Map { < lt   > gt   & amp   \" quot}
    regsub -all {[\\$]} $text {\\&} text
    regsub -all {[><&"]} $text {\&$Map(&);} text
    subst -nocommands $text
}

# File_Reset - hack to close files after a leak has sprung

proc File_Reset {} {
    for {set i 5} {$i <= 1025} {incr i} {
	if {! [catch {close file$i}]} {
	    append result file$i\n
	}
    }
    for {set i 10} {$i <= 1025} {incr i} {
	if {! [catch {close sock$i}]} {
	    append result sock$i\n
	}
    }
    Log_SetFile
    return $result
}

# File_List - report which files are open.

proc File_List {} {
    global OpenFiles
    for {set i 1} {$i <= 1025} {incr i} {
	if {! [catch {fconfigure file$i} conf]} {
	    append result "file$i $conf\n"
	    if {[info exist OpenFiles(file$i)]} {
		append result "file$i: $OpenFiles(file$i)\n"
	    }
	}
	if {! [catch {fconfigure sock$i} conf]} {
	    array set c {-peername {} -sockname {}}
	    array set c $conf
	    append result "sock$i $c(-peername) $c(-sockname)\n"
	}
    }
    return $result
}

# parray - version of parray that returns the result instead
# of printing it out.

proc parray {aname {pat *}} {
    upvar $aname a
    foreach name [array names a $pat] {
	setmax max [string length $name]
    }
    if {![info exists max]} {
	return {}
    }
    incr max [string length $aname]
    incr max 2
    set result {}
    foreach name [lsort [array names a $pat]] {
	append result [list set ${aname}($name) $a($name)]
	append result \n
    }
    return $result
}

#
# Example 27-3
# Listbox with optional scrollbars.
#

proc Scrolled_Listbox { f args } {
	frame $f
	listbox $f.list \
		-xscrollcommand [list Scroll_Set $f.xscroll \
			[list grid $f.xscroll -row 1 -column 0 -sticky we]] \
		-yscrollcommand [list Scroll_Set $f.yscroll \
			[list grid $f.yscroll -row 0 -column 1 -sticky ns]]
	eval {$f.list configure} $args
	scrollbar $f.xscroll -orient horizontal \
		-command [list $f.list xview]
	scrollbar $f.yscroll -orient vertical \
		-command [list $f.list yview]
	grid $f.list $f.yscroll -sticky news
	grid $f.xscroll -sticky news
	grid rowconfigure $f 0 -weight 1
	grid columnconfigure $f 0 -weight 1
	return $f.list
}


#
# Example 27-1
# A text widget and two scrollbars.
#

proc Scrolled_Text { f args } {
	frame $f
	eval {text $f.text \
		-xscrollcommand [list $f.xscroll set] \
		-yscrollcommand [list $f.yscroll set]} $args
	scrollbar $f.xscroll -orient horizontal \
		-command [list $f.text xview]
	scrollbar $f.yscroll -orient vertical \
		-command [list $f.text yview]
	grid $f.text $f.yscroll -sticky news
	grid $f.xscroll -sticky news
	grid rowconfigure $f 0 -weight 1
	grid columnconfigure $f 0 -weight 1
	return $f.text
}

#
# Example 27-2
# Scroll_Set manages optional scrollbars.
#

proc Scroll_Set {scrollbar geoCmd offset size} {
	if {$offset != 0.0 || $size != 1.0} {
		eval $geoCmd					;# Make sure it is visible
		$scrollbar set $offset $size
	} else {
		set manager [lindex $geoCmd 0]
		$manager forget $scrollbar								;# hide it
	}
}

#
# Example 31-1
# A large scrolling canvas.
#

proc Scrolled_Canvas { c args } {
	frame $c
	eval {canvas $c.canvas \
		-xscrollcommand [list $c.xscroll set] \
		-yscrollcommand [list $c.yscroll set] \
		-highlightthickness 0 \
		-borderwidth 0} $args
	scrollbar $c.xscroll -orient horizontal \
		-command [list $c.canvas xview]
	scrollbar $c.yscroll -orient vertical \
		-command [list $c.canvas yview]
	grid $c.canvas $c.yscroll -sticky news
	grid $c.xscroll -sticky ew
	grid rowconfigure $c 0 -weight 1
	grid columnconfigure $c 0 -weight 1
	return $c.canvas
}


proc ChopLine {line {limit 72}} {
    regsub -all " *\n" $line " " line
    set new {}
    while {[string length $line] > $limit} {
	set hit 0
	for {set c $limit} {$c >= 0} {incr c -1} {
	    set char [string index $line $c]
	    if {[regexp \[\ \t\n>/\] $char]} {
		set hit 1
		break
	    }
	}
	if !$hit {
	    set c $limit
	}
	append new [string trimright [string range $line 0 $c]]\n
	incr c
	set line [string range $line $c end]
    }
    append new "$line"
    return $new
}

# boolean --
#
#	Convert boolean values to 0/1
#
# Arguments:
#	value	boolean value: true/false, on/off, yes/no, etc
#
# Results:
#	Returns 0 or 1.

proc boolean value {
    if {!([regsub -nocase {^(1|yes|true|on)$} $value 1 value] || \
	  [regsub -nocase {^(0|no|false|off)$} $value 0 value])} {
	error "boolean value expected"
    }
    return $value
}


# file_latest --
#
#	Return the newest file from the list.
#
# Arguments:
#	files	A list of filenames.
#
# Results:
#	None
#
# Side Effects:
#	The name of the newest file.

proc file_latest {files} {
    set newest {}
    foreach file $files {
	if {[file readable $file]} {
	    set m [file mtime $file]
	    if {![info exist mtime] || ($m > $mtime)} {
		set mtime $m
		set newest $file
	    }
	}
    }
    return $newest
}

if {([package vcompare [package provide Tcl] 7.6] < 0)
    && [string match unix $tcl_platform(platform)]} {

    # The subcommands copy, delete, rename, and mkdir were added to
    # the Tcl command 'file' in Tcl version 7.6.  The following command
    # approximates them on Unix platforms.  It may not agree with
    # the Tcl 7.6+ command 'file' in all of its functionality (notably
    # the way it reports errors).  Further refinements should be made as
    # needed.
    rename file Tcl7.5_file
    proc file {option args} {
        switch -glob -- $option {
            c* {
                if {[string first $option copy] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                # Translate -force into -f
                if {[string match -force [lindex $args 0]]} {
                    set args [lreplace $args 0 0 -f]
                }
                uplevel exec cp $args
            }
            de* {
                if {[string first $option delete] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                if {[string match -force [lindex $args 0]]} {
                    set args [lreplace $args 0 0 -f]
                }
                catch {uplevel exec rm $args}
            }
            mk* {
                if {[string first $option mkdir] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                uplevel exec mkdir $args
            }
            ren* {
                if {[string first $option rename] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                if {[string match -force [lindex $args 0]]} {
                    set args [lreplace $args 0 0 -f]
                }
                uplevel exec mv $args
            }
            default {
                uplevel [list Tcl7.5_file $option] $args
            }
        }
    }
}

if {[package vcompare [package provide Tcl] 8] < 0} {
    
    # The subcommands nativename and attributes were added to
    # the Tcl command 'file' in Tcl version 8.0.  Here is an approximation
    # for earlier Tcl versions:
    rename file Tcl7.6_file
    ;proc file {option args} {
        switch -glob -- $option {
            att* {
                if {[string first $option attributes] != 0} {
                    uplevel [list Tcl7.6_file $option] $args
                }
                return -code error "Tcl [package provide Tcl] does not support\
			\[file attributes\].\n\tUpgrade to Tcl 8.0 to use it."
            }
            n* {
                if {[string first $option nativename] != 0} {
                    uplevel [list Tcl7.6_file $option] $args
                }
                if {![llength $args]} {
                    return -code error "wrong # args: should be\
                	    \"file nativename name ?arg ...?\""
                }
                set fcomps [file split [lindex $args 0]]
                # Take care of tilde substitution
                set first [lindex $fcomps 0]
                if {[string match ~* $first]} {
                    set first [file join [file dirname $first] [file tail $first]]
                }
                set result [eval file join [list $first] [lrange $fcomps 1 end]]
                global tcl_platform
                if {[string match windows $tcl_platform(platform)]} {
                    regsub -all -- / $result \\ result
                }
                return $result
            }
            default {
                uplevel [list Tcl7.6_file $option] $args
            }
        }
    }
}

if {[package vcompare [package provide Tcl] 8.4] < 0} {
    # The subcommands nativename and attributes were added to
    # the Tcl command 'file' in Tcl version 8.0.  Here is an approximation
    # for earlier Tcl versions:
    rename file Tcl8.0_file
    ;proc file {option args} {
        switch -glob -- $option {
	    norm* {
		set sp [file split [lindex $args 0]]
		if {[file pathtype [lindex $sp 0]] == "relative"} {
		    set sp [file split [eval [list file join [pwd]] $sp]]
		}
		set np {}
		foreach ele $sp {
		    if {$ele != ".."} {
			if {$ele != "."} { lappend np $ele }
		    } elseif {[llength $np]> 1} {
			set np [lrange $np 0 [expr {[llength $np] - 2}]]
		    }
		}
		if {[llength $np] > 0} { return [eval file join $np] }
	    }
	    default {
		uplevel [list Tcl8.0_file $option] $args
	    }
	}
    }
}

# see http://mini.net/tcl/lambda
proc K {a b} {set a}
proc lambda {argl body} {K [info level 0] [proc [info level 0] $argl $body]}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted lib/version.tcl.

1
2
3
4
5
package provide httpd::version 3.5
proc Httpd_Version {} {
    global Httpd
    set Httpd(version)	"3.5.2 CVS"
}
<
<
<
<
<










Added modules/bootstrap/bootstrap.tcl.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
###
# Add hooks for bootstrap
###

package require httpd::doc	;# Httpd_Redirect Httpd_ReturnData

set PWD [file dirname [file normalize [info script]]]

Doc_AddRoot /bootstrap/css $PWD/css
Doc_AddRoot /bootstrap/fonts $PWD/fonts
Doc_AddRoot /bootstrap/js $PWD/js

package provide httpd::bootstrap 0.1

Added modules/bootstrap/css/bootstrap-theme.css.

























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn-default .badge,
.btn-primary .badge,
.btn-success .badge,
.btn-info .badge,
.btn-warning .badge,
.btn-danger .badge {
  text-shadow: none;
}
.btn:active,
.btn.active {
  background-image: none;
}
.btn-default {
  text-shadow: 0 1px 0 #fff;
  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #dbdbdb;
  border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
  background-color: #e0e0e0;
  background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
  background-color: #e0e0e0;
  border-color: #dbdbdb;
}
.btn-default.disabled,
.btn-default:disabled,
.btn-default[disabled] {
  background-color: #e0e0e0;
  background-image: none;
}
.btn-primary {
  background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
  background-image:      -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
  background-image:         linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #245580;
}
.btn-primary:hover,
.btn-primary:focus {
  background-color: #265a88;
  background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
  background-color: #265a88;
  border-color: #245580;
}
.btn-primary.disabled,
.btn-primary:disabled,
.btn-primary[disabled] {
  background-color: #265a88;
  background-image: none;
}
.btn-success {
  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
  background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
  background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
  background-color: #419641;
  background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
  background-color: #419641;
  border-color: #3e8f3e;
}
.btn-success.disabled,
.btn-success:disabled,
.btn-success[disabled] {
  background-color: #419641;
  background-image: none;
}
.btn-info {
  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
  background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
  background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
  background-color: #2aabd2;
  background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
  background-color: #2aabd2;
  border-color: #28a4c9;
}
.btn-info.disabled,
.btn-info:disabled,
.btn-info[disabled] {
  background-color: #2aabd2;
  background-image: none;
}
.btn-warning {
  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
  background-color: #eb9316;
  background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
  background-color: #eb9316;
  border-color: #e38d13;
}
.btn-warning.disabled,
.btn-warning:disabled,
.btn-warning[disabled] {
  background-color: #eb9316;
  background-image: none;
}
.btn-danger {
  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
  background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
  background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
  background-color: #c12e2a;
  background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
  background-color: #c12e2a;
  border-color: #b92c28;
}
.btn-danger.disabled,
.btn-danger:disabled,
.btn-danger[disabled] {
  background-color: #c12e2a;
  background-image: none;
}
.thumbnail,
.img-thumbnail {
  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
  background-color: #e8e8e8;
  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
  background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
  background-color: #2e6da4;
  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
  background-repeat: repeat-x;
}
.navbar-default {
  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
  border-radius: 4px;
  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .active > a {
  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
  background-repeat: repeat-x;
  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
  background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
  background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
  background-repeat: repeat-x;
}
.navbar-inverse .navbar-nav > .open > a,
.navbar-inverse .navbar-nav > .active > a {
  background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
  background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
  background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
  background-repeat: repeat-x;
  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
  border-radius: 0;
}
@media (max-width: 767px) {
  .navbar .navbar-nav .open .dropdown-menu > .active > a,
  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
    color: #fff;
    background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
    background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
    background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
    background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
    background-repeat: repeat-x;
  }
}
.alert {
  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
  background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
  background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
  background-repeat: repeat-x;
  border-color: #b2dba1;
}
.alert-info {
  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
  background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
  background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
  background-repeat: repeat-x;
  border-color: #9acfea;
}
.alert-warning {
  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
  background-repeat: repeat-x;
  border-color: #f5e79e;
}
.alert-danger {
  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
  background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
  background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
  background-repeat: repeat-x;
  border-color: #dca7a7;
}
.progress {
  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
  background-repeat: repeat-x;
}
.progress-bar {
  background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
  background-image:      -o-linear-gradient(top, #337ab7 0%, #286090 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
  background-image:         linear-gradient(to bottom, #337ab7 0%, #286090 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
  background-repeat: repeat-x;
}
.progress-bar-success {
  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
  background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
  background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
  background-repeat: repeat-x;
}
.progress-bar-info {
  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
  background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
  background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
  background-repeat: repeat-x;
}
.progress-bar-warning {
  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
  background-repeat: repeat-x;
}
.progress-bar-danger {
  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
  background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
  background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
  background-repeat: repeat-x;
}
.progress-bar-striped {
  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.list-group {
  border-radius: 4px;
  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
  text-shadow: 0 -1px 0 #286090;
  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
  background-image:      -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
  background-image:         linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
  background-repeat: repeat-x;
  border-color: #2b669a;
}
.list-group-item.active .badge,
.list-group-item.active:hover .badge,
.list-group-item.active:focus .badge {
  text-shadow: none;
}
.panel {
  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
  background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
  background-repeat: repeat-x;
}
.panel-success > .panel-heading {
  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
  background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
  background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
  background-repeat: repeat-x;
}
.panel-info > .panel-heading {
  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
  background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
  background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
  background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
  background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
  background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
  background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
  background-repeat: repeat-x;
}
.well {
  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
  background-repeat: repeat-x;
  border-color: #dcdcdc;
  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

Added modules/bootstrap/css/bootstrap-theme.css.map.

cannot compute difference between binary files

Added modules/bootstrap/css/bootstrap-theme.min.css.











>
>
>
>
>
1
2
3
4
5
/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary:disabled,.btn-primary[disabled]{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}

Added modules/bootstrap/css/bootstrap.css.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
html {
  font-family: sans-serif;
  -webkit-text-size-adjust: 100%;
      -ms-text-size-adjust: 100%;
}
body {
  margin: 0;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
  display: block;
}
audio,
canvas,
progress,
video {
  display: inline-block;
  vertical-align: baseline;
}
audio:not([controls]) {
  display: none;
  height: 0;
}
[hidden],
template {
  display: none;
}
a {
  background-color: transparent;
}
a:active,
a:hover {
  outline: 0;
}
abbr[title] {
  border-bottom: 1px dotted;
}
b,
strong {
  font-weight: bold;
}
dfn {
  font-style: italic;
}
h1 {
  margin: .67em 0;
  font-size: 2em;
}
mark {
  color: #000;
  background: #ff0;
}
small {
  font-size: 80%;
}
sub,
sup {
  position: relative;
  font-size: 75%;
  line-height: 0;
  vertical-align: baseline;
}
sup {
  top: -.5em;
}
sub {
  bottom: -.25em;
}
img {
  border: 0;
}
svg:not(:root) {
  overflow: hidden;
}
figure {
  margin: 1em 40px;
}
hr {
  height: 0;
  -webkit-box-sizing: content-box;
     -moz-box-sizing: content-box;
          box-sizing: content-box;
}
pre {
  overflow: auto;
}
code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em;
}
button,
input,
optgroup,
select,
textarea {
  margin: 0;
  font: inherit;
  color: inherit;
}
button {
  overflow: visible;
}
button,
select {
  text-transform: none;
}
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button;
  cursor: pointer;
}
button[disabled],
html input[disabled] {
  cursor: default;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
  padding: 0;
  border: 0;
}
input {
  line-height: normal;
}
input[type="checkbox"],
input[type="radio"] {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
  padding: 0;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto;
}
input[type="search"] {
  -webkit-box-sizing: content-box;
     -moz-box-sizing: content-box;
          box-sizing: content-box;
  -webkit-appearance: textfield;
}
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}
fieldset {
  padding: .35em .625em .75em;
  margin: 0 2px;
  border: 1px solid #c0c0c0;
}
legend {
  padding: 0;
  border: 0;
}
textarea {
  overflow: auto;
}
optgroup {
  font-weight: bold;
}
table {
  border-spacing: 0;
  border-collapse: collapse;
}
td,
th {
  padding: 0;
}
/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
@media print {
  *,
  *:before,
  *:after {
    color: #000 !important;
    text-shadow: none !important;
    background: transparent !important;
    -webkit-box-shadow: none !important;
            box-shadow: none !important;
  }
  a,
  a:visited {
    text-decoration: underline;
  }
  a[href]:after {
    content: " (" attr(href) ")";
  }
  abbr[title]:after {
    content: " (" attr(title) ")";
  }
  a[href^="#"]:after,
  a[href^="javascript:"]:after {
    content: "";
  }
  pre,
  blockquote {
    border: 1px solid #999;

    page-break-inside: avoid;
  }
  thead {
    display: table-header-group;
  }
  tr,
  img {
    page-break-inside: avoid;
  }
  img {
    max-width: 100% !important;
  }
  p,
  h2,
  h3 {
    orphans: 3;
    widows: 3;
  }
  h2,
  h3 {
    page-break-after: avoid;
  }
  select {
    background: #fff !important;
  }
  .navbar {
    display: none;
  }
  .btn > .caret,
  .dropup > .btn > .caret {
    border-top-color: #000 !important;
  }
  .label {
    border: 1px solid #000;
  }
  .table {
    border-collapse: collapse !important;
  }
  .table td,
  .table th {
    background-color: #fff !important;
  }
  .table-bordered th,
  .table-bordered td {
    border: 1px solid #ddd !important;
  }
}
@font-face {
  font-family: 'Glyphicons Halflings';

  src: url('../fonts/glyphicons-halflings-regular.eot');
  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
.glyphicon {
  position: relative;
  top: 1px;
  display: inline-block;
  font-family: 'Glyphicons Halflings';
  font-style: normal;
  font-weight: normal;
  line-height: 1;

  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.glyphicon-asterisk:before {
  content: "\2a";
}
.glyphicon-plus:before {
  content: "\2b";
}
.glyphicon-euro:before,
.glyphicon-eur:before {
  content: "\20ac";
}
.glyphicon-minus:before {
  content: "\2212";
}
.glyphicon-cloud:before {
  content: "\2601";
}
.glyphicon-envelope:before {
  content: "\2709";
}
.glyphicon-pencil:before {
  content: "\270f";
}
.glyphicon-glass:before {
  content: "\e001";
}
.glyphicon-music:before {
  content: "\e002";
}
.glyphicon-search:before {
  content: "\e003";
}
.glyphicon-heart:before {
  content: "\e005";
}
.glyphicon-star:before {
  content: "\e006";
}
.glyphicon-star-empty:before {
  content: "\e007";
}
.glyphicon-user:before {
  content: "\e008";
}
.glyphicon-film:before {
  content: "\e009";
}
.glyphicon-th-large:before {
  content: "\e010";
}
.glyphicon-th:before {
  content: "\e011";
}
.glyphicon-th-list:before {
  content: "\e012";
}
.glyphicon-ok:before {
  content: "\e013";
}
.glyphicon-remove:before {
  content: "\e014";
}
.glyphicon-zoom-in:before {
  content: "\e015";
}
.glyphicon-zoom-out:before {
  content: "\e016";
}
.glyphicon-off:before {
  content: "\e017";
}
.glyphicon-signal:before {
  content: "\e018";
}
.glyphicon-cog:before {
  content: "\e019";
}
.glyphicon-trash:before {
  content: "\e020";
}
.glyphicon-home:before {
  content: "\e021";
}
.glyphicon-file:before {
  content: "\e022";
}
.glyphicon-time:before {
  content: "\e023";
}
.glyphicon-road:before {
  content: "\e024";
}
.glyphicon-download-alt:before {
  content: "\e025";
}
.glyphicon-download:before {
  content: "\e026";
}
.glyphicon-upload:before {
  content: "\e027";
}
.glyphicon-inbox:before {
  content: "\e028";
}
.glyphicon-play-circle:before {
  content: "\e029";
}
.glyphicon-repeat:before {
  content: "\e030";
}
.glyphicon-refresh:before {
  content: "\e031";
}
.glyphicon-list-alt:before {
  content: "\e032";
}
.glyphicon-lock:before {
  content: "\e033";
}
.glyphicon-flag:before {
  content: "\e034";
}
.glyphicon-headphones:before {
  content: "\e035";
}
.glyphicon-volume-off:before {
  content: "\e036";
}
.glyphicon-volume-down:before {
  content: "\e037";
}
.glyphicon-volume-up:before {
  content: "\e038";
}
.glyphicon-qrcode:before {
  content: "\e039";
}
.glyphicon-barcode:before {
  content: "\e040";
}
.glyphicon-tag:before {
  content: "\e041";
}
.glyphicon-tags:before {
  content: "\e042";
}
.glyphicon-book:before {
  content: "\e043";
}
.glyphicon-bookmark:before {
  content: "\e044";
}
.glyphicon-print:before {
  content: "\e045";
}
.glyphicon-camera:before {
  content: "\e046";
}
.glyphicon-font:before {
  content: "\e047";
}
.glyphicon-bold:before {
  content: "\e048";
}
.glyphicon-italic:before {
  content: "\e049";
}
.glyphicon-text-height:before {
  content: "\e050";
}
.glyphicon-text-width:before {
  content: "\e051";
}
.glyphicon-align-left:before {
  content: "\e052";
}
.glyphicon-align-center:before {
  content: "\e053";
}
.glyphicon-align-right:before {
  content: "\e054";
}
.glyphicon-align-justify:before {
  content: "\e055";
}
.glyphicon-list:before {
  content: "\e056";
}
.glyphicon-indent-left:before {
  content: "\e057";
}
.glyphicon-indent-right:before {
  content: "\e058";
}
.glyphicon-facetime-video:before {
  content: "\e059";
}
.glyphicon-picture:before {
  content: "\e060";
}
.glyphicon-map-marker:before {
  content: "\e062";
}
.glyphicon-adjust:before {
  content: "\e063";
}
.glyphicon-tint:before {
  content: "\e064";
}
.glyphicon-edit:before {
  content: "\e065";
}
.glyphicon-share:before {
  content: "\e066";
}
.glyphicon-check:before {
  content: "\e067";
}
.glyphicon-move:before {
  content: "\e068";
}
.glyphicon-step-backward:before {
  content: "\e069";
}
.glyphicon-fast-backward:before {
  content: "\e070";
}
.glyphicon-backward:before {
  content: "\e071";
}
.glyphicon-play:before {
  content: "\e072";
}
.glyphicon-pause:before {
  content: "\e073";
}
.glyphicon-stop:before {
  content: "\e074";
}
.glyphicon-forward:before {
  content: "\e075";
}
.glyphicon-fast-forward:before {
  content: "\e076";
}
.glyphicon-step-forward:before {
  content: "\e077";
}
.glyphicon-eject:before {
  content: "\e078";
}
.glyphicon-chevron-left:before {
  content: "\e079";
}
.glyphicon-chevron-right:before {
  content: "\e080";
}
.glyphicon-plus-sign:before {
  content: "\e081";
}
.glyphicon-minus-sign:before {
  content: "\e082";
}
.glyphicon-remove-sign:before {
  content: "\e083";
}
.glyphicon-ok-sign:before {
  content: "\e084";
}
.glyphicon-question-sign:before {
  content: "\e085";
}
.glyphicon-info-sign:before {
  content: "\e086";
}
.glyphicon-screenshot:before {
  content: "\e087";
}
.glyphicon-remove-circle:before {
  content: "\e088";
}
.glyphicon-ok-circle:before {
  content: "\e089";
}
.glyphicon-ban-circle:before {
  content: "\e090";
}
.glyphicon-arrow-left:before {
  content: "\e091";
}
.glyphicon-arrow-right:before {
  content: "\e092";
}
.glyphicon-arrow-up:before {
  content: "\e093";
}
.glyphicon-arrow-down:before {
  content: "\e094";
}
.glyphicon-share-alt:before {
  content: "\e095";
}
.glyphicon-resize-full:before {
  content: "\e096";
}
.glyphicon-resize-small:before {
  content: "\e097";
}
.glyphicon-exclamation-sign:before {
  content: "\e101";
}
.glyphicon-gift:before {
  content: "\e102";
}
.glyphicon-leaf:before {
  content: "\e103";
}
.glyphicon-fire:before {
  content: "\e104";
}
.glyphicon-eye-open:before {
  content: "\e105";
}
.glyphicon-eye-close:before {
  content: "\e106";
}
.glyphicon-warning-sign:before {
  content: "\e107";
}
.glyphicon-plane:before {
  content: "\e108";
}
.glyphicon-calendar:before {
  content: "\e109";
}
.glyphicon-random:before {
  content: "\e110";
}
.glyphicon-comment:before {
  content: "\e111";
}
.glyphicon-magnet:before {
  content: "\e112";
}
.glyphicon-chevron-up:before {
  content: "\e113";
}
.glyphicon-chevron-down:before {
  content: "\e114";
}
.glyphicon-retweet:before {
  content: "\e115";
}
.glyphicon-shopping-cart:before {
  content: "\e116";
}
.glyphicon-folder-close:before {
  content: "\e117";
}
.glyphicon-folder-open:before {
  content: "\e118";
}
.glyphicon-resize-vertical:before {
  content: "\e119";
}
.glyphicon-resize-horizontal:before {
  content: "\e120";
}
.glyphicon-hdd:before {
  content: "\e121";
}
.glyphicon-bullhorn:before {
  content: "\e122";
}
.glyphicon-bell:before {
  content: "\e123";
}
.glyphicon-certificate:before {
  content: "\e124";
}
.glyphicon-thumbs-up:before {
  content: "\e125";
}
.glyphicon-thumbs-down:before {
  content: "\e126";
}
.glyphicon-hand-right:before {
  content: "\e127";
}
.glyphicon-hand-left:before {
  content: "\e128";
}
.glyphicon-hand-up:before {
  content: "\e129";
}
.glyphicon-hand-down:before {
  content: "\e130";
}
.glyphicon-circle-arrow-right:before {
  content: "\e131";
}
.glyphicon-circle-arrow-left:before {
  content: "\e132";
}
.glyphicon-circle-arrow-up:before {
  content: "\e133";
}
.glyphicon-circle-arrow-down:before {
  content: "\e134";
}
.glyphicon-globe:before {
  content: "\e135";
}
.glyphicon-wrench:before {
  content: "\e136";
}
.glyphicon-tasks:before {
  content: "\e137";
}
.glyphicon-filter:before {
  content: "\e138";
}
.glyphicon-briefcase:before {
  content: "\e139";
}
.glyphicon-fullscreen:before {
  content: "\e140";
}
.glyphicon-dashboard:before {
  content: "\e141";
}
.glyphicon-paperclip:before {
  content: "\e142";
}
.glyphicon-heart-empty:before {
  content: "\e143";
}
.glyphicon-link:before {
  content: "\e144";
}
.glyphicon-phone:before {
  content: "\e145";
}
.glyphicon-pushpin:before {
  content: "\e146";
}
.glyphicon-usd:before {
  content: "\e148";
}
.glyphicon-gbp:before {
  content: "\e149";
}
.glyphicon-sort:before {
  content: "\e150";
}
.glyphicon-sort-by-alphabet:before {
  content: "\e151";
}
.glyphicon-sort-by-alphabet-alt:before {
  content: "\e152";
}
.glyphicon-sort-by-order:before {
  content: "\e153";
}
.glyphicon-sort-by-order-alt:before {
  content: "\e154";
}
.glyphicon-sort-by-attributes:before {
  content: "\e155";
}
.glyphicon-sort-by-attributes-alt:before {
  content: "\e156";
}
.glyphicon-unchecked:before {
  content: "\e157";
}
.glyphicon-expand:before {
  content: "\e158";
}
.glyphicon-collapse-down:before {
  content: "\e159";
}
.glyphicon-collapse-up:before {
  content: "\e160";
}
.glyphicon-log-in:before {
  content: "\e161";
}
.glyphicon-flash:before {
  content: "\e162";
}
.glyphicon-log-out:before {
  content: "\e163";
}
.glyphicon-new-window:before {
  content: "\e164";
}
.glyphicon-record:before {
  content: "\e165";
}
.glyphicon-save:before {
  content: "\e166";
}
.glyphicon-open:before {
  content: "\e167";
}
.glyphicon-saved:before {
  content: "\e168";
}
.glyphicon-import:before {
  content: "\e169";
}
.glyphicon-export:before {
  content: "\e170";
}
.glyphicon-send:before {
  content: "\e171";
}
.glyphicon-floppy-disk:before {
  content: "\e172";
}
.glyphicon-floppy-saved:before {
  content: "\e173";
}
.glyphicon-floppy-remove:before {
  content: "\e174";
}
.glyphicon-floppy-save:before {
  content: "\e175";
}
.glyphicon-floppy-open:before {
  content: "\e176";
}
.glyphicon-credit-card:before {
  content: "\e177";
}
.glyphicon-transfer:before {
  content: "\e178";
}
.glyphicon-cutlery:before {
  content: "\e179";
}
.glyphicon-header:before {
  content: "\e180";
}
.glyphicon-compressed:before {
  content: "\e181";
}
.glyphicon-earphone:before {
  content: "\e182";
}
.glyphicon-phone-alt:before {
  content: "\e183";
}
.glyphicon-tower:before {
  content: "\e184";
}
.glyphicon-stats:before {
  content: "\e185";
}
.glyphicon-sd-video:before {
  content: "\e186";
}
.glyphicon-hd-video:before {
  content: "\e187";
}
.glyphicon-subtitles:before {
  content: "\e188";
}
.glyphicon-sound-stereo:before {
  content: "\e189";
}
.glyphicon-sound-dolby:before {
  content: "\e190";
}
.glyphicon-sound-5-1:before {
  content: "\e191";
}
.glyphicon-sound-6-1:before {
  content: "\e192";
}
.glyphicon-sound-7-1:before {
  content: "\e193";
}
.glyphicon-copyright-mark:before {
  content: "\e194";
}
.glyphicon-registration-mark:before {
  content: "\e195";
}
.glyphicon-cloud-download:before {
  content: "\e197";
}
.glyphicon-cloud-upload:before {
  content: "\e198";
}
.glyphicon-tree-conifer:before {
  content: "\e199";
}
.glyphicon-tree-deciduous:before {
  content: "\e200";
}
.glyphicon-cd:before {
  content: "\e201";
}
.glyphicon-save-file:before {
  content: "\e202";
}
.glyphicon-open-file:before {
  content: "\e203";
}
.glyphicon-level-up:before {
  content: "\e204";
}
.glyphicon-copy:before {
  content: "\e205";
}
.glyphicon-paste:before {
  content: "\e206";
}
.glyphicon-alert:before {
  content: "\e209";
}
.glyphicon-equalizer:before {
  content: "\e210";
}
.glyphicon-king:before {
  content: "\e211";
}
.glyphicon-queen:before {
  content: "\e212";
}
.glyphicon-pawn:before {
  content: "\e213";
}
.glyphicon-bishop:before {
  content: "\e214";
}
.glyphicon-knight:before {
  content: "\e215";
}
.glyphicon-baby-formula:before {
  content: "\e216";
}
.glyphicon-tent:before {
  content: "\26fa";
}
.glyphicon-blackboard:before {
  content: "\e218";
}
.glyphicon-bed:before {
  content: "\e219";
}
.glyphicon-apple:before {
  content: "\f8ff";
}
.glyphicon-erase:before {
  content: "\e221";
}
.glyphicon-hourglass:before {
  content: "\231b";
}
.glyphicon-lamp:before {
  content: "\e223";
}
.glyphicon-duplicate:before {
  content: "\e224";
}
.glyphicon-piggy-bank:before {
  content: "\e225";
}
.glyphicon-scissors:before {
  content: "\e226";
}
.glyphicon-bitcoin:before {
  content: "\e227";
}
.glyphicon-btc:before {
  content: "\e227";
}
.glyphicon-xbt:before {
  content: "\e227";
}
.glyphicon-yen:before {
  content: "\00a5";
}
.glyphicon-jpy:before {
  content: "\00a5";
}
.glyphicon-ruble:before {
  content: "\20bd";
}
.glyphicon-rub:before {
  content: "\20bd";
}
.glyphicon-scale:before {
  content: "\e230";
}
.glyphicon-ice-lolly:before {
  content: "\e231";
}
.glyphicon-ice-lolly-tasted:before {
  content: "\e232";
}
.glyphicon-education:before {
  content: "\e233";
}
.glyphicon-option-horizontal:before {
  content: "\e234";
}
.glyphicon-option-vertical:before {
  content: "\e235";
}
.glyphicon-menu-hamburger:before {
  content: "\e236";
}
.glyphicon-modal-window:before {
  content: "\e237";
}
.glyphicon-oil:before {
  content: "\e238";
}
.glyphicon-grain:before {
  content: "\e239";
}
.glyphicon-sunglasses:before {
  content: "\e240";
}
.glyphicon-text-size:before {
  content: "\e241";
}
.glyphicon-text-color:before {
  content: "\e242";
}
.glyphicon-text-background:before {
  content: "\e243";
}
.glyphicon-object-align-top:before {
  content: "\e244";
}
.glyphicon-object-align-bottom:before {
  content: "\e245";
}
.glyphicon-object-align-horizontal:before {
  content: "\e246";
}
.glyphicon-object-align-left:before {
  content: "\e247";
}
.glyphicon-object-align-vertical:before {
  content: "\e248";
}
.glyphicon-object-align-right:before {
  content: "\e249";
}
.glyphicon-triangle-right:before {
  content: "\e250";
}
.glyphicon-triangle-left:before {
  content: "\e251";
}
.glyphicon-triangle-bottom:before {
  content: "\e252";
}
.glyphicon-triangle-top:before {
  content: "\e253";
}
.glyphicon-console:before {
  content: "\e254";
}
.glyphicon-superscript:before {
  content: "\e255";
}
.glyphicon-subscript:before {
  content: "\e256";
}
.glyphicon-menu-left:before {
  content: "\e257";
}
.glyphicon-menu-right:before {
  content: "\e258";
}
.glyphicon-menu-down:before {
  content: "\e259";
}
.glyphicon-menu-up:before {
  content: "\e260";
}
* {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}
*:before,
*:after {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}
html {
  font-size: 10px;

  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.42857143;
  color: #333;
  background-color: #fff;
}
input,
button,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}
a {
  color: #337ab7;
  text-decoration: none;
}
a:hover,
a:focus {
  color: #23527c;
  text-decoration: underline;
}
a:focus {
  outline: thin dotted;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}
figure {
  margin: 0;
}
img {
  vertical-align: middle;
}
.img-responsive,
.thumbnail > img,
.thumbnail a > img,
.carousel-inner > .item > img,
.carousel-inner > .item > a > img {
  display: block;
  max-width: 100%;
  height: auto;
}
.img-rounded {
  border-radius: 6px;
}
.img-thumbnail {
  display: inline-block;
  max-width: 100%;
  height: auto;
  padding: 4px;
  line-height: 1.42857143;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  -webkit-transition: all .2s ease-in-out;
       -o-transition: all .2s ease-in-out;
          transition: all .2s ease-in-out;
}
.img-circle {
  border-radius: 50%;
}
hr {
  margin-top: 20px;
  margin-bottom: 20px;
  border: 0;
  border-top: 1px solid #eee;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}
.sr-only-focusable:active,
.sr-only-focusable:focus {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
}
[role="button"] {
  cursor: pointer;
}
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
  font-family: inherit;
  font-weight: 500;
  line-height: 1.1;
  color: inherit;
}
h1 small,
h2 small,
h3 small,
h4 small,
h5 small,
h6 small,
.h1 small,
.h2 small,
.h3 small,
.h4 small,
.h5 small,
.h6 small,
h1 .small,
h2 .small,
h3 .small,
h4 .small,
h5 .small,
h6 .small,
.h1 .small,
.h2 .small,
.h3 .small,
.h4 .small,
.h5 .small,
.h6 .small {
  font-weight: normal;
  line-height: 1;
  color: #777;
}
h1,
.h1,
h2,
.h2,
h3,
.h3 {
  margin-top: 20px;
  margin-bottom: 10px;
}
h1 small,
.h1 small,
h2 small,
.h2 small,
h3 small,
.h3 small,
h1 .small,
.h1 .small,
h2 .small,
.h2 .small,
h3 .small,
.h3 .small {
  font-size: 65%;
}
h4,
.h4,
h5,
.h5,
h6,
.h6 {
  margin-top: 10px;
  margin-bottom: 10px;
}
h4 small,
.h4 small,
h5 small,
.h5 small,
h6 small,
.h6 small,
h4 .small,
.h4 .small,
h5 .small,
.h5 .small,
h6 .small,
.h6 .small {
  font-size: 75%;
}
h1,
.h1 {
  font-size: 36px;
}
h2,
.h2 {
  font-size: 30px;
}
h3,
.h3 {
  font-size: 24px;
}
h4,
.h4 {
  font-size: 18px;
}
h5,
.h5 {
  font-size: 14px;
}
h6,
.h6 {
  font-size: 12px;
}
p {
  margin: 0 0 10px;
}
.lead {
  margin-bottom: 20px;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.4;
}
@media (min-width: 768px) {
  .lead {
    font-size: 21px;
  }
}
small,
.small {
  font-size: 85%;
}
mark,
.mark {
  padding: .2em;
  background-color: #fcf8e3;
}
.text-left {
  text-align: left;
}
.text-right {
  text-align: right;
}
.text-center {
  text-align: center;
}
.text-justify {
  text-align: justify;
}
.text-nowrap {
  white-space: nowrap;
}
.text-lowercase {
  text-transform: lowercase;
}
.text-uppercase {
  text-transform: uppercase;
}
.text-capitalize {
  text-transform: capitalize;
}
.text-muted {
  color: #777;
}
.text-primary {
  color: #337ab7;
}
a.text-primary:hover {
  color: #286090;
}
.text-success {
  color: #3c763d;
}
a.text-success:hover {
  color: #2b542c;
}
.text-info {
  color: #31708f;
}
a.text-info:hover {
  color: #245269;
}
.text-warning {
  color: #8a6d3b;
}
a.text-warning:hover {
  color: #66512c;
}
.text-danger {
  color: #a94442;
}
a.text-danger:hover {
  color: #843534;
}
.bg-primary {
  color: #fff;
  background-color: #337ab7;
}
a.bg-primary:hover {
  background-color: #286090;
}
.bg-success {
  background-color: #dff0d8;
}
a.bg-success:hover {
  background-color: #c1e2b3;
}
.bg-info {
  background-color: #d9edf7;
}
a.bg-info:hover {
  background-color: #afd9ee;
}
.bg-warning {
  background-color: #fcf8e3;
}
a.bg-warning:hover {
  background-color: #f7ecb5;
}
.bg-danger {
  background-color: #f2dede;
}
a.bg-danger:hover {
  background-color: #e4b9b9;
}
.page-header {
  padding-bottom: 9px;
  margin: 40px 0 20px;
  border-bottom: 1px solid #eee;
}
ul,
ol {
  margin-top: 0;
  margin-bottom: 10px;
}
ul ul,
ol ul,
ul ol,
ol ol {
  margin-bottom: 0;
}
.list-unstyled {
  padding-left: 0;
  list-style: none;
}
.list-inline {
  padding-left: 0;
  margin-left: -5px;
  list-style: none;
}
.list-inline > li {
  display: inline-block;
  padding-right: 5px;
  padding-left: 5px;
}
dl {
  margin-top: 0;
  margin-bottom: 20px;
}
dt,
dd {
  line-height: 1.42857143;
}
dt {
  font-weight: bold;
}
dd {
  margin-left: 0;
}
@media (min-width: 768px) {
  .dl-horizontal dt {
    float: left;
    width: 160px;
    overflow: hidden;
    clear: left;
    text-align: right;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .dl-horizontal dd {
    margin-left: 180px;
  }
}
abbr[title],
abbr[data-original-title] {
  cursor: help;
  border-bottom: 1px dotted #777;
}
.initialism {
  font-size: 90%;
  text-transform: uppercase;
}
blockquote {
  padding: 10px 20px;
  margin: 0 0 20px;
  font-size: 17.5px;
  border-left: 5px solid #eee;
}
blockquote p:last-child,
blockquote ul:last-child,
blockquote ol:last-child {
  margin-bottom: 0;
}
blockquote footer,
blockquote small,
blockquote .small {
  display: block;
  font-size: 80%;
  line-height: 1.42857143;
  color: #777;
}
blockquote footer:before,
blockquote small:before,
blockquote .small:before {
  content: '\2014 \00A0';
}
.blockquote-reverse,
blockquote.pull-right {
  padding-right: 15px;
  padding-left: 0;
  text-align: right;
  border-right: 5px solid #eee;
  border-left: 0;
}
.blockquote-reverse footer:before,
blockquote.pull-right footer:before,
.blockquote-reverse small:before,
blockquote.pull-right small:before,
.blockquote-reverse .small:before,
blockquote.pull-right .small:before {
  content: '';
}
.blockquote-reverse footer:after,
blockquote.pull-right footer:after,
.blockquote-reverse small:after,
blockquote.pull-right small:after,
.blockquote-reverse .small:after,
blockquote.pull-right .small:after {
  content: '\00A0 \2014';
}
address {
  margin-bottom: 20px;
  font-style: normal;
  line-height: 1.42857143;
}
code,
kbd,
pre,
samp {
  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
}
code {
  padding: 2px 4px;
  font-size: 90%;
  color: #c7254e;
  background-color: #f9f2f4;
  border-radius: 4px;
}
kbd {
  padding: 2px 4px;
  font-size: 90%;
  color: #fff;
  background-color: #333;
  border-radius: 3px;
  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
}
kbd kbd {
  padding: 0;
  font-size: 100%;
  font-weight: bold;
  -webkit-box-shadow: none;
          box-shadow: none;
}
pre {
  display: block;
  padding: 9.5px;
  margin: 0 0 10px;
  font-size: 13px;
  line-height: 1.42857143;
  color: #333;
  word-break: break-all;
  word-wrap: break-word;
  background-color: #f5f5f5;
  border: 1px solid #ccc;
  border-radius: 4px;
}
pre code {
  padding: 0;
  font-size: inherit;
  color: inherit;
  white-space: pre-wrap;
  background-color: transparent;
  border-radius: 0;
}
.pre-scrollable {
  max-height: 340px;
  overflow-y: scroll;
}
.container {
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
}
@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}
@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}
@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}
.container-fluid {
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
}
.row {
  margin-right: -15px;
  margin-left: -15px;
}
.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
  position: relative;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}
.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
  float: left;
}
.col-xs-12 {
  width: 100%;
}
.col-xs-11 {
  width: 91.66666667%;
}
.col-xs-10 {
  width: 83.33333333%;
}
.col-xs-9 {
  width: 75%;
}
.col-xs-8 {
  width: 66.66666667%;
}
.col-xs-7 {
  width: 58.33333333%;
}
.col-xs-6 {
  width: 50%;
}
.col-xs-5 {
  width: 41.66666667%;
}
.col-xs-4 {
  width: 33.33333333%;
}
.col-xs-3 {
  width: 25%;
}
.col-xs-2 {
  width: 16.66666667%;
}
.col-xs-1 {
  width: 8.33333333%;
}
.col-xs-pull-12 {
  right: 100%;
}
.col-xs-pull-11 {
  right: 91.66666667%;
}
.col-xs-pull-10 {
  right: 83.33333333%;
}
.col-xs-pull-9 {
  right: 75%;
}
.col-xs-pull-8 {
  right: 66.66666667%;
}
.col-xs-pull-7 {
  right: 58.33333333%;
}
.col-xs-pull-6 {
  right: 50%;
}
.col-xs-pull-5 {
  right: 41.66666667%;
}
.col-xs-pull-4 {
  right: 33.33333333%;
}
.col-xs-pull-3 {
  right: 25%;
}
.col-xs-pull-2 {
  right: 16.66666667%;
}
.col-xs-pull-1 {
  right: 8.33333333%;
}
.col-xs-pull-0 {
  right: auto;
}
.col-xs-push-12 {
  left: 100%;
}
.col-xs-push-11 {
  left: 91.66666667%;
}
.col-xs-push-10 {
  left: 83.33333333%;
}
.col-xs-push-9 {
  left: 75%;
}
.col-xs-push-8 {
  left: 66.66666667%;
}
.col-xs-push-7 {
  left: 58.33333333%;
}
.col-xs-push-6 {
  left: 50%;
}
.col-xs-push-5 {
  left: 41.66666667%;
}
.col-xs-push-4 {
  left: 33.33333333%;
}
.col-xs-push-3 {
  left: 25%;
}
.col-xs-push-2 {
  left: 16.66666667%;
}
.col-xs-push-1 {
  left: 8.33333333%;
}
.col-xs-push-0 {
  left: auto;
}
.col-xs-offset-12 {
  margin-left: 100%;
}
.col-xs-offset-11 {
  margin-left: 91.66666667%;
}
.col-xs-offset-10 {
  margin-left: 83.33333333%;
}
.col-xs-offset-9 {
  margin-left: 75%;
}
.col-xs-offset-8 {
  margin-left: 66.66666667%;
}
.col-xs-offset-7 {
  margin-left: 58.33333333%;
}
.col-xs-offset-6 {
  margin-left: 50%;
}
.col-xs-offset-5 {
  margin-left: 41.66666667%;
}
.col-xs-offset-4 {
  margin-left: 33.33333333%;
}
.col-xs-offset-3 {
  margin-left: 25%;
}
.col-xs-offset-2 {
  margin-left: 16.66666667%;
}
.col-xs-offset-1 {
  margin-left: 8.33333333%;
}
.col-xs-offset-0 {
  margin-left: 0;
}
@media (min-width: 768px) {
  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
    float: left;
  }
  .col-sm-12 {
    width: 100%;
  }
  .col-sm-11 {
    width: 91.66666667%;
  }
  .col-sm-10 {
    width: 83.33333333%;
  }
  .col-sm-9 {
    width: 75%;
  }
  .col-sm-8 {
    width: 66.66666667%;
  }
  .col-sm-7 {
    width: 58.33333333%;
  }
  .col-sm-6 {
    width: 50%;
  }
  .col-sm-5 {
    width: 41.66666667%;
  }
  .col-sm-4 {
    width: 33.33333333%;
  }
  .col-sm-3 {
    width: 25%;
  }
  .col-sm-2 {
    width: 16.66666667%;
  }
  .col-sm-1 {
    width: 8.33333333%;
  }
  .col-sm-pull-12 {
    right: 100%;
  }
  .col-sm-pull-11 {
    right: 91.66666667%;
  }
  .col-sm-pull-10 {
    right: 83.33333333%;
  }
  .col-sm-pull-9 {
    right: 75%;
  }
  .col-sm-pull-8 {
    right: 66.66666667%;
  }
  .col-sm-pull-7 {
    right: 58.33333333%;
  }
  .col-sm-pull-6 {
    right: 50%;
  }
  .col-sm-pull-5 {
    right: 41.66666667%;
  }
  .col-sm-pull-4 {
    right: 33.33333333%;
  }
  .col-sm-pull-3 {
    right: 25%;
  }
  .col-sm-pull-2 {
    right: 16.66666667%;
  }
  .col-sm-pull-1 {
    right: 8.33333333%;
  }
  .col-sm-pull-0 {
    right: auto;
  }
  .col-sm-push-12 {
    left: 100%;
  }
  .col-sm-push-11 {
    left: 91.66666667%;
  }
  .col-sm-push-10 {
    left: 83.33333333%;
  }
  .col-sm-push-9 {
    left: 75%;
  }
  .col-sm-push-8 {
    left: 66.66666667%;
  }
  .col-sm-push-7 {
    left: 58.33333333%;
  }
  .col-sm-push-6 {
    left: 50%;
  }
  .col-sm-push-5 {
    left: 41.66666667%;
  }
  .col-sm-push-4 {
    left: 33.33333333%;
  }
  .col-sm-push-3 {
    left: 25%;
  }
  .col-sm-push-2 {
    left: 16.66666667%;
  }
  .col-sm-push-1 {
    left: 8.33333333%;
  }
  .col-sm-push-0 {
    left: auto;
  }
  .col-sm-offset-12 {
    margin-left: 100%;
  }
  .col-sm-offset-11 {
    margin-left: 91.66666667%;
  }
  .col-sm-offset-10 {
    margin-left: 83.33333333%;
  }
  .col-sm-offset-9 {
    margin-left: 75%;
  }
  .col-sm-offset-8 {
    margin-left: 66.66666667%;
  }
  .col-sm-offset-7 {
    margin-left: 58.33333333%;
  }
  .col-sm-offset-6 {
    margin-left: 50%;
  }
  .col-sm-offset-5 {
    margin-left: 41.66666667%;
  }
  .col-sm-offset-4 {
    margin-left: 33.33333333%;
  }
  .col-sm-offset-3 {
    margin-left: 25%;
  }
  .col-sm-offset-2 {
    margin-left: 16.66666667%;
  }
  .col-sm-offset-1 {
    margin-left: 8.33333333%;
  }
  .col-sm-offset-0 {
    margin-left: 0;
  }
}
@media (min-width: 992px) {
  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
    float: left;
  }
  .col-md-12 {
    width: 100%;
  }
  .col-md-11 {
    width: 91.66666667%;
  }
  .col-md-10 {
    width: 83.33333333%;
  }
  .col-md-9 {
    width: 75%;
  }
  .col-md-8 {
    width: 66.66666667%;
  }
  .col-md-7 {
    width: 58.33333333%;
  }
  .col-md-6 {
    width: 50%;
  }
  .col-md-5 {
    width: 41.66666667%;
  }
  .col-md-4 {
    width: 33.33333333%;
  }
  .col-md-3 {
    width: 25%;
  }
  .col-md-2 {
    width: 16.66666667%;
  }
  .col-md-1 {
    width: 8.33333333%;
  }
  .col-md-pull-12 {
    right: 100%;
  }
  .col-md-pull-11 {
    right: 91.66666667%;
  }
  .col-md-pull-10 {
    right: 83.33333333%;
  }
  .col-md-pull-9 {
    right: 75%;
  }
  .col-md-pull-8 {
    right: 66.66666667%;
  }
  .col-md-pull-7 {
    right: 58.33333333%;
  }
  .col-md-pull-6 {
    right: 50%;
  }
  .col-md-pull-5 {
    right: 41.66666667%;
  }
  .col-md-pull-4 {
    right: 33.33333333%;
  }
  .col-md-pull-3 {
    right: 25%;
  }
  .col-md-pull-2 {
    right: 16.66666667%;
  }
  .col-md-pull-1 {
    right: 8.33333333%;
  }
  .col-md-pull-0 {
    right: auto;
  }
  .col-md-push-12 {
    left: 100%;
  }
  .col-md-push-11 {
    left: 91.66666667%;
  }
  .col-md-push-10 {
    left: 83.33333333%;
  }
  .col-md-push-9 {
    left: 75%;
  }
  .col-md-push-8 {
    left: 66.66666667%;
  }
  .col-md-push-7 {
    left: 58.33333333%;
  }
  .col-md-push-6 {
    left: 50%;
  }
  .col-md-push-5 {
    left: 41.66666667%;
  }
  .col-md-push-4 {
    left: 33.33333333%;
  }
  .col-md-push-3 {
    left: 25%;
  }
  .col-md-push-2 {
    left: 16.66666667%;
  }
  .col-md-push-1 {
    left: 8.33333333%;
  }
  .col-md-push-0 {
    left: auto;
  }
  .col-md-offset-12 {
    margin-left: 100%;
  }
  .col-md-offset-11 {
    margin-left: 91.66666667%;
  }
  .col-md-offset-10 {
    margin-left: 83.33333333%;
  }
  .col-md-offset-9 {
    margin-left: 75%;
  }
  .col-md-offset-8 {
    margin-left: 66.66666667%;
  }
  .col-md-offset-7 {
    margin-left: 58.33333333%;
  }
  .col-md-offset-6 {
    margin-left: 50%;
  }
  .col-md-offset-5 {
    margin-left: 41.66666667%;
  }
  .col-md-offset-4 {
    margin-left: 33.33333333%;
  }
  .col-md-offset-3 {
    margin-left: 25%;
  }
  .col-md-offset-2 {
    margin-left: 16.66666667%;
  }
  .col-md-offset-1 {
    margin-left: 8.33333333%;
  }
  .col-md-offset-0 {
    margin-left: 0;
  }
}
@media (min-width: 1200px) {
  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
    float: left;
  }
  .col-lg-12 {
    width: 100%;
  }
  .col-lg-11 {
    width: 91.66666667%;
  }
  .col-lg-10 {
    width: 83.33333333%;
  }
  .col-lg-9 {
    width: 75%;
  }
  .col-lg-8 {
    width: 66.66666667%;
  }
  .col-lg-7 {
    width: 58.33333333%;
  }
  .col-lg-6 {
    width: 50%;
  }
  .col-lg-5 {
    width: 41.66666667%;
  }
  .col-lg-4 {
    width: 33.33333333%;
  }
  .col-lg-3 {
    width: 25%;
  }
  .col-lg-2 {
    width: 16.66666667%;
  }
  .col-lg-1 {
    width: 8.33333333%;
  }
  .col-lg-pull-12 {
    right: 100%;
  }
  .col-lg-pull-11 {
    right: 91.66666667%;
  }
  .col-lg-pull-10 {
    right: 83.33333333%;
  }
  .col-lg-pull-9 {
    right: 75%;
  }
  .col-lg-pull-8 {
    right: 66.66666667%;
  }
  .col-lg-pull-7 {
    right: 58.33333333%;
  }
  .col-lg-pull-6 {
    right: 50%;
  }
  .col-lg-pull-5 {
    right: 41.66666667%;
  }
  .col-lg-pull-4 {
    right: 33.33333333%;
  }
  .col-lg-pull-3 {
    right: 25%;
  }
  .col-lg-pull-2 {
    right: 16.66666667%;
  }
  .col-lg-pull-1 {
    right: 8.33333333%;
  }
  .col-lg-pull-0 {
    right: auto;
  }
  .col-lg-push-12 {
    left: 100%;
  }
  .col-lg-push-11 {
    left: 91.66666667%;
  }
  .col-lg-push-10 {
    left: 83.33333333%;
  }
  .col-lg-push-9 {
    left: 75%;
  }
  .col-lg-push-8 {
    left: 66.66666667%;
  }
  .col-lg-push-7 {
    left: 58.33333333%;
  }
  .col-lg-push-6 {
    left: 50%;
  }
  .col-lg-push-5 {
    left: 41.66666667%;
  }
  .col-lg-push-4 {
    left: 33.33333333%;
  }
  .col-lg-push-3 {
    left: 25%;
  }
  .col-lg-push-2 {
    left: 16.66666667%;
  }
  .col-lg-push-1 {
    left: 8.33333333%;
  }
  .col-lg-push-0 {
    left: auto;
  }
  .col-lg-offset-12 {
    margin-left: 100%;
  }
  .col-lg-offset-11 {
    margin-left: 91.66666667%;
  }
  .col-lg-offset-10 {
    margin-left: 83.33333333%;
  }
  .col-lg-offset-9 {
    margin-left: 75%;
  }
  .col-lg-offset-8 {
    margin-left: 66.66666667%;
  }
  .col-lg-offset-7 {
    margin-left: 58.33333333%;
  }
  .col-lg-offset-6 {
    margin-left: 50%;
  }
  .col-lg-offset-5 {
    margin-left: 41.66666667%;
  }
  .col-lg-offset-4 {
    margin-left: 33.33333333%;
  }
  .col-lg-offset-3 {
    margin-left: 25%;
  }
  .col-lg-offset-2 {
    margin-left: 16.66666667%;
  }
  .col-lg-offset-1 {
    margin-left: 8.33333333%;
  }
  .col-lg-offset-0 {
    margin-left: 0;
  }
}
table {
  background-color: transparent;
}
caption {
  padding-top: 8px;
  padding-bottom: 8px;
  color: #777;
  text-align: left;
}
th {
  text-align: left;
}
.table {
  width: 100%;
  max-width: 100%;
  margin-bottom: 20px;
}
.table > thead > tr > th,
.table > tbody > tr > th,
.table > tfoot > tr > th,
.table > thead > tr > td,
.table > tbody > tr > td,
.table > tfoot > tr > td {
  padding: 8px;
  line-height: 1.42857143;
  vertical-align: top;
  border-top: 1px solid #ddd;
}
.table > thead > tr > th {
  vertical-align: bottom;
  border-bottom: 2px solid #ddd;
}
.table > caption + thead > tr:first-child > th,
.table > colgroup + thead > tr:first-child > th,
.table > thead:first-child > tr:first-child > th,
.table > caption + thead > tr:first-child > td,
.table > colgroup + thead > tr:first-child > td,
.table > thead:first-child > tr:first-child > td {
  border-top: 0;
}
.table > tbody + tbody {
  border-top: 2px solid #ddd;
}
.table .table {
  background-color: #fff;
}
.table-condensed > thead > tr > th,
.table-condensed > tbody > tr > th,
.table-condensed > tfoot > tr > th,
.table-condensed > thead > tr > td,
.table-condensed > tbody > tr > td,
.table-condensed > tfoot > tr > td {
  padding: 5px;
}
.table-bordered {
  border: 1px solid #ddd;
}
.table-bordered > thead > tr > th,
.table-bordered > tbody > tr > th,
.table-bordered > tfoot > tr > th,
.table-bordered > thead > tr > td,
.table-bordered > tbody > tr > td,
.table-bordered > tfoot > tr > td {
  border: 1px solid #ddd;
}
.table-bordered > thead > tr > th,
.table-bordered > thead > tr > td {
  border-bottom-width: 2px;
}
.table-striped > tbody > tr:nth-of-type(odd) {
  background-color: #f9f9f9;
}
.table-hover > tbody > tr:hover {
  background-color: #f5f5f5;
}
table col[class*="col-"] {
  position: static;
  display: table-column;
  float: none;
}
table td[class*="col-"],
table th[class*="col-"] {
  position: static;
  display: table-cell;
  float: none;
}
.table > thead > tr > td.active,
.table > tbody > tr > td.active,
.table > tfoot > tr > td.active,
.table > thead > tr > th.active,
.table > tbody > tr > th.active,
.table > tfoot > tr > th.active,
.table > thead > tr.active > td,
.table > tbody > tr.active > td,
.table > tfoot > tr.active > td,
.table > thead > tr.active > th,
.table > tbody > tr.active > th,
.table > tfoot > tr.active > th {
  background-color: #f5f5f5;
}
.table-hover > tbody > tr > td.active:hover,
.table-hover > tbody > tr > th.active:hover,
.table-hover > tbody > tr.active:hover > td,
.table-hover > tbody > tr:hover > .active,
.table-hover > tbody > tr.active:hover > th {
  background-color: #e8e8e8;
}
.table > thead > tr > td.success,
.table > tbody > tr > td.success,
.table > tfoot > tr > td.success,
.table > thead > tr > th.success,
.table > tbody > tr > th.success,
.table > tfoot > tr > th.success,
.table > thead > tr.success > td,
.table > tbody > tr.success > td,
.table > tfoot > tr.success > td,
.table > thead > tr.success > th,
.table > tbody > tr.success > th,
.table > tfoot > tr.success > th {
  background-color: #dff0d8;
}
.table-hover > tbody > tr > td.success:hover,
.table-hover > tbody > tr > th.success:hover,
.table-hover > tbody > tr.success:hover > td,
.table-hover > tbody > tr:hover > .success,
.table-hover > tbody > tr.success:hover > th {
  background-color: #d0e9c6;
}
.table > thead > tr > td.info,
.table > tbody > tr > td.info,
.table > tfoot > tr > td.info,
.table > thead > tr > th.info,
.table > tbody > tr > th.info,
.table > tfoot > tr > th.info,
.table > thead > tr.info > td,
.table > tbody > tr.info > td,
.table > tfoot > tr.info > td,
.table > thead > tr.info > th,
.table > tbody > tr.info > th,
.table > tfoot > tr.info > th {
  background-color: #d9edf7;
}
.table-hover > tbody > tr > td.info:hover,
.table-hover > tbody > tr > th.info:hover,
.table-hover > tbody > tr.info:hover > td,
.table-hover > tbody > tr:hover > .info,
.table-hover > tbody > tr.info:hover > th {
  background-color: #c4e3f3;
}
.table > thead > tr > td.warning,
.table > tbody > tr > td.warning,
.table > tfoot > tr > td.warning,
.table > thead > tr > th.warning,
.table > tbody > tr > th.warning,
.table > tfoot > tr > th.warning,
.table > thead > tr.warning > td,
.table > tbody > tr.warning > td,
.table > tfoot > tr.warning > td,
.table > thead > tr.warning > th,
.table > tbody > tr.warning > th,
.table > tfoot > tr.warning > th {
  background-color: #fcf8e3;
}
.table-hover > tbody > tr > td.warning:hover,
.table-hover > tbody > tr > th.warning:hover,
.table-hover > tbody > tr.warning:hover > td,
.table-hover > tbody > tr:hover > .warning,
.table-hover > tbody > tr.warning:hover > th {
  background-color: #faf2cc;
}
.table > thead > tr > td.danger,
.table > tbody > tr > td.danger,
.table > tfoot > tr > td.danger,
.table > thead > tr > th.danger,
.table > tbody > tr > th.danger,
.table > tfoot > tr > th.danger,
.table > thead > tr.danger > td,
.table > tbody > tr.danger > td,
.table > tfoot > tr.danger > td,
.table > thead > tr.danger > th,
.table > tbody > tr.danger > th,
.table > tfoot > tr.danger > th {
  background-color: #f2dede;
}
.table-hover > tbody > tr > td.danger:hover,
.table-hover > tbody > tr > th.danger:hover,
.table-hover > tbody > tr.danger:hover > td,
.table-hover > tbody > tr:hover > .danger,
.table-hover > tbody > tr.danger:hover > th {
  background-color: #ebcccc;
}
.table-responsive {
  min-height: .01%;
  overflow-x: auto;
}
@media screen and (max-width: 767px) {
  .table-responsive {
    width: 100%;
    margin-bottom: 15px;
    overflow-y: hidden;
    -ms-overflow-style: -ms-autohiding-scrollbar;
    border: 1px solid #ddd;
  }
  .table-responsive > .table {
    margin-bottom: 0;
  }
  .table-responsive > .table > thead > tr > th,
  .table-responsive > .table > tbody > tr > th,
  .table-responsive > .table > tfoot > tr > th,
  .table-responsive > .table > thead > tr > td,
  .table-responsive > .table > tbody > tr > td,
  .table-responsive > .table > tfoot > tr > td {
    white-space: nowrap;
  }
  .table-responsive > .table-bordered {
    border: 0;
  }
  .table-responsive > .table-bordered > thead > tr > th:first-child,
  .table-responsive > .table-bordered > tbody > tr > th:first-child,
  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
  .table-responsive > .table-bordered > thead > tr > td:first-child,
  .table-responsive > .table-bordered > tbody > tr > td:first-child,
  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
    border-left: 0;
  }
  .table-responsive > .table-bordered > thead > tr > th:last-child,
  .table-responsive > .table-bordered > tbody > tr > th:last-child,
  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
  .table-responsive > .table-bordered > thead > tr > td:last-child,
  .table-responsive > .table-bordered > tbody > tr > td:last-child,
  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
    border-right: 0;
  }
  .table-responsive > .table-bordered > tbody > tr:last-child > th,
  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
  .table-responsive > .table-bordered > tbody > tr:last-child > td,
  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
    border-bottom: 0;
  }
}
fieldset {
  min-width: 0;
  padding: 0;
  margin: 0;
  border: 0;
}
legend {
  display: block;
  width: 100%;
  padding: 0;
  margin-bottom: 20px;
  font-size: 21px;
  line-height: inherit;
  color: #333;
  border: 0;
  border-bottom: 1px solid #e5e5e5;
}
label {
  display: inline-block;
  max-width: 100%;
  margin-bottom: 5px;
  font-weight: bold;
}
input[type="search"] {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}
input[type="radio"],
input[type="checkbox"] {
  margin: 4px 0 0;
  margin-top: 1px \9;
  line-height: normal;
}
input[type="file"] {
  display: block;
}
input[type="range"] {
  display: block;
  width: 100%;
}
select[multiple],
select[size] {
  height: auto;
}
input[type="file"]:focus,
input[type="radio"]:focus,
input[type="checkbox"]:focus {
  outline: thin dotted;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}
output {
  display: block;
  padding-top: 7px;
  font-size: 14px;
  line-height: 1.42857143;
  color: #555;
}
.form-control {
  display: block;
  width: 100%;
  height: 34px;
  padding: 6px 12px;
  font-size: 14px;
  line-height: 1.42857143;
  color: #555;
  background-color: #fff;
  background-image: none;
  border: 1px solid #ccc;
  border-radius: 4px;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.form-control:focus {
  border-color: #66afe9;
  outline: 0;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
}
.form-control::-moz-placeholder {
  color: #999;
  opacity: 1;
}
.form-control:-ms-input-placeholder {
  color: #999;
}
.form-control::-webkit-input-placeholder {
  color: #999;
}
.form-control[disabled],
.form-control[readonly],
fieldset[disabled] .form-control {
  background-color: #eee;
  opacity: 1;
}
.form-control[disabled],
fieldset[disabled] .form-control {
  cursor: not-allowed;
}
textarea.form-control {
  height: auto;
}
input[type="search"] {
  -webkit-appearance: none;
}
@media screen and (-webkit-min-device-pixel-ratio: 0) {
  input[type="date"],
  input[type="time"],
  input[type="datetime-local"],
  input[type="month"] {
    line-height: 34px;
  }
  input[type="date"].input-sm,
  input[type="time"].input-sm,
  input[type="datetime-local"].input-sm,
  input[type="month"].input-sm,
  .input-group-sm input[type="date"],
  .input-group-sm input[type="time"],
  .input-group-sm input[type="datetime-local"],
  .input-group-sm input[type="month"] {
    line-height: 30px;
  }
  input[type="date"].input-lg,
  input[type="time"].input-lg,
  input[type="datetime-local"].input-lg,
  input[type="month"].input-lg,
  .input-group-lg input[type="date"],
  .input-group-lg input[type="time"],
  .input-group-lg input[type="datetime-local"],
  .input-group-lg input[type="month"] {
    line-height: 46px;
  }
}
.form-group {
  margin-bottom: 15px;
}
.radio,
.checkbox {
  position: relative;
  display: block;
  margin-top: 10px;
  margin-bottom: 10px;
}
.radio label,
.checkbox label {
  min-height: 20px;
  padding-left: 20px;
  margin-bottom: 0;
  font-weight: normal;
  cursor: pointer;
}
.radio input[type="radio"],
.radio-inline input[type="radio"],
.checkbox input[type="checkbox"],
.checkbox-inline input[type="checkbox"] {
  position: absolute;
  margin-top: 4px \9;
  margin-left: -20px;
}
.radio + .radio,
.checkbox + .checkbox {
  margin-top: -5px;
}
.radio-inline,
.checkbox-inline {
  position: relative;
  display: inline-block;
  padding-left: 20px;
  margin-bottom: 0;
  font-weight: normal;
  vertical-align: middle;
  cursor: pointer;
}
.radio-inline + .radio-inline,
.checkbox-inline + .checkbox-inline {
  margin-top: 0;
  margin-left: 10px;
}
input[type="radio"][disabled],
input[type="checkbox"][disabled],
input[type="radio"].disabled,
input[type="checkbox"].disabled,
fieldset[disabled] input[type="radio"],
fieldset[disabled] input[type="checkbox"] {
  cursor: not-allowed;
}
.radio-inline.disabled,
.checkbox-inline.disabled,
fieldset[disabled] .radio-inline,
fieldset[disabled] .checkbox-inline {
  cursor: not-allowed;
}
.radio.disabled label,
.checkbox.disabled label,
fieldset[disabled] .radio label,
fieldset[disabled] .checkbox label {
  cursor: not-allowed;
}
.form-control-static {
  min-height: 34px;
  padding-top: 7px;
  padding-bottom: 7px;
  margin-bottom: 0;
}
.form-control-static.input-lg,
.form-control-static.input-sm {
  padding-right: 0;
  padding-left: 0;
}
.input-sm {
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}
select.input-sm {
  height: 30px;
  line-height: 30px;
}
textarea.input-sm,
select[multiple].input-sm {
  height: auto;
}
.form-group-sm .form-control {
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}
select.form-group-sm .form-control {
  height: 30px;
  line-height: 30px;
}
textarea.form-group-sm .form-control,
select[multiple].form-group-sm .form-control {
  height: auto;
}
.form-group-sm .form-control-static {
  height: 30px;
  min-height: 32px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
}
.input-lg {
  height: 46px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.3333333;
  border-radius: 6px;
}
select.input-lg {
  height: 46px;
  line-height: 46px;
}
textarea.input-lg,
select[multiple].input-lg {
  height: auto;
}
.form-group-lg .form-control {
  height: 46px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.3333333;
  border-radius: 6px;
}
select.form-group-lg .form-control {
  height: 46px;
  line-height: 46px;
}
textarea.form-group-lg .form-control,
select[multiple].form-group-lg .form-control {
  height: auto;
}
.form-group-lg .form-control-static {
  height: 46px;
  min-height: 38px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.3333333;
}
.has-feedback {
  position: relative;
}
.has-feedback .form-control {
  padding-right: 42.5px;
}
.form-control-feedback {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  display: block;
  width: 34px;
  height: 34px;
  line-height: 34px;
  text-align: center;
  pointer-events: none;
}
.input-lg + .form-control-feedback {
  width: 46px;
  height: 46px;
  line-height: 46px;
}
.input-sm + .form-control-feedback {
  width: 30px;
  height: 30px;
  line-height: 30px;
}
.has-success .help-block,
.has-success .control-label,
.has-success .radio,
.has-success .checkbox,
.has-success .radio-inline,
.has-success .checkbox-inline,
.has-success.radio label,
.has-success.checkbox label,
.has-success.radio-inline label,
.has-success.checkbox-inline label {
  color: #3c763d;
}
.has-success .form-control {
  border-color: #3c763d;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
}
.has-success .form-control:focus {
  border-color: #2b542c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
}
.has-success .input-group-addon {
  color: #3c763d;
  background-color: #dff0d8;
  border-color: #3c763d;
}
.has-success .form-control-feedback {
  color: #3c763d;
}
.has-warning .help-block,
.has-warning .control-label,
.has-warning .radio,
.has-warning .checkbox,
.has-warning .radio-inline,
.has-warning .checkbox-inline,
.has-warning.radio label,
.has-warning.checkbox label,
.has-warning.radio-inline label,
.has-warning.checkbox-inline label {
  color: #8a6d3b;
}
.has-warning .form-control {
  border-color: #8a6d3b;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
}
.has-warning .form-control:focus {
  border-color: #66512c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
}
.has-warning .input-group-addon {
  color: #8a6d3b;
  background-color: #fcf8e3;
  border-color: #8a6d3b;
}
.has-warning .form-control-feedback {
  color: #8a6d3b;
}
.has-error .help-block,
.has-error .control-label,
.has-error .radio,
.has-error .checkbox,
.has-error .radio-inline,
.has-error .checkbox-inline,
.has-error.radio label,
.has-error.checkbox label,
.has-error.radio-inline label,
.has-error.checkbox-inline label {
  color: #a94442;
}
.has-error .form-control {
  border-color: #a94442;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
}
.has-error .form-control:focus {
  border-color: #843534;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
}
.has-error .input-group-addon {
  color: #a94442;
  background-color: #f2dede;
  border-color: #a94442;
}
.has-error .form-control-feedback {
  color: #a94442;
}
.has-feedback label ~ .form-control-feedback {
  top: 25px;
}
.has-feedback label.sr-only ~ .form-control-feedback {
  top: 0;
}
.help-block {
  display: block;
  margin-top: 5px;
  margin-bottom: 10px;
  color: #737373;
}
@media (min-width: 768px) {
  .form-inline .form-group {
    display: inline-block;
    margin-bottom: 0;
    vertical-align: middle;
  }
  .form-inline .form-control {
    display: inline-block;
    width: auto;
    vertical-align: middle;
  }
  .form-inline .form-control-static {
    display: inline-block;
  }
  .form-inline .input-group {
    display: inline-table;
    vertical-align: middle;
  }
  .form-inline .input-group .input-group-addon,
  .form-inline .input-group .input-group-btn,
  .form-inline .input-group .form-control {
    width: auto;
  }
  .form-inline .input-group > .form-control {
    width: 100%;
  }
  .form-inline .control-label {
    margin-bottom: 0;
    vertical-align: middle;
  }
  .form-inline .radio,
  .form-inline .checkbox {
    display: inline-block;
    margin-top: 0;
    margin-bottom: 0;
    vertical-align: middle;
  }
  .form-inline .radio label,
  .form-inline .checkbox label {
    padding-left: 0;
  }
  .form-inline .radio input[type="radio"],
  .form-inline .checkbox input[type="checkbox"] {
    position: relative;
    margin-left: 0;
  }
  .form-inline .has-feedback .form-control-feedback {
    top: 0;
  }
}
.form-horizontal .radio,
.form-horizontal .checkbox,
.form-horizontal .radio-inline,
.form-horizontal .checkbox-inline {
  padding-top: 7px;
  margin-top: 0;
  margin-bottom: 0;
}
.form-horizontal .radio,
.form-horizontal .checkbox {
  min-height: 27px;
}
.form-horizontal .form-group {
  margin-right: -15px;
  margin-left: -15px;
}
@media (min-width: 768px) {
  .form-horizontal .control-label {
    padding-top: 7px;
    margin-bottom: 0;
    text-align: right;
  }
}
.form-horizontal .has-feedback .form-control-feedback {
  right: 15px;
}
@media (min-width: 768px) {
  .form-horizontal .form-group-lg .control-label {
    padding-top: 14.333333px;
  }
}
@media (min-width: 768px) {
  .form-horizontal .form-group-sm .control-label {
    padding-top: 6px;
  }
}
.btn {
  display: inline-block;
  padding: 6px 12px;
  margin-bottom: 0;
  font-size: 14px;
  font-weight: normal;
  line-height: 1.42857143;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  -ms-touch-action: manipulation;
      touch-action: manipulation;
  cursor: pointer;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  background-image: none;
  border: 1px solid transparent;
  border-radius: 4px;
}
.btn:focus,
.btn:active:focus,
.btn.active:focus,
.btn.focus,
.btn:active.focus,
.btn.active.focus {
  outline: thin dotted;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}
.btn:hover,
.btn:focus,
.btn.focus {
  color: #333;
  text-decoration: none;
}
.btn:active,
.btn.active {
  background-image: none;
  outline: 0;
  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn.disabled,
.btn[disabled],
fieldset[disabled] .btn {
  pointer-events: none;
  cursor: not-allowed;
  filter: alpha(opacity=65);
  -webkit-box-shadow: none;
          box-shadow: none;
  opacity: .65;
}
.btn-default {
  color: #333;
  background-color: #fff;
  border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus,
.btn-default.focus,
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
  color: #333;
  background-color: #e6e6e6;
  border-color: #adadad;
}
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
  background-image: none;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
  background-color: #fff;
  border-color: #ccc;
}
.btn-default .badge {
  color: #fff;
  background-color: #333;
}
.btn-primary {
  color: #fff;
  background-color: #337ab7;
  border-color: #2e6da4;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary.focus,
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
  color: #fff;
  background-color: #286090;
  border-color: #204d74;
}
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
  background-image: none;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
  background-color: #337ab7;
  border-color: #2e6da4;
}
.btn-primary .badge {
  color: #337ab7;
  background-color: #fff;
}
.btn-success {
  color: #fff;
  background-color: #5cb85c;
  border-color: #4cae4c;
}
.btn-success:hover,
.btn-success:focus,
.btn-success.focus,
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
  color: #fff;
  background-color: #449d44;
  border-color: #398439;
}
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
  background-image: none;
}
.btn-success.disabled,
.btn-success[disabled],
fieldset[disabled] .btn-success,
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled.focus,
.btn-success[disabled].focus,
fieldset[disabled] .btn-success.focus,
.btn-success.disabled:active,
.btn-success[disabled]:active,
fieldset[disabled] .btn-success:active,
.btn-success.disabled.active,
.btn-success[disabled].active,
fieldset[disabled] .btn-success.active {
  background-color: #5cb85c;
  border-color: #4cae4c;
}
.btn-success .badge {
  color: #5cb85c;
  background-color: #fff;
}
.btn-info {
  color: #fff;
  background-color: #5bc0de;
  border-color: #46b8da;
}
.btn-info:hover,
.btn-info:focus,
.btn-info.focus,
.btn-info:active,
.btn-info.active,
.open > .dropdown-toggle.btn-info {
  color: #fff;
  background-color: #31b0d5;
  border-color: #269abc;
}
.btn-info:active,
.btn-info.active,
.open > .dropdown-toggle.btn-info {
  background-image: none;
}
.btn-info.disabled,
.btn-info[disabled],
fieldset[disabled] .btn-info,
.btn-info.disabled:hover,
.btn-info[disabled]:hover,
fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
.btn-info.disabled.focus,
.btn-info[disabled].focus,
fieldset[disabled] .btn-info.focus,
.btn-info.disabled:active,
.btn-info[disabled]:active,
fieldset[disabled] .btn-info:active,
.btn-info.disabled.active,
.btn-info[disabled].active,
fieldset[disabled] .btn-info.active {
  background-color: #5bc0de;
  border-color: #46b8da;
}
.btn-info .badge {
  color: #5bc0de;
  background-color: #fff;
}
.btn-warning {
  color: #fff;
  background-color: #f0ad4e;
  border-color: #eea236;
}
.btn-warning:hover,
.btn-warning:focus,
.btn-warning.focus,
.btn-warning:active,
.btn-warning.active,
.open > .dropdown-toggle.btn-warning {
  color: #fff;
  background-color: #ec971f;
  border-color: #d58512;
}
.btn-warning:active,
.btn-warning.active,
.open > .dropdown-toggle.btn-warning {
  background-image: none;
}
.btn-warning.disabled,
.btn-warning[disabled],
fieldset[disabled] .btn-warning,
.btn-warning.disabled:hover,
.btn-warning[disabled]:hover,
fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
.btn-warning.disabled.focus,
.btn-warning[disabled].focus,
fieldset[disabled] .btn-warning.focus,
.btn-warning.disabled:active,
.btn-warning[disabled]:active,
fieldset[disabled] .btn-warning:active,
.btn-warning.disabled.active,
.btn-warning[disabled].active,
fieldset[disabled] .btn-warning.active {
  background-color: #f0ad4e;
  border-color: #eea236;
}
.btn-warning .badge {
  color: #f0ad4e;
  background-color: #fff;
}
.btn-danger {
  color: #fff;
  background-color: #d9534f;
  border-color: #d43f3a;
}
.btn-danger:hover,
.btn-danger:focus,
.btn-danger.focus,
.btn-danger:active,
.btn-danger.active,
.open > .dropdown-toggle.btn-danger {
  color: #fff;
  background-color: #c9302c;
  border-color: #ac2925;
}
.btn-danger:active,
.btn-danger.active,
.open > .dropdown-toggle.btn-danger {
  background-image: none;
}
.btn-danger.disabled,
.btn-danger[disabled],
fieldset[disabled] .btn-danger,
.btn-danger.disabled:hover,
.btn-danger[disabled]:hover,
fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
.btn-danger.disabled.focus,
.btn-danger[disabled].focus,
fieldset[disabled] .btn-danger.focus,
.btn-danger.disabled:active,
.btn-danger[disabled]:active,
fieldset[disabled] .btn-danger:active,
.btn-danger.disabled.active,
.btn-danger[disabled].active,
fieldset[disabled] .btn-danger.active {
  background-color: #d9534f;
  border-color: #d43f3a;
}
.btn-danger .badge {
  color: #d9534f;
  background-color: #fff;
}
.btn-link {
  font-weight: normal;
  color: #337ab7;
  border-radius: 0;
}
.btn-link,
.btn-link:active,
.btn-link.active,
.btn-link[disabled],
fieldset[disabled] .btn-link {
  background-color: transparent;
  -webkit-box-shadow: none;
          box-shadow: none;
}
.btn-link,
.btn-link:hover,
.btn-link:focus,
.btn-link:active {
  border-color: transparent;
}
.btn-link:hover,
.btn-link:focus {
  color: #23527c;
  text-decoration: underline;
  background-color: transparent;
}
.btn-link[disabled]:hover,
fieldset[disabled] .btn-link:hover,
.btn-link[disabled]:focus,
fieldset[disabled] .btn-link:focus {
  color: #777;
  text-decoration: none;
}
.btn-lg,
.btn-group-lg > .btn {
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.3333333;
  border-radius: 6px;
}
.btn-sm,
.btn-group-sm > .btn {
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}
.btn-xs,
.btn-group-xs > .btn {
  padding: 1px 5px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}
.btn-block {
  display: block;
  width: 100%;
}
.btn-block + .btn-block {
  margin-top: 5px;
}
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
  width: 100%;
}
.fade {
  opacity: 0;
  -webkit-transition: opacity .15s linear;
       -o-transition: opacity .15s linear;
          transition: opacity .15s linear;
}
.fade.in {
  opacity: 1;
}
.collapse {
  display: none;
}
.collapse.in {
  display: block;
}
tr.collapse.in {
  display: table-row;
}
tbody.collapse.in {
  display: table-row-group;
}
.collapsing {
  position: relative;
  height: 0;
  overflow: hidden;
  -webkit-transition-timing-function: ease;
       -o-transition-timing-function: ease;
          transition-timing-function: ease;
  -webkit-transition-duration: .35s;
       -o-transition-duration: .35s;
          transition-duration: .35s;
  -webkit-transition-property: height, visibility;
       -o-transition-property: height, visibility;
          transition-property: height, visibility;
}
.caret {
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: 2px;
  vertical-align: middle;
  border-top: 4px dashed;
  border-right: 4px solid transparent;
  border-left: 4px solid transparent;
}
.dropup,
.dropdown {
  position: relative;
}
.dropdown-toggle:focus {
  outline: 0;
}
.dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  display: none;
  float: left;
  min-width: 160px;
  padding: 5px 0;
  margin: 2px 0 0;
  font-size: 14px;
  text-align: left;
  list-style: none;
  background-color: #fff;
  -webkit-background-clip: padding-box;
          background-clip: padding-box;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, .15);
  border-radius: 4px;
  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
}
.dropdown-menu.pull-right {
  right: 0;
  left: auto;
}
.dropdown-menu .divider {
  height: 1px;
  margin: 9px 0;
  overflow: hidden;
  background-color: #e5e5e5;
}
.dropdown-menu > li > a {
  display: block;
  padding: 3px 20px;
  clear: both;
  font-weight: normal;
  line-height: 1.42857143;
  color: #333;
  white-space: nowrap;
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
  color: #262626;
  text-decoration: none;
  background-color: #f5f5f5;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
  color: #fff;
  text-decoration: none;
  background-color: #337ab7;
  outline: 0;
}
.dropdown-menu > .disabled > a,
.dropdown-menu > .disabled > a:hover,
.dropdown-menu > .disabled > a:focus {
  color: #777;
}
.dropdown-menu > .disabled > a:hover,
.dropdown-menu > .disabled > a:focus {
  text-decoration: none;
  cursor: not-allowed;
  background-color: transparent;
  background-image: none;
  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
.open > .dropdown-menu {
  display: block;
}
.open > a {
  outline: 0;
}
.dropdown-menu-right {
  right: 0;
  left: auto;
}
.dropdown-menu-left {
  right: auto;
  left: 0;
}
.dropdown-header {
  display: block;
  padding: 3px 20px;
  font-size: 12px;
  line-height: 1.42857143;
  color: #777;
  white-space: nowrap;
}
.dropdown-backdrop {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 990;
}
.pull-right > .dropdown-menu {
  right: 0;
  left: auto;
}
.dropup .caret,
.navbar-fixed-bottom .dropdown .caret {
  content: "";
  border-top: 0;
  border-bottom: 4px solid;
}
.dropup .dropdown-menu,
.navbar-fixed-bottom .dropdown .dropdown-menu {
  top: auto;
  bottom: 100%;
  margin-bottom: 2px;
}
@media (min-width: 768px) {
  .navbar-right .dropdown-menu {
    right: 0;
    left: auto;
  }
  .navbar-right .dropdown-menu-left {
    right: auto;
    left: 0;
  }
}
.btn-group,
.btn-group-vertical {
  position: relative;
  display: inline-block;
  vertical-align: middle;
}
.btn-group > .btn,
.btn-group-vertical > .btn {
  position: relative;
  float: left;
}
.btn-group > .btn:hover,
.btn-group-vertical > .btn:hover,
.btn-group > .btn:focus,
.btn-group-vertical > .btn:focus,
.btn-group > .btn:active,
.btn-group-vertical > .btn:active,
.btn-group > .btn.active,
.btn-group-vertical > .btn.active {
  z-index: 2;
}
.btn-group .btn + .btn,
.btn-group .btn + .btn-group,
.btn-group .btn-group + .btn,
.btn-group .btn-group + .btn-group {
  margin-left: -1px;
}
.btn-toolbar {
  margin-left: -5px;
}
.btn-toolbar .btn-group,
.btn-toolbar .input-group {
  float: left;
}
.btn-toolbar > .btn,
.btn-toolbar > .btn-group,
.btn-toolbar > .input-group {
  margin-left: 5px;
}
.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
  border-radius: 0;
}
.btn-group > .btn:first-child {
  margin-left: 0;
}
.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.btn-group > .btn:last-child:not(:first-child),
.btn-group > .dropdown-toggle:not(:first-child) {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.btn-group > .btn-group {
  float: left;
}
.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
  border-radius: 0;
}
.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.btn-group .dropdown-toggle:active,
.btn-group.open .dropdown-toggle {
  outline: 0;
}
.btn-group > .btn + .dropdown-toggle {
  padding-right: 8px;
  padding-left: 8px;
}
.btn-group > .btn-lg + .dropdown-toggle {
  padding-right: 12px;
  padding-left: 12px;
}
.btn-group.open .dropdown-toggle {
  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn-group.open .dropdown-toggle.btn-link {
  -webkit-box-shadow: none;
          box-shadow: none;
}
.btn .caret {
  margin-left: 0;
}
.btn-lg .caret {
  border-width: 5px 5px 0;
  border-bottom-width: 0;
}
.dropup .btn-lg .caret {
  border-width: 0 5px 5px;
}
.btn-group-vertical > .btn,
.btn-group-vertical > .btn-group,
.btn-group-vertical > .btn-group > .btn {
  display: block;
  float: none;
  width: 100%;
  max-width: 100%;
}
.btn-group-vertical > .btn-group > .btn {
  float: none;
}
.btn-group-vertical > .btn + .btn,
.btn-group-vertical > .btn + .btn-group,
.btn-group-vertical > .btn-group + .btn,
.btn-group-vertical > .btn-group + .btn-group {
  margin-top: -1px;
  margin-left: 0;
}
.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
  border-radius: 0;
}
.btn-group-vertical > .btn:first-child:not(:last-child) {
  border-top-right-radius: 4px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.btn-group-vertical > .btn:last-child:not(:first-child) {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-bottom-left-radius: 4px;
}
.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
  border-radius: 0;
}
.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
.btn-group-justified {
  display: table;
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
}
.btn-group-justified > .btn,
.btn-group-justified > .btn-group {
  display: table-cell;
  float: none;
  width: 1%;
}
.btn-group-justified > .btn-group .btn {
  width: 100%;
}
.btn-group-justified > .btn-group .dropdown-menu {
  left: auto;
}
[data-toggle="buttons"] > .btn input[type="radio"],
[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
[data-toggle="buttons"] > .btn input[type="checkbox"],
[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
  position: absolute;
  clip: rect(0, 0, 0, 0);
  pointer-events: none;
}
.input-group {
  position: relative;
  display: table;
  border-collapse: separate;
}
.input-group[class*="col-"] {
  float: none;
  padding-right: 0;
  padding-left: 0;
}
.input-group .form-control {
  position: relative;
  z-index: 2;
  float: left;
  width: 100%;
  margin-bottom: 0;
}
.input-group-lg > .form-control,
.input-group-lg > .input-group-addon,
.input-group-lg > .input-group-btn > .btn {
  height: 46px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.3333333;
  border-radius: 6px;
}
select.input-group-lg > .form-control,
select.input-group-lg > .input-group-addon,
select.input-group-lg > .input-group-btn > .btn {
  height: 46px;
  line-height: 46px;
}
textarea.input-group-lg > .form-control,
textarea.input-group-lg > .input-group-addon,
textarea.input-group-lg > .input-group-btn > .btn,
select[multiple].input-group-lg > .form-control,
select[multiple].input-group-lg > .input-group-addon,
select[multiple].input-group-lg > .input-group-btn > .btn {
  height: auto;
}
.input-group-sm > .form-control,
.input-group-sm > .input-group-addon,
.input-group-sm > .input-group-btn > .btn {
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 3px;
}
select.input-group-sm > .form-control,
select.input-group-sm > .input-group-addon,
select.input-group-sm > .input-group-btn > .btn {
  height: 30px;
  line-height: 30px;
}
textarea.input-group-sm > .form-control,
textarea.input-group-sm > .input-group-addon,
textarea.input-group-sm > .input-group-btn > .btn,
select[multiple].input-group-sm > .form-control,
select[multiple].input-group-sm > .input-group-addon,
select[multiple].input-group-sm > .input-group-btn > .btn {
  height: auto;
}
.input-group-addon,
.input-group-btn,
.input-group .form-control {
  display: table-cell;
}
.input-group-addon:not(:first-child):not(:last-child),
.input-group-btn:not(:first-child):not(:last-child),
.input-group .form-control:not(:first-child):not(:last-child) {
  border-radius: 0;
}
.input-group-addon,
.input-group-btn {
  width: 1%;
  white-space: nowrap;
  vertical-align: middle;
}
.input-group-addon {
  padding: 6px 12px;
  font-size: 14px;
  font-weight: normal;
  line-height: 1;
  color: #555;
  text-align: center;
  background-color: #eee;
  border: 1px solid #ccc;
  border-radius: 4px;
}
.input-group-addon.input-sm {
  padding: 5px 10px;
  font-size: 12px;
  border-radius: 3px;
}
.input-group-addon.input-lg {
  padding: 10px 16px;
  font-size: 18px;
  border-radius: 6px;
}
.input-group-addon input[type="radio"],
.input-group-addon input[type="checkbox"] {
  margin-top: 0;
}
.input-group .form-control:first-child,
.input-group-addon:first-child,
.input-group-btn:first-child > .btn,
.input-group-btn:first-child > .btn-group > .btn,
.input-group-btn:first-child > .dropdown-toggle,
.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.input-group-addon:first-child {
  border-right: 0;
}
.input-group .form-control:last-child,
.input-group-addon:last-child,
.input-group-btn:last-child > .btn,
.input-group-btn:last-child > .btn-group > .btn,
.input-group-btn:last-child > .dropdown-toggle,
.input-group-btn:first-child > .btn:not(:first-child),
.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.input-group-addon:last-child {
  border-left: 0;
}
.input-group-btn {
  position: relative;
  font-size: 0;
  white-space: nowrap;
}
.input-group-btn > .btn {
  position: relative;
}
.input-group-btn > .btn + .btn {
  margin-left: -1px;
}
.input-group-btn > .btn:hover,
.input-group-btn > .btn:focus,
.input-group-btn > .btn:active {
  z-index: 2;
}
.input-group-btn:first-child > .btn,
.input-group-btn:first-child > .btn-group {
  margin-right: -1px;
}
.input-group-btn:last-child > .btn,
.input-group-btn:last-child > .btn-group {
  margin-left: -1px;
}
.nav {
  padding-left: 0;
  margin-bottom: 0;
  list-style: none;
}
.nav > li {
  position: relative;
  display: block;
}
.nav > li > a {
  position: relative;
  display: block;
  padding: 10px 15px;
}
.nav > li > a:hover,
.nav > li > a:focus {
  text-decoration: none;
  background-color: #eee;
}
.nav > li.disabled > a {
  color: #777;
}
.nav > li.disabled > a:hover,
.nav > li.disabled > a:focus {
  color: #777;
  text-decoration: none;
  cursor: not-allowed;
  background-color: transparent;
}
.nav .open > a,
.nav .open > a:hover,
.nav .open > a:focus {
  background-color: #eee;
  border-color: #337ab7;
}
.nav .nav-divider {
  height: 1px;
  margin: 9px 0;
  overflow: hidden;
  background-color: #e5e5e5;
}
.nav > li > a > img {
  max-width: none;
}
.nav-tabs {
  border-bottom: 1px solid #ddd;
}
.nav-tabs > li {
  float: left;
  margin-bottom: -1px;
}
.nav-tabs > li > a {
  margin-right: 2px;
  line-height: 1.42857143;
  border: 1px solid transparent;
  border-radius: 4px 4px 0 0;
}
.nav-tabs > li > a:hover {
  border-color: #eee #eee #ddd;
}
.nav-tabs > li.active > a,
.nav-tabs > li.active > a:hover,
.nav-tabs > li.active > a:focus {
  color: #555;
  cursor: default;
  background-color: #fff;
  border: 1px solid #ddd;
  border-bottom-color: transparent;
}
.nav-tabs.nav-justified {
  width: 100%;
  border-bottom: 0;
}
.nav-tabs.nav-justified > li {
  float: none;
}
.nav-tabs.nav-justified > li > a {
  margin-bottom: 5px;
  text-align: center;
}
.nav-tabs.nav-justified > .dropdown .dropdown-menu {
  top: auto;
  left: auto;
}
@media (min-width: 768px) {
  .nav-tabs.nav-justified > li {
    display: table-cell;
    width: 1%;
  }
  .nav-tabs.nav-justified > li > a {
    margin-bottom: 0;
  }
}
.nav-tabs.nav-justified > li > a {
  margin-right: 0;
  border-radius: 4px;
}
.nav-tabs.nav-justified > .active > a,
.nav-tabs.nav-justified > .active > a:hover,
.nav-tabs.nav-justified > .active > a:focus {
  border: 1px solid #ddd;
}
@media (min-width: 768px) {
  .nav-tabs.nav-justified > li > a {
    border-bottom: 1px solid #ddd;
    border-radius: 4px 4px 0 0;
  }
  .nav-tabs.nav-justified > .active > a,
  .nav-tabs.nav-justified > .active > a:hover,
  .nav-tabs.nav-justified > .active > a:focus {
    border-bottom-color: #fff;
  }
}
.nav-pills > li {
  float: left;
}
.nav-pills > li > a {
  border-radius: 4px;
}
.nav-pills > li + li {
  margin-left: 2px;
}
.nav-pills > li.active > a,
.nav-pills > li.active > a:hover,
.nav-pills > li.active > a:focus {
  color: #fff;
  background-color: #337ab7;
}
.nav-stacked > li {
  float: none;
}
.nav-stacked > li + li {
  margin-top: 2px;
  margin-left: 0;
}
.nav-justified {
  width: 100%;
}
.nav-justified > li {
  float: none;
}
.nav-justified > li > a {
  margin-bottom: 5px;
  text-align: center;
}
.nav-justified > .dropdown .dropdown-menu {
  top: auto;
  left: auto;
}
@media (min-width: 768px) {
  .nav-justified > li {
    display: table-cell;
    width: 1%;
  }
  .nav-justified > li > a {
    margin-bottom: 0;
  }
}
.nav-tabs-justified {
  border-bottom: 0;
}
.nav-tabs-justified > li > a {
  margin-right: 0;
  border-radius: 4px;
}
.nav-tabs-justified > .active > a,
.nav-tabs-justified > .active > a:hover,
.nav-tabs-justified > .active > a:focus {
  border: 1px solid #ddd;
}
@media (min-width: 768px) {
  .nav-tabs-justified > li > a {
    border-bottom: 1px solid #ddd;
    border-radius: 4px 4px 0 0;
  }
  .nav-tabs-justified > .active > a,
  .nav-tabs-justified > .active > a:hover,
  .nav-tabs-justified > .active > a:focus {
    border-bottom-color: #fff;
  }
}
.tab-content > .tab-pane {
  display: none;
}
.tab-content > .active {
  display: block;
}
.nav-tabs .dropdown-menu {
  margin-top: -1px;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
.navbar {
  position: relative;
  min-height: 50px;
  margin-bottom: 20px;
  border: 1px solid transparent;
}
@media (min-width: 768px) {
  .navbar {
    border-radius: 4px;
  }
}
@media (min-width: 768px) {
  .navbar-header {
    float: left;
  }
}
.navbar-collapse {
  padding-right: 15px;
  padding-left: 15px;
  overflow-x: visible;
  -webkit-overflow-scrolling: touch;
  border-top: 1px solid transparent;
  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
}
.navbar-collapse.in {
  overflow-y: auto;
}
@media (min-width: 768px) {
  .navbar-collapse {
    width: auto;
    border-top: 0;
    -webkit-box-shadow: none;
            box-shadow: none;
  }
  .navbar-collapse.collapse {
    display: block !important;
    height: auto !important;
    padding-bottom: 0;
    overflow: visible !important;
  }
  .navbar-collapse.in {
    overflow-y: visible;
  }
  .navbar-fixed-top .navbar-collapse,
  .navbar-static-top .navbar-collapse,
  .navbar-fixed-bottom .navbar-collapse {
    padding-right: 0;
    padding-left: 0;
  }
}
.navbar-fixed-top .navbar-collapse,
.navbar-fixed-bottom .navbar-collapse {
  max-height: 340px;
}
@media (max-device-width: 480px) and (orientation: landscape) {
  .navbar-fixed-top .navbar-collapse,
  .navbar-fixed-bottom .navbar-collapse {
    max-height: 200px;
  }
}
.container > .navbar-header,
.container-fluid > .navbar-header,
.container > .navbar-collapse,
.container-fluid > .navbar-collapse {
  margin-right: -15px;
  margin-left: -15px;
}
@media (min-width: 768px) {
  .container > .navbar-header,
  .container-fluid > .navbar-header,
  .container > .navbar-collapse,
  .container-fluid > .navbar-collapse {
    margin-right: 0;
    margin-left: 0;
  }
}
.navbar-static-top {
  z-index: 1000;
  border-width: 0 0 1px;
}
@media (min-width: 768px) {
  .navbar-static-top {
    border-radius: 0;
  }
}
.navbar-fixed-top,
.navbar-fixed-bottom {
  position: fixed;
  right: 0;
  left: 0;
  z-index: 1030;
}
@media (min-width: 768px) {
  .navbar-fixed-top,
  .navbar-fixed-bottom {
    border-radius: 0;
  }
}
.navbar-fixed-top {
  top: 0;
  border-width: 0 0 1px;
}
.navbar-fixed-bottom {
  bottom: 0;
  margin-bottom: 0;
  border-width: 1px 0 0;
}
.navbar-brand {
  float: left;
  height: 50px;
  padding: 15px 15px;
  font-size: 18px;
  line-height: 20px;
}
.navbar-brand:hover,
.navbar-brand:focus {
  text-decoration: none;
}
.navbar-brand > img {
  display: block;
}
@media (min-width: 768px) {
  .navbar > .container .navbar-brand,
  .navbar > .container-fluid .navbar-brand {
    margin-left: -15px;
  }
}
.navbar-toggle {
  position: relative;
  float: right;
  padding: 9px 10px;
  margin-top: 8px;
  margin-right: 15px;
  margin-bottom: 8px;
  background-color: transparent;
  background-image: none;
  border: 1px solid transparent;
  border-radius: 4px;
}
.navbar-toggle:focus {
  outline: 0;
}
.navbar-toggle .icon-bar {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 1px;
}
.navbar-toggle .icon-bar + .icon-bar {
  margin-top: 4px;
}
@media (min-width: 768px) {
  .navbar-toggle {
    display: none;
  }
}
.navbar-nav {
  margin: 7.5px -15px;
}
.navbar-nav > li > a {
  padding-top: 10px;
  padding-bottom: 10px;
  line-height: 20px;
}
@media (max-width: 767px) {
  .navbar-nav .open .dropdown-menu {
    position: static;
    float: none;
    width: auto;
    margin-top: 0;
    background-color: transparent;
    border: 0;
    -webkit-box-shadow: none;
            box-shadow: none;
  }
  .navbar-nav .open .dropdown-menu > li > a,
  .navbar-nav .open .dropdown-menu .dropdown-header {
    padding: 5px 15px 5px 25px;
  }
  .navbar-nav .open .dropdown-menu > li > a {
    line-height: 20px;
  }
  .navbar-nav .open .dropdown-menu > li > a:hover,
  .navbar-nav .open .dropdown-menu > li > a:focus {
    background-image: none;
  }
}
@media (min-width: 768px) {
  .navbar-nav {
    float: left;
    margin: 0;
  }
  .navbar-nav > li {
    float: left;
  }
  .navbar-nav > li > a {
    padding-top: 15px;
    padding-bottom: 15px;
  }
}
.navbar-form {
  padding: 10px 15px;
  margin-top: 8px;
  margin-right: -15px;
  margin-bottom: 8px;
  margin-left: -15px;
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
}
@media (min-width: 768px) {
  .navbar-form .form-group {
    display: inline-block;
    margin-bottom: 0;
    vertical-align: middle;
  }
  .navbar-form .form-control {
    display: inline-block;
    width: auto;
    vertical-align: middle;
  }
  .navbar-form .form-control-static {
    display: inline-block;
  }
  .navbar-form .input-group {
    display: inline-table;
    vertical-align: middle;
  }
  .navbar-form .input-group .input-group-addon,
  .navbar-form .input-group .input-group-btn,
  .navbar-form .input-group .form-control {
    width: auto;
  }
  .navbar-form .input-group > .form-control {
    width: 100%;
  }
  .navbar-form .control-label {
    margin-bottom: 0;
    vertical-align: middle;
  }
  .navbar-form .radio,
  .navbar-form .checkbox {
    display: inline-block;
    margin-top: 0;
    margin-bottom: 0;
    vertical-align: middle;
  }
  .navbar-form .radio label,
  .navbar-form .checkbox label {
    padding-left: 0;
  }
  .navbar-form .radio input[type="radio"],
  .navbar-form .checkbox input[type="checkbox"] {
    position: relative;
    margin-left: 0;
  }
  .navbar-form .has-feedback .form-control-feedback {
    top: 0;
  }
}
@media (max-width: 767px) {
  .navbar-form .form-group {
    margin-bottom: 5px;
  }
  .navbar-form .form-group:last-child {
    margin-bottom: 0;
  }
}
@media (min-width: 768px) {
  .navbar-form {
    width: auto;
    padding-top: 0;
    padding-bottom: 0;
    margin-right: 0;
    margin-left: 0;
    border: 0;
    -webkit-box-shadow: none;
            box-shadow: none;
  }
}
.navbar-nav > li > .dropdown-menu {
  margin-top: 0;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}
.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
  margin-bottom: 0;
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.navbar-btn {
  margin-top: 8px;
  margin-bottom: 8px;
}
.navbar-btn.btn-sm {
  margin-top: 10px;
  margin-bottom: 10px;
}
.navbar-btn.btn-xs {
  margin-top: 14px;
  margin-bottom: 14px;
}
.navbar-text {
  margin-top: 15px;
  margin-bottom: 15px;
}
@media (min-width: 768px) {
  .navbar-text {
    float: left;
    margin-right: 15px;
    margin-left: 15px;
  }
}
@media (min-width: 768px) {
  .navbar-left {
    float: left !important;
  }
  .navbar-right {
    float: right !important;
    margin-right: -15px;
  }
  .navbar-right ~ .navbar-right {
    margin-right: 0;
  }
}
.navbar-default {
  background-color: #f8f8f8;
  border-color: #e7e7e7;
}
.navbar-default .navbar-brand {
  color: #777;
}
.navbar-default .navbar-brand:hover,
.navbar-default .navbar-brand:focus {
  color: #5e5e5e;
  background-color: transparent;
}
.navbar-default .navbar-text {
  color: #777;
}
.navbar-default .navbar-nav > li > a {
  color: #777;
}
.navbar-default .navbar-nav > li > a:hover,
.navbar-default .navbar-nav > li > a:focus {
  color: #333;
  background-color: transparent;
}
.navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:hover,
.navbar-default .navbar-nav > .active > a:focus {
  color: #555;
  background-color: #e7e7e7;
}
.navbar-default .navbar-nav > .disabled > a,
.navbar-default .navbar-nav > .disabled > a:hover,
.navbar-default .navbar-nav > .disabled > a:focus {
  color: #ccc;
  background-color: transparent;
}
.navbar-default .navbar-toggle {
  border-color: #ddd;
}
.navbar-default .navbar-toggle:hover,
.navbar-default .navbar-toggle:focus {
  background-color: #ddd;
}
.navbar-default .navbar-toggle .icon-bar {
  background-color: #888;
}
.navbar-default .navbar-collapse,
.navbar-default .navbar-form {
  border-color: #e7e7e7;
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .open > a:hover,
.navbar-default .navbar-nav > .open > a:focus {
  color: #555;
  background-color: #e7e7e7;
}
@media (max-width: 767px) {
  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
    color: #777;
  }
  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
    color: #333;
    background-color: transparent;
  }
  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
    color: #555;
    background-color: #e7e7e7;
  }
  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
    color: #ccc;
    background-color: transparent;
  }
}
.navbar-default .navbar-link {
  color: #777;
}
.navbar-default .navbar-link:hover {
  color: #333;
}
.navbar-default .btn-link {
  color: #777;
}
.navbar-default .btn-link:hover,
.navbar-default .btn-link:focus {
  color: #333;
}
.navbar-default .btn-link[disabled]:hover,
fieldset[disabled] .navbar-default .btn-link:hover,
.navbar-default .btn-link[disabled]:focus,
fieldset[disabled] .navbar-default .btn-link:focus {
  color: #ccc;
}
.navbar-inverse {
  background-color: #222;
  border-color: #080808;
}
.navbar-inverse .navbar-brand {
  color: #9d9d9d;
}
.navbar-inverse .navbar-brand:hover,
.navbar-inverse .navbar-brand:focus {
  color: #fff;
  background-color: transparent;
}
.navbar-inverse .navbar-text {
  color: #9d9d9d;
}
.navbar-inverse .navbar-nav > li > a {
  color: #9d9d9d;
}
.navbar-inverse .navbar-nav > li > a:hover,
.navbar-inverse .navbar-nav > li > a:focus {
  color: #fff;
  background-color: transparent;
}
.navbar-inverse .navbar-nav > .active > a,
.navbar-inverse .navbar-nav > .active > a:hover,
.navbar-inverse .navbar-nav > .active > a:focus {
  color: #fff;
  background-color: #080808;
}
.navbar-inverse .navbar-nav > .disabled > a,
.navbar-inverse .navbar-nav > .disabled > a:hover,
.navbar-inverse .navbar-nav > .disabled > a:focus {
  color: #444;
  background-color: transparent;
}
.navbar-inverse .navbar-toggle {
  border-color: #333;
}
.navbar-inverse .navbar-toggle:hover,
.navbar-inverse .navbar-toggle:focus {
  background-color: #333;
}
.navbar-inverse .navbar-toggle .icon-bar {
  background-color: #fff;
}
.navbar-inverse .navbar-collapse,
.navbar-inverse .navbar-form {
  border-color: #101010;
}
.navbar-inverse .navbar-nav > .open > a,
.navbar-inverse .navbar-nav > .open > a:hover,
.navbar-inverse .navbar-nav > .open > a:focus {
  color: #fff;
  background-color: #080808;
}
@media (max-width: 767px) {
  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
    border-color: #080808;
  }
  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
    background-color: #080808;
  }
  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
    color: #9d9d9d;
  }
  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
    color: #fff;
    background-color: transparent;
  }
  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
    color: #fff;
    background-color: #080808;
  }
  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
    color: #444;
    background-color: transparent;
  }
}
.navbar-inverse .navbar-link {
  color: #9d9d9d;
}
.navbar-inverse .navbar-link:hover {
  color: #fff;
}
.navbar-inverse .btn-link {
  color: #9d9d9d;
}
.navbar-inverse .btn-link:hover,
.navbar-inverse .btn-link:focus {
  color: #fff;
}
.navbar-inverse .btn-link[disabled]:hover,
fieldset[disabled] .navbar-inverse .btn-link:hover,
.navbar-inverse .btn-link[disabled]:focus,
fieldset[disabled] .navbar-inverse .btn-link:focus {
  color: #444;
}
.breadcrumb {
  padding: 8px 15px;
  margin-bottom: 20px;
  list-style: none;
  background-color: #f5f5f5;
  border-radius: 4px;
}
.breadcrumb > li {
  display: inline-block;
}
.breadcrumb > li + li:before {
  padding: 0 5px;
  color: #ccc;
  content: "/\00a0";
}
.breadcrumb > .active {
  color: #777;
}
.pagination {
  display: inline-block;
  padding-left: 0;
  margin: 20px 0;
  border-radius: 4px;
}
.pagination > li {
  display: inline;
}
.pagination > li > a,
.pagination > li > span {
  position: relative;
  float: left;
  padding: 6px 12px;
  margin-left: -1px;
  line-height: 1.42857143;
  color: #337ab7;
  text-decoration: none;
  background-color: #fff;
  border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
  margin-left: 0;
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
}
.pagination > li:last-child > a,
.pagination > li:last-child > span {
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
  color: #23527c;
  background-color: #eee;
  border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
  z-index: 2;
  color: #fff;
  cursor: default;
  background-color: #337ab7;
  border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
  color: #777;
  cursor: not-allowed;
  background-color: #fff;
  border-color: #ddd;
}
.pagination-lg > li > a,
.pagination-lg > li > span {
  padding: 10px 16px;
  font-size: 18px;
}
.pagination-lg > li:first-child > a,
.pagination-lg > li:first-child > span {
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}
.pagination-lg > li:last-child > a,
.pagination-lg > li:last-child > span {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}
.pagination-sm > li > a,
.pagination-sm > li > span {
  padding: 5px 10px;
  font-size: 12px;
}
.pagination-sm > li:first-child > a,
.pagination-sm > li:first-child > span {
  border-top-left-radius: 3px;
  border-bottom-left-radius: 3px;
}
.pagination-sm > li:last-child > a,
.pagination-sm > li:last-child > span {
  border-top-right-radius: 3px;
  border-bottom-right-radius: 3px;
}
.pager {
  padding-left: 0;
  margin: 20px 0;
  text-align: center;
  list-style: none;
}
.pager li {
  display: inline;
}
.pager li > a,
.pager li > span {
  display: inline-block;
  padding: 5px 14px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 15px;
}
.pager li > a:hover,
.pager li > a:focus {
  text-decoration: none;
  background-color: #eee;
}
.pager .next > a,
.pager .next > span {
  float: right;
}
.pager .previous > a,
.pager .previous > span {
  float: left;
}
.pager .disabled > a,
.pager .disabled > a:hover,
.pager .disabled > a:focus,
.pager .disabled > span {
  color: #777;
  cursor: not-allowed;
  background-color: #fff;
}
.label {
  display: inline;
  padding: .2em .6em .3em;
  font-size: 75%;
  font-weight: bold;
  line-height: 1;
  color: #fff;
  text-align: center;
  white-space: nowrap;
  vertical-align: baseline;
  border-radius: .25em;
}
a.label:hover,
a.label:focus {
  color: #fff;
  text-decoration: none;
  cursor: pointer;
}
.label:empty {
  display: none;
}
.btn .label {
  position: relative;
  top: -1px;
}
.label-default {
  background-color: #777;
}
.label-default[href]:hover,
.label-default[href]:focus {
  background-color: #5e5e5e;
}
.label-primary {
  background-color: #337ab7;
}
.label-primary[href]:hover,
.label-primary[href]:focus {
  background-color: #286090;
}
.label-success {
  background-color: #5cb85c;
}
.label-success[href]:hover,
.label-success[href]:focus {
  background-color: #449d44;
}
.label-info {
  background-color: #5bc0de;
}
.label-info[href]:hover,
.label-info[href]:focus {
  background-color: #31b0d5;
}
.label-warning {
  background-color: #f0ad4e;
}
.label-warning[href]:hover,
.label-warning[href]:focus {
  background-color: #ec971f;
}
.label-danger {
  background-color: #d9534f;
}
.label-danger[href]:hover,
.label-danger[href]:focus {
  background-color: #c9302c;
}
.badge {
  display: inline-block;
  min-width: 10px;
  padding: 3px 7px;
  font-size: 12px;
  font-weight: bold;
  line-height: 1;
  color: #fff;
  text-align: center;
  white-space: nowrap;
  vertical-align: baseline;
  background-color: #777;
  border-radius: 10px;
}
.badge:empty {
  display: none;
}
.btn .badge {
  position: relative;
  top: -1px;
}
.btn-xs .badge,
.btn-group-xs > .btn .badge {
  top: 0;
  padding: 1px 5px;
}
a.badge:hover,
a.badge:focus {
  color: #fff;
  text-decoration: none;
  cursor: pointer;
}
.list-group-item.active > .badge,
.nav-pills > .active > a > .badge {
  color: #337ab7;
  background-color: #fff;
}
.list-group-item > .badge {
  float: right;
}
.list-group-item > .badge + .badge {
  margin-right: 5px;
}
.nav-pills > li > a > .badge {
  margin-left: 3px;
}
.jumbotron {
  padding: 30px 15px;
  margin-bottom: 30px;
  color: inherit;
  background-color: #eee;
}
.jumbotron h1,
.jumbotron .h1 {
  color: inherit;
}
.jumbotron p {
  margin-bottom: 15px;
  font-size: 21px;
  font-weight: 200;
}
.jumbotron > hr {
  border-top-color: #d5d5d5;
}
.container .jumbotron,
.container-fluid .jumbotron {
  border-radius: 6px;
}
.jumbotron .container {
  max-width: 100%;
}
@media screen and (min-width: 768px) {
  .jumbotron {
    padding: 48px 0;
  }
  .container .jumbotron,
  .container-fluid .jumbotron {
    padding-right: 60px;
    padding-left: 60px;
  }
  .jumbotron h1,
  .jumbotron .h1 {
    font-size: 63px;
  }
}
.thumbnail {
  display: block;
  padding: 4px;
  margin-bottom: 20px;
  line-height: 1.42857143;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  -webkit-transition: border .2s ease-in-out;
       -o-transition: border .2s ease-in-out;
          transition: border .2s ease-in-out;
}
.thumbnail > img,
.thumbnail a > img {
  margin-right: auto;
  margin-left: auto;
}
a.thumbnail:hover,
a.thumbnail:focus,
a.thumbnail.active {
  border-color: #337ab7;
}
.thumbnail .caption {
  padding: 9px;
  color: #333;
}
.alert {
  padding: 15px;
  margin-bottom: 20px;
  border: 1px solid transparent;
  border-radius: 4px;
}
.alert h4 {
  margin-top: 0;
  color: inherit;
}
.alert .alert-link {
  font-weight: bold;
}
.alert > p,
.alert > ul {
  margin-bottom: 0;
}
.alert > p + p {
  margin-top: 5px;
}
.alert-dismissable,
.alert-dismissible {
  padding-right: 35px;
}
.alert-dismissable .close,
.alert-dismissible .close {
  position: relative;
  top: -2px;
  right: -21px;
  color: inherit;
}
.alert-success {
  color: #3c763d;
  background-color: #dff0d8;
  border-color: #d6e9c6;
}
.alert-success hr {
  border-top-color: #c9e2b3;
}
.alert-success .alert-link {
  color: #2b542c;
}
.alert-info {
  color: #31708f;
  background-color: #d9edf7;
  border-color: #bce8f1;
}
.alert-info hr {
  border-top-color: #a6e1ec;
}
.alert-info .alert-link {
  color: #245269;
}
.alert-warning {
  color: #8a6d3b;
  background-color: #fcf8e3;
  border-color: #faebcc;
}
.alert-warning hr {
  border-top-color: #f7e1b5;
}
.alert-warning .alert-link {
  color: #66512c;
}
.alert-danger {
  color: #a94442;
  background-color: #f2dede;
  border-color: #ebccd1;
}
.alert-danger hr {
  border-top-color: #e4b9c0;
}
.alert-danger .alert-link {
  color: #843534;
}
@-webkit-keyframes progress-bar-stripes {
  from {
    background-position: 40px 0;
  }
  to {
    background-position: 0 0;
  }
}
@-o-keyframes progress-bar-stripes {
  from {
    background-position: 40px 0;
  }
  to {
    background-position: 0 0;
  }
}
@keyframes progress-bar-stripes {
  from {
    background-position: 40px 0;
  }
  to {
    background-position: 0 0;
  }
}
.progress {
  height: 20px;
  margin-bottom: 20px;
  overflow: hidden;
  background-color: #f5f5f5;
  border-radius: 4px;
  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
}
.progress-bar {
  float: left;
  width: 0;
  height: 100%;
  font-size: 12px;
  line-height: 20px;
  color: #fff;
  text-align: center;
  background-color: #337ab7;
  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
  -webkit-transition: width .6s ease;
       -o-transition: width .6s ease;
          transition: width .6s ease;
}
.progress-striped .progress-bar,
.progress-bar-striped {
  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  -webkit-background-size: 40px 40px;
          background-size: 40px 40px;
}
.progress.active .progress-bar,
.progress-bar.active {
  -webkit-animation: progress-bar-stripes 2s linear infinite;
       -o-animation: progress-bar-stripes 2s linear infinite;
          animation: progress-bar-stripes 2s linear infinite;
}
.progress-bar-success {
  background-color: #5cb85c;
}
.progress-striped .progress-bar-success {
  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.progress-bar-info {
  background-color: #5bc0de;
}
.progress-striped .progress-bar-info {
  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.progress-bar-warning {
  background-color: #f0ad4e;
}
.progress-striped .progress-bar-warning {
  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.progress-bar-danger {
  background-color: #d9534f;
}
.progress-striped .progress-bar-danger {
  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.media {
  margin-top: 15px;
}
.media:first-child {
  margin-top: 0;
}
.media,
.media-body {
  overflow: hidden;
  zoom: 1;
}
.media-body {
  width: 10000px;
}
.media-object {
  display: block;
}
.media-right,
.media > .pull-right {
  padding-left: 10px;
}
.media-left,
.media > .pull-left {
  padding-right: 10px;
}
.media-left,
.media-right,
.media-body {
  display: table-cell;
  vertical-align: top;
}
.media-middle {
  vertical-align: middle;
}
.media-bottom {
  vertical-align: bottom;
}
.media-heading {
  margin-top: 0;
  margin-bottom: 5px;
}
.media-list {
  padding-left: 0;
  list-style: none;
}
.list-group {
  padding-left: 0;
  margin-bottom: 20px;
}
.list-group-item {
  position: relative;
  display: block;
  padding: 10px 15px;
  margin-bottom: -1px;
  background-color: #fff;
  border: 1px solid #ddd;
}
.list-group-item:first-child {
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
}
.list-group-item:last-child {
  margin-bottom: 0;
  border-bottom-right-radius: 4px;
  border-bottom-left-radius: 4px;
}
a.list-group-item {
  color: #555;
}
a.list-group-item .list-group-item-heading {
  color: #333;
}
a.list-group-item:hover,
a.list-group-item:focus {
  color: #555;
  text-decoration: none;
  background-color: #f5f5f5;
}
.list-group-item.disabled,
.list-group-item.disabled:hover,
.list-group-item.disabled:focus {
  color: #777;
  cursor: not-allowed;
  background-color: #eee;
}
.list-group-item.disabled .list-group-item-heading,
.list-group-item.disabled:hover .list-group-item-heading,
.list-group-item.disabled:focus .list-group-item-heading {
  color: inherit;
}
.list-group-item.disabled .list-group-item-text,
.list-group-item.disabled:hover .list-group-item-text,
.list-group-item.disabled:focus .list-group-item-text {
  color: #777;
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
  z-index: 2;
  color: #fff;
  background-color: #337ab7;
  border-color: #337ab7;
}
.list-group-item.active .list-group-item-heading,
.list-group-item.active:hover .list-group-item-heading,
.list-group-item.active:focus .list-group-item-heading,
.list-group-item.active .list-group-item-heading > small,
.list-group-item.active:hover .list-group-item-heading > small,
.list-group-item.active:focus .list-group-item-heading > small,
.list-group-item.active .list-group-item-heading > .small,
.list-group-item.active:hover .list-group-item-heading > .small,
.list-group-item.active:focus .list-group-item-heading > .small {
  color: inherit;
}
.list-group-item.active .list-group-item-text,
.list-group-item.active:hover .list-group-item-text,
.list-group-item.active:focus .list-group-item-text {
  color: #c7ddef;
}
.list-group-item-success {
  color: #3c763d;
  background-color: #dff0d8;
}
a.list-group-item-success {
  color: #3c763d;
}
a.list-group-item-success .list-group-item-heading {
  color: inherit;
}
a.list-group-item-success:hover,
a.list-group-item-success:focus {
  color: #3c763d;
  background-color: #d0e9c6;
}
a.list-group-item-success.active,
a.list-group-item-success.active:hover,
a.list-group-item-success.active:focus {
  color: #fff;
  background-color: #3c763d;
  border-color: #3c763d;
}
.list-group-item-info {
  color: #31708f;
  background-color: #d9edf7;
}
a.list-group-item-info {
  color: #31708f;
}
a.list-group-item-info .list-group-item-heading {
  color: inherit;
}
a.list-group-item-info:hover,
a.list-group-item-info:focus {
  color: #31708f;
  background-color: #c4e3f3;
}
a.list-group-item-info.active,
a.list-group-item-info.active:hover,
a.list-group-item-info.active:focus {
  color: #fff;
  background-color: #31708f;
  border-color: #31708f;
}
.list-group-item-warning {
  color: #8a6d3b;
  background-color: #fcf8e3;
}
a.list-group-item-warning {
  color: #8a6d3b;
}
a.list-group-item-warning .list-group-item-heading {
  color: inherit;
}
a.list-group-item-warning:hover,
a.list-group-item-warning:focus {
  color: #8a6d3b;
  background-color: #faf2cc;
}
a.list-group-item-warning.active,
a.list-group-item-warning.active:hover,
a.list-group-item-warning.active:focus {
  color: #fff;
  background-color: #8a6d3b;
  border-color: #8a6d3b;
}
.list-group-item-danger {
  color: #a94442;
  background-color: #f2dede;
}
a.list-group-item-danger {
  color: #a94442;
}
a.list-group-item-danger .list-group-item-heading {
  color: inherit;
}
a.list-group-item-danger:hover,
a.list-group-item-danger:focus {
  color: #a94442;
  background-color: #ebcccc;
}
a.list-group-item-danger.active,
a.list-group-item-danger.active:hover,
a.list-group-item-danger.active:focus {
  color: #fff;
  background-color: #a94442;
  border-color: #a94442;
}
.list-group-item-heading {
  margin-top: 0;
  margin-bottom: 5px;
}
.list-group-item-text {
  margin-bottom: 0;
  line-height: 1.3;
}
.panel {
  margin-bottom: 20px;
  background-color: #fff;
  border: 1px solid transparent;
  border-radius: 4px;
  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
}
.panel-body {
  padding: 15px;
}
.panel-heading {
  padding: 10px 15px;
  border-bottom: 1px solid transparent;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}
.panel-heading > .dropdown .dropdown-toggle {
  color: inherit;
}
.panel-title {
  margin-top: 0;
  margin-bottom: 0;
  font-size: 16px;
  color: inherit;
}
.panel-title > a,
.panel-title > small,
.panel-title > .small,
.panel-title > small > a,
.panel-title > .small > a {
  color: inherit;
}
.panel-footer {
  padding: 10px 15px;
  background-color: #f5f5f5;
  border-top: 1px solid #ddd;
  border-bottom-right-radius: 3px;
  border-bottom-left-radius: 3px;
}
.panel > .list-group,
.panel > .panel-collapse > .list-group {
  margin-bottom: 0;
}
.panel > .list-group .list-group-item,
.panel > .panel-collapse > .list-group .list-group-item {
  border-width: 1px 0;
  border-radius: 0;
}
.panel > .list-group:first-child .list-group-item:first-child,
.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
  border-top: 0;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}
.panel > .list-group:last-child .list-group-item:last-child,
.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
  border-bottom: 0;
  border-bottom-right-radius: 3px;
  border-bottom-left-radius: 3px;
}
.panel-heading + .list-group .list-group-item:first-child {
  border-top-width: 0;
}
.list-group + .panel-footer {
  border-top-width: 0;
}
.panel > .table,
.panel > .table-responsive > .table,
.panel > .panel-collapse > .table {
  margin-bottom: 0;
}
.panel > .table caption,
.panel > .table-responsive > .table caption,
.panel > .panel-collapse > .table caption {
  padding-right: 15px;
  padding-left: 15px;
}
.panel > .table:first-child,
.panel > .table-responsive:first-child > .table:first-child {
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}
.panel > .table:first-child > thead:first-child > tr:first-child,
.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
.panel > .table:first-child > tbody:first-child > tr:first-child,
.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}
.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
  border-top-left-radius: 3px;
}
.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
  border-top-right-radius: 3px;
}
.panel > .table:last-child,
.panel > .table-responsive:last-child > .table:last-child {
  border-bottom-right-radius: 3px;
  border-bottom-left-radius: 3px;
}
.panel > .table:last-child > tbody:last-child > tr:last-child,
.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
.panel > .table:last-child > tfoot:last-child > tr:last-child,
.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
  border-bottom-right-radius: 3px;
  border-bottom-left-radius: 3px;
}
.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
  border-bottom-left-radius: 3px;
}
.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
  border-bottom-right-radius: 3px;
}
.panel > .panel-body + .table,
.panel > .panel-body + .table-responsive,
.panel > .table + .panel-body,
.panel > .table-responsive + .panel-body {
  border-top: 1px solid #ddd;
}
.panel > .table > tbody:first-child > tr:first-child th,
.panel > .table > tbody:first-child > tr:first-child td {
  border-top: 0;
}
.panel > .table-bordered,
.panel > .table-responsive > .table-bordered {
  border: 0;
}
.panel > .table-bordered > thead > tr > th:first-child,
.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
.panel > .table-bordered > tbody > tr > th:first-child,
.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
.panel > .table-bordered > tfoot > tr > th:first-child,
.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
.panel > .table-bordered > thead > tr > td:first-child,
.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
.panel > .table-bordered > tbody > tr > td:first-child,
.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
.panel > .table-bordered > tfoot > tr > td:first-child,
.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
  border-left: 0;
}
.panel > .table-bordered > thead > tr > th:last-child,
.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
.panel > .table-bordered > tbody > tr > th:last-child,
.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
.panel > .table-bordered > tfoot > tr > th:last-child,
.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
.panel > .table-bordered > thead > tr > td:last-child,
.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
.panel > .table-bordered > tbody > tr > td:last-child,
.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
.panel > .table-bordered > tfoot > tr > td:last-child,
.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
  border-right: 0;
}
.panel > .table-bordered > thead > tr:first-child > td,
.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
.panel > .table-bordered > tbody > tr:first-child > td,
.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
.panel > .table-bordered > thead > tr:first-child > th,
.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
.panel > .table-bordered > tbody > tr:first-child > th,
.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
  border-bottom: 0;
}
.panel > .table-bordered > tbody > tr:last-child > td,
.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
.panel > .table-bordered > tfoot > tr:last-child > td,
.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
.panel > .table-bordered > tbody > tr:last-child > th,
.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
.panel > .table-bordered > tfoot > tr:last-child > th,
.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
  border-bottom: 0;
}
.panel > .table-responsive {
  margin-bottom: 0;
  border: 0;
}
.panel-group {
  margin-bottom: 20px;
}
.panel-group .panel {
  margin-bottom: 0;
  border-radius: 4px;
}
.panel-group .panel + .panel {
  margin-top: 5px;
}
.panel-group .panel-heading {
  border-bottom: 0;
}
.panel-group .panel-heading + .panel-collapse > .panel-body,
.panel-group .panel-heading + .panel-collapse > .list-group {
  border-top: 1px solid #ddd;
}
.panel-group .panel-footer {
  border-top: 0;
}
.panel-group .panel-footer + .panel-collapse .panel-body {
  border-bottom: 1px solid #ddd;
}
.panel-default {
  border-color: #ddd;
}
.panel-default > .panel-heading {
  color: #333;
  background-color: #f5f5f5;
  border-color: #ddd;
}
.panel-default > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #ddd;
}
.panel-default > .panel-heading .badge {
  color: #f5f5f5;
  background-color: #333;
}
.panel-default > .panel-footer + .panel-collapse > .panel-body {
  border-bottom-color: #ddd;
}
.panel-primary {
  border-color: #337ab7;
}
.panel-primary > .panel-heading {
  color: #fff;
  background-color: #337ab7;
  border-color: #337ab7;
}
.panel-primary > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #337ab7;
}
.panel-primary > .panel-heading .badge {
  color: #337ab7;
  background-color: #fff;
}
.panel-primary > .panel-footer + .panel-collapse > .panel-body {
  border-bottom-color: #337ab7;
}
.panel-success {
  border-color: #d6e9c6;
}
.panel-success > .panel-heading {
  color: #3c763d;
  background-color: #dff0d8;
  border-color: #d6e9c6;
}
.panel-success > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #d6e9c6;
}
.panel-success > .panel-heading .badge {
  color: #dff0d8;
  background-color: #3c763d;
}
.panel-success > .panel-footer + .panel-collapse > .panel-body {
  border-bottom-color: #d6e9c6;
}
.panel-info {
  border-color: #bce8f1;
}
.panel-info > .panel-heading {
  color: #31708f;
  background-color: #d9edf7;
  border-color: #bce8f1;
}
.panel-info > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #bce8f1;
}
.panel-info > .panel-heading .badge {
  color: #d9edf7;
  background-color: #31708f;
}
.panel-info > .panel-footer + .panel-collapse > .panel-body {
  border-bottom-color: #bce8f1;
}
.panel-warning {
  border-color: #faebcc;
}
.panel-warning > .panel-heading {
  color: #8a6d3b;
  background-color: #fcf8e3;
  border-color: #faebcc;
}
.panel-warning > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #faebcc;
}
.panel-warning > .panel-heading .badge {
  color: #fcf8e3;
  background-color: #8a6d3b;
}
.panel-warning > .panel-footer + .panel-collapse > .panel-body {
  border-bottom-color: #faebcc;
}
.panel-danger {
  border-color: #ebccd1;
}
.panel-danger > .panel-heading {
  color: #a94442;
  background-color: #f2dede;
  border-color: #ebccd1;
}
.panel-danger > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #ebccd1;
}
.panel-danger > .panel-heading .badge {
  color: #f2dede;
  background-color: #a94442;
}
.panel-danger > .panel-footer + .panel-collapse > .panel-body {
  border-bottom-color: #ebccd1;
}
.embed-responsive {
  position: relative;
  display: block;
  height: 0;
  padding: 0;
  overflow: hidden;
}
.embed-responsive .embed-responsive-item,
.embed-responsive iframe,
.embed-responsive embed,
.embed-responsive object,
.embed-responsive video {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.embed-responsive-16by9 {
  padding-bottom: 56.25%;
}
.embed-responsive-4by3 {
  padding-bottom: 75%;
}
.well {
  min-height: 20px;
  padding: 19px;
  margin-bottom: 20px;
  background-color: #f5f5f5;
  border: 1px solid #e3e3e3;
  border-radius: 4px;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
}
.well blockquote {
  border-color: #ddd;
  border-color: rgba(0, 0, 0, .15);
}
.well-lg {
  padding: 24px;
  border-radius: 6px;
}
.well-sm {
  padding: 9px;
  border-radius: 3px;
}
.close {
  float: right;
  font-size: 21px;
  font-weight: bold;
  line-height: 1;
  color: #000;
  text-shadow: 0 1px 0 #fff;
  filter: alpha(opacity=20);
  opacity: .2;
}
.close:hover,
.close:focus {
  color: #000;
  text-decoration: none;
  cursor: pointer;
  filter: alpha(opacity=50);
  opacity: .5;
}
button.close {
  -webkit-appearance: none;
  padding: 0;
  cursor: pointer;
  background: transparent;
  border: 0;
}
.modal-open {
  overflow: hidden;
}
.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1050;
  display: none;
  overflow: hidden;
  -webkit-overflow-scrolling: touch;
  outline: 0;
}
.modal.fade .modal-dialog {
  -webkit-transition: -webkit-transform .3s ease-out;
       -o-transition:      -o-transform .3s ease-out;
          transition:         transform .3s ease-out;
  -webkit-transform: translate(0, -25%);
      -ms-transform: translate(0, -25%);
       -o-transform: translate(0, -25%);
          transform: translate(0, -25%);
}
.modal.in .modal-dialog {
  -webkit-transform: translate(0, 0);
      -ms-transform: translate(0, 0);
       -o-transform: translate(0, 0);
          transform: translate(0, 0);
}
.modal-open .modal {
  overflow-x: hidden;
  overflow-y: auto;
}
.modal-dialog {
  position: relative;
  width: auto;
  margin: 10px;
}
.modal-content {
  position: relative;
  background-color: #fff;
  -webkit-background-clip: padding-box;
          background-clip: padding-box;
  border: 1px solid #999;
  border: 1px solid rgba(0, 0, 0, .2);
  border-radius: 6px;
  outline: 0;
  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
}
.modal-backdrop {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1040;
  background-color: #000;
}
.modal-backdrop.fade {
  filter: alpha(opacity=0);
  opacity: 0;
}
.modal-backdrop.in {
  filter: alpha(opacity=50);
  opacity: .5;
}
.modal-header {
  min-height: 16.42857143px;
  padding: 15px;
  border-bottom: 1px solid #e5e5e5;
}
.modal-header .close {
  margin-top: -2px;
}
.modal-title {
  margin: 0;
  line-height: 1.42857143;
}
.modal-body {
  position: relative;
  padding: 15px;
}
.modal-footer {
  padding: 15px;
  text-align: right;
  border-top: 1px solid #e5e5e5;
}
.modal-footer .btn + .btn {
  margin-bottom: 0;
  margin-left: 5px;
}
.modal-footer .btn-group .btn + .btn {
  margin-left: -1px;
}
.modal-footer .btn-block + .btn-block {
  margin-left: 0;
}
.modal-scrollbar-measure {
  position: absolute;
  top: -9999px;
  width: 50px;
  height: 50px;
  overflow: scroll;
}
@media (min-width: 768px) {
  .modal-dialog {
    width: 600px;
    margin: 30px auto;
  }
  .modal-content {
    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
  }
  .modal-sm {
    width: 300px;
  }
}
@media (min-width: 992px) {
  .modal-lg {
    width: 900px;
  }
}
.tooltip {
  position: absolute;
  z-index: 1070;
  display: block;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 12px;
  font-weight: normal;
  line-height: 1.4;
  filter: alpha(opacity=0);
  opacity: 0;
}
.tooltip.in {
  filter: alpha(opacity=90);
  opacity: .9;
}
.tooltip.top {
  padding: 5px 0;
  margin-top: -3px;
}
.tooltip.right {
  padding: 0 5px;
  margin-left: 3px;
}
.tooltip.bottom {
  padding: 5px 0;
  margin-top: 3px;
}
.tooltip.left {
  padding: 0 5px;
  margin-left: -3px;
}
.tooltip-inner {
  max-width: 200px;
  padding: 3px 8px;
  color: #fff;
  text-align: center;
  text-decoration: none;
  background-color: #000;
  border-radius: 4px;
}
.tooltip-arrow {
  position: absolute;
  width: 0;
  height: 0;
  border-color: transparent;
  border-style: solid;
}
.tooltip.top .tooltip-arrow {
  bottom: 0;
  left: 50%;
  margin-left: -5px;
  border-width: 5px 5px 0;
  border-top-color: #000;
}
.tooltip.top-left .tooltip-arrow {
  right: 5px;
  bottom: 0;
  margin-bottom: -5px;
  border-width: 5px 5px 0;
  border-top-color: #000;
}
.tooltip.top-right .tooltip-arrow {
  bottom: 0;
  left: 5px;
  margin-bottom: -5px;
  border-width: 5px 5px 0;
  border-top-color: #000;
}
.tooltip.right .tooltip-arrow {
  top: 50%;
  left: 0;
  margin-top: -5px;
  border-width: 5px 5px 5px 0;
  border-right-color: #000;
}
.tooltip.left .tooltip-arrow {
  top: 50%;
  right: 0;
  margin-top: -5px;
  border-width: 5px 0 5px 5px;
  border-left-color: #000;
}
.tooltip.bottom .tooltip-arrow {
  top: 0;
  left: 50%;
  margin-left: -5px;
  border-width: 0 5px 5px;
  border-bottom-color: #000;
}
.tooltip.bottom-left .tooltip-arrow {
  top: 0;
  right: 5px;
  margin-top: -5px;
  border-width: 0 5px 5px;
  border-bottom-color: #000;
}
.tooltip.bottom-right .tooltip-arrow {
  top: 0;
  left: 5px;
  margin-top: -5px;
  border-width: 0 5px 5px;
  border-bottom-color: #000;
}
.popover {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1060;
  display: none;
  max-width: 276px;
  padding: 1px;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  font-weight: normal;
  line-height: 1.42857143;
  text-align: left;
  white-space: normal;
  background-color: #fff;
  -webkit-background-clip: padding-box;
          background-clip: padding-box;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, .2);
  border-radius: 6px;
  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
}
.popover.top {
  margin-top: -10px;
}
.popover.right {
  margin-left: 10px;
}
.popover.bottom {
  margin-top: 10px;
}
.popover.left {
  margin-left: -10px;
}
.popover-title {
  padding: 8px 14px;
  margin: 0;
  font-size: 14px;
  background-color: #f7f7f7;
  border-bottom: 1px solid #ebebeb;
  border-radius: 5px 5px 0 0;
}
.popover-content {
  padding: 9px 14px;
}
.popover > .arrow,
.popover > .arrow:after {
  position: absolute;
  display: block;
  width: 0;
  height: 0;
  border-color: transparent;
  border-style: solid;
}
.popover > .arrow {
  border-width: 11px;
}
.popover > .arrow:after {
  content: "";
  border-width: 10px;
}
.popover.top > .arrow {
  bottom: -11px;
  left: 50%;
  margin-left: -11px;
  border-top-color: #999;
  border-top-color: rgba(0, 0, 0, .25);
  border-bottom-width: 0;
}
.popover.top > .arrow:after {
  bottom: 1px;
  margin-left: -10px;
  content: " ";
  border-top-color: #fff;
  border-bottom-width: 0;
}
.popover.right > .arrow {
  top: 50%;
  left: -11px;
  margin-top: -11px;
  border-right-color: #999;
  border-right-color: rgba(0, 0, 0, .25);
  border-left-width: 0;
}
.popover.right > .arrow:after {
  bottom: -10px;
  left: 1px;
  content: " ";
  border-right-color: #fff;
  border-left-width: 0;
}
.popover.bottom > .arrow {
  top: -11px;
  left: 50%;
  margin-left: -11px;
  border-top-width: 0;
  border-bottom-color: #999;
  border-bottom-color: rgba(0, 0, 0, .25);
}
.popover.bottom > .arrow:after {
  top: 1px;
  margin-left: -10px;
  content: " ";
  border-top-width: 0;
  border-bottom-color: #fff;
}
.popover.left > .arrow {
  top: 50%;
  right: -11px;
  margin-top: -11px;
  border-right-width: 0;
  border-left-color: #999;
  border-left-color: rgba(0, 0, 0, .25);
}
.popover.left > .arrow:after {
  right: 1px;
  bottom: -10px;
  content: " ";
  border-right-width: 0;
  border-left-color: #fff;
}
.carousel {
  position: relative;
}
.carousel-inner {
  position: relative;
  width: 100%;
  overflow: hidden;
}
.carousel-inner > .item {
  position: relative;
  display: none;
  -webkit-transition: .6s ease-in-out left;
       -o-transition: .6s ease-in-out left;
          transition: .6s ease-in-out left;
}
.carousel-inner > .item > img,
.carousel-inner > .item > a > img {
  line-height: 1;
}
@media all and (transform-3d), (-webkit-transform-3d) {
  .carousel-inner > .item {
    -webkit-transition: -webkit-transform .6s ease-in-out;
         -o-transition:      -o-transform .6s ease-in-out;
            transition:         transform .6s ease-in-out;

    -webkit-backface-visibility: hidden;
            backface-visibility: hidden;
    -webkit-perspective: 1000;
            perspective: 1000;
  }
  .carousel-inner > .item.next,
  .carousel-inner > .item.active.right {
    left: 0;
    -webkit-transform: translate3d(100%, 0, 0);
            transform: translate3d(100%, 0, 0);
  }
  .carousel-inner > .item.prev,
  .carousel-inner > .item.active.left {
    left: 0;
    -webkit-transform: translate3d(-100%, 0, 0);
            transform: translate3d(-100%, 0, 0);
  }
  .carousel-inner > .item.next.left,
  .carousel-inner > .item.prev.right,
  .carousel-inner > .item.active {
    left: 0;
    -webkit-transform: translate3d(0, 0, 0);
            transform: translate3d(0, 0, 0);
  }
}
.carousel-inner > .active,
.carousel-inner > .next,
.carousel-inner > .prev {
  display: block;
}
.carousel-inner > .active {
  left: 0;
}
.carousel-inner > .next,
.carousel-inner > .prev {
  position: absolute;
  top: 0;
  width: 100%;
}
.carousel-inner > .next {
  left: 100%;
}
.carousel-inner > .prev {
  left: -100%;
}
.carousel-inner > .next.left,
.carousel-inner > .prev.right {
  left: 0;
}
.carousel-inner > .active.left {
  left: -100%;
}
.carousel-inner > .active.right {
  left: 100%;
}
.carousel-control {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 15%;
  font-size: 20px;
  color: #fff;
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
  filter: alpha(opacity=50);
  opacity: .5;
}
.carousel-control.left {
  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
  background-repeat: repeat-x;
}
.carousel-control.right {
  right: 0;
  left: auto;
  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
  background-repeat: repeat-x;
}
.carousel-control:hover,
.carousel-control:focus {
  color: #fff;
  text-decoration: none;
  filter: alpha(opacity=90);
  outline: 0;
  opacity: .9;
}
.carousel-control .icon-prev,
.carousel-control .icon-next,
.carousel-control .glyphicon-chevron-left,
.carousel-control .glyphicon-chevron-right {
  position: absolute;
  top: 50%;
  z-index: 5;
  display: inline-block;
}
.carousel-control .icon-prev,
.carousel-control .glyphicon-chevron-left {
  left: 50%;
  margin-left: -10px;
}
.carousel-control .icon-next,
.carousel-control .glyphicon-chevron-right {
  right: 50%;
  margin-right: -10px;
}
.carousel-control .icon-prev,
.carousel-control .icon-next {
  width: 20px;
  height: 20px;
  margin-top: -10px;
  font-family: serif;
  line-height: 1;
}
.carousel-control .icon-prev:before {
  content: '\2039';
}
.carousel-control .icon-next:before {
  content: '\203a';
}
.carousel-indicators {
  position: absolute;
  bottom: 10px;
  left: 50%;
  z-index: 15;
  width: 60%;
  padding-left: 0;
  margin-left: -30%;
  text-align: center;
  list-style: none;
}
.carousel-indicators li {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin: 1px;
  text-indent: -999px;
  cursor: pointer;
  background-color: #000 \9;
  background-color: rgba(0, 0, 0, 0);
  border: 1px solid #fff;
  border-radius: 10px;
}
.carousel-indicators .active {
  width: 12px;
  height: 12px;
  margin: 0;
  background-color: #fff;
}
.carousel-caption {
  position: absolute;
  right: 15%;
  bottom: 20px;
  left: 15%;
  z-index: 10;
  padding-top: 20px;
  padding-bottom: 20px;
  color: #fff;
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
.carousel-caption .btn {
  text-shadow: none;
}
@media screen and (min-width: 768px) {
  .carousel-control .glyphicon-chevron-left,
  .carousel-control .glyphicon-chevron-right,
  .carousel-control .icon-prev,
  .carousel-control .icon-next {
    width: 30px;
    height: 30px;
    margin-top: -15px;
    font-size: 30px;
  }
  .carousel-control .glyphicon-chevron-left,
  .carousel-control .icon-prev {
    margin-left: -15px;
  }
  .carousel-control .glyphicon-chevron-right,
  .carousel-control .icon-next {
    margin-right: -15px;
  }
  .carousel-caption {
    right: 20%;
    left: 20%;
    padding-bottom: 30px;
  }
  .carousel-indicators {
    bottom: 20px;
  }
}
.clearfix:before,
.clearfix:after,
.dl-horizontal dd:before,
.dl-horizontal dd:after,
.container:before,
.container:after,
.container-fluid:before,
.container-fluid:after,
.row:before,
.row:after,
.form-horizontal .form-group:before,
.form-horizontal .form-group:after,
.btn-toolbar:before,
.btn-toolbar:after,
.btn-group-vertical > .btn-group:before,
.btn-group-vertical > .btn-group:after,
.nav:before,
.nav:after,
.navbar:before,
.navbar:after,
.navbar-header:before,
.navbar-header:after,
.navbar-collapse:before,
.navbar-collapse:after,
.pager:before,
.pager:after,
.panel-body:before,
.panel-body:after,
.modal-footer:before,
.modal-footer:after {
  display: table;
  content: " ";
}
.clearfix:after,
.dl-horizontal dd:after,
.container:after,
.container-fluid:after,
.row:after,
.form-horizontal .form-group:after,
.btn-toolbar:after,
.btn-group-vertical > .btn-group:after,
.nav:after,
.navbar:after,
.navbar-header:after,
.navbar-collapse:after,
.pager:after,
.panel-body:after,
.modal-footer:after {
  clear: both;
}
.center-block {
  display: block;
  margin-right: auto;
  margin-left: auto;
}
.pull-right {
  float: right !important;
}
.pull-left {
  float: left !important;
}
.hide {
  display: none !important;
}
.show {
  display: block !important;
}
.invisible {
  visibility: hidden;
}
.text-hide {
  font: 0/0 a;
  color: transparent;
  text-shadow: none;
  background-color: transparent;
  border: 0;
}
.hidden {
  display: none !important;
}
.affix {
  position: fixed;
}
@-ms-viewport {
  width: device-width;
}
.visible-xs,
.visible-sm,
.visible-md,
.visible-lg {
  display: none !important;
}
.visible-xs-block,
.visible-xs-inline,
.visible-xs-inline-block,
.visible-sm-block,
.visible-sm-inline,
.visible-sm-inline-block,
.visible-md-block,
.visible-md-inline,
.visible-md-inline-block,
.visible-lg-block,
.visible-lg-inline,
.visible-lg-inline-block {
  display: none !important;
}
@media (max-width: 767px) {
  .visible-xs {
    display: block !important;
  }
  table.visible-xs {
    display: table;
  }
  tr.visible-xs {
    display: table-row !important;
  }
  th.visible-xs,
  td.visible-xs {
    display: table-cell !important;
  }
}
@media (max-width: 767px) {
  .visible-xs-block {
    display: block !important;
  }
}
@media (max-width: 767px) {
  .visible-xs-inline {
    display: inline !important;
  }
}
@media (max-width: 767px) {
  .visible-xs-inline-block {
    display: inline-block !important;
  }
}
@media (min-width: 768px) and (max-width: 991px) {
  .visible-sm {
    display: block !important;
  }
  table.visible-sm {
    display: table;
  }
  tr.visible-sm {
    display: table-row !important;
  }
  th.visible-sm,
  td.visible-sm {
    display: table-cell !important;
  }
}
@media (min-width: 768px) and (max-width: 991px) {
  .visible-sm-block {
    display: block !important;
  }
}
@media (min-width: 768px) and (max-width: 991px) {
  .visible-sm-inline {
    display: inline !important;
  }
}
@media (min-width: 768px) and (max-width: 991px) {
  .visible-sm-inline-block {
    display: inline-block !important;
  }
}
@media (min-width: 992px) and (max-width: 1199px) {
  .visible-md {
    display: block !important;
  }
  table.visible-md {
    display: table;
  }
  tr.visible-md {
    display: table-row !important;
  }
  th.visible-md,
  td.visible-md {
    display: table-cell !important;
  }
}
@media (min-width: 992px) and (max-width: 1199px) {
  .visible-md-block {
    display: block !important;
  }
}
@media (min-width: 992px) and (max-width: 1199px) {
  .visible-md-inline {
    display: inline !important;
  }
}
@media (min-width: 992px) and (max-width: 1199px) {
  .visible-md-inline-block {
    display: inline-block !important;
  }
}
@media (min-width: 1200px) {
  .visible-lg {
    display: block !important;
  }
  table.visible-lg {
    display: table;
  }
  tr.visible-lg {
    display: table-row !important;
  }
  th.visible-lg,
  td.visible-lg {
    display: table-cell !important;
  }
}
@media (min-width: 1200px) {
  .visible-lg-block {
    display: block !important;
  }
}
@media (min-width: 1200px) {
  .visible-lg-inline {
    display: inline !important;
  }
}
@media (min-width: 1200px) {
  .visible-lg-inline-block {
    display: inline-block !important;
  }
}
@media (max-width: 767px) {
  .hidden-xs {
    display: none !important;
  }
}
@media (min-width: 768px) and (max-width: 991px) {
  .hidden-sm {
    display: none !important;
  }
}
@media (min-width: 992px) and (max-width: 1199px) {
  .hidden-md {
    display: none !important;
  }
}
@media (min-width: 1200px) {
  .hidden-lg {
    display: none !important;
  }
}
.visible-print {
  display: none !important;
}
@media print {
  .visible-print {
    display: block !important;
  }
  table.visible-print {
    display: table;
  }
  tr.visible-print {
    display: table-row !important;
  }
  th.visible-print,
  td.visible-print {
    display: table-cell !important;
  }
}
.visible-print-block {
  display: none !important;
}
@media print {
  .visible-print-block {
    display: block !important;
  }
}
.visible-print-inline {
  display: none !important;
}
@media print {
  .visible-print-inline {
    display: inline !important;
  }
}
.visible-print-inline-block {
  display: none !important;
}
@media print {
  .visible-print-inline-block {
    display: inline-block !important;
  }
}
@media print {
  .hidden-print {
    display: none !important;
  }
}
/*# sourceMappingURL=bootstrap.css.map */

Added modules/bootstrap/css/bootstrap.css.map.

cannot compute difference between binary files

Added modules/bootstrap/css/bootstrap.min.css.

cannot compute difference between binary files

Added modules/bootstrap/fonts/glyphicons-halflings-regular.eot.

cannot compute difference between binary files

Added modules/bootstrap/fonts/glyphicons-halflings-regular.svg.

































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata></metadata>
<defs>
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
<font-face units-per-em="1200" ascent="960" descent="-240" />
<missing-glyph horiz-adv-x="500" />
<glyph horiz-adv-x="0" />
<glyph horiz-adv-x="400" />
<glyph unicode=" " />
<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xa0;" />
<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
<glyph unicode="&#x2000;" horiz-adv-x="650" />
<glyph unicode="&#x2001;" horiz-adv-x="1300" />
<glyph unicode="&#x2002;" horiz-adv-x="650" />
<glyph unicode="&#x2003;" horiz-adv-x="1300" />
<glyph unicode="&#x2004;" horiz-adv-x="433" />
<glyph unicode="&#x2005;" horiz-adv-x="325" />
<glyph unicode="&#x2006;" horiz-adv-x="216" />
<glyph unicode="&#x2007;" horiz-adv-x="216" />
<glyph unicode="&#x2008;" horiz-adv-x="162" />
<glyph unicode="&#x2009;" horiz-adv-x="260" />
<glyph unicode="&#x200a;" horiz-adv-x="72" />
<glyph unicode="&#x202f;" horiz-adv-x="260" />
<glyph unicode="&#x205f;" horiz-adv-x="325" />
<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
</font>
</defs></svg> 

Added modules/bootstrap/fonts/glyphicons-halflings-regular.ttf.

cannot compute difference between binary files

Added modules/bootstrap/fonts/glyphicons-halflings-regular.woff.

cannot compute difference between binary files

Added modules/bootstrap/fonts/glyphicons-halflings-regular.woff2.

cannot compute difference between binary files

Added modules/bootstrap/js/bootstrap.js.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

if (typeof jQuery === 'undefined') {
  throw new Error('Bootstrap\'s JavaScript requires jQuery')
}

+function ($) {
  'use strict';
  var version = $.fn.jquery.split(' ')[0].split('.')
  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
  }
}(jQuery);

/* ========================================================================
 * Bootstrap: transition.js v3.3.4
 * http://getbootstrap.com/javascript/#transitions
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
  // ============================================================

  function transitionEnd() {
    var el = document.createElement('bootstrap')

    var transEndEventNames = {
      WebkitTransition : 'webkitTransitionEnd',
      MozTransition    : 'transitionend',
      OTransition      : 'oTransitionEnd otransitionend',
      transition       : 'transitionend'
    }

    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return { end: transEndEventNames[name] }
      }
    }

    return false // explicit for ie8 (  ._.)
  }

  // http://blog.alexmaccaw.com/css-transitions
  $.fn.emulateTransitionEnd = function (duration) {
    var called = false
    var $el = this
    $(this).one('bsTransitionEnd', function () { called = true })
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
    setTimeout(callback, duration)
    return this
  }

  $(function () {
    $.support.transition = transitionEnd()

    if (!$.support.transition) return

    $.event.special.bsTransitionEnd = {
      bindType: $.support.transition.end,
      delegateType: $.support.transition.end,
      handle: function (e) {
        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
      }
    }
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: alert.js v3.3.4
 * http://getbootstrap.com/javascript/#alerts
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // ALERT CLASS DEFINITION
  // ======================

  var dismiss = '[data-dismiss="alert"]'
  var Alert   = function (el) {
    $(el).on('click', dismiss, this.close)
  }

  Alert.VERSION = '3.3.4'

  Alert.TRANSITION_DURATION = 150

  Alert.prototype.close = function (e) {
    var $this    = $(this)
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    var $parent = $(selector)

    if (e) e.preventDefault()

    if (!$parent.length) {
      $parent = $this.closest('.alert')
    }

    $parent.trigger(e = $.Event('close.bs.alert'))

    if (e.isDefaultPrevented()) return

    $parent.removeClass('in')

    function removeElement() {
      // detach from parent, fire event then clean up data
      $parent.detach().trigger('closed.bs.alert').remove()
    }

    $.support.transition && $parent.hasClass('fade') ?
      $parent
        .one('bsTransitionEnd', removeElement)
        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
      removeElement()
  }


  // ALERT PLUGIN DEFINITION
  // =======================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.alert')

      if (!data) $this.data('bs.alert', (data = new Alert(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.alert

  $.fn.alert             = Plugin
  $.fn.alert.Constructor = Alert


  // ALERT NO CONFLICT
  // =================

  $.fn.alert.noConflict = function () {
    $.fn.alert = old
    return this
  }


  // ALERT DATA-API
  // ==============

  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)

}(jQuery);

/* ========================================================================
 * Bootstrap: button.js v3.3.4
 * http://getbootstrap.com/javascript/#buttons
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // BUTTON PUBLIC CLASS DEFINITION
  // ==============================

  var Button = function (element, options) {
    this.$element  = $(element)
    this.options   = $.extend({}, Button.DEFAULTS, options)
    this.isLoading = false
  }

  Button.VERSION  = '3.3.4'

  Button.DEFAULTS = {
    loadingText: 'loading...'
  }

  Button.prototype.setState = function (state) {
    var d    = 'disabled'
    var $el  = this.$element
    var val  = $el.is('input') ? 'val' : 'html'
    var data = $el.data()

    state = state + 'Text'

    if (data.resetText == null) $el.data('resetText', $el[val]())

    // push to event loop to allow forms to submit
    setTimeout($.proxy(function () {
      $el[val](data[state] == null ? this.options[state] : data[state])

      if (state == 'loadingText') {
        this.isLoading = true
        $el.addClass(d).attr(d, d)
      } else if (this.isLoading) {
        this.isLoading = false
        $el.removeClass(d).removeAttr(d)
      }
    }, this), 0)
  }

  Button.prototype.toggle = function () {
    var changed = true
    var $parent = this.$element.closest('[data-toggle="buttons"]')

    if ($parent.length) {
      var $input = this.$element.find('input')
      if ($input.prop('type') == 'radio') {
        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
        else $parent.find('.active').removeClass('active')
      }
      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
    } else {
      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
    }

    if (changed) this.$element.toggleClass('active')
  }


  // BUTTON PLUGIN DEFINITION
  // ========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.button')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.button', (data = new Button(this, options)))

      if (option == 'toggle') data.toggle()
      else if (option) data.setState(option)
    })
  }

  var old = $.fn.button

  $.fn.button             = Plugin
  $.fn.button.Constructor = Button


  // BUTTON NO CONFLICT
  // ==================

  $.fn.button.noConflict = function () {
    $.fn.button = old
    return this
  }


  // BUTTON DATA-API
  // ===============

  $(document)
    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
      var $btn = $(e.target)
      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
      Plugin.call($btn, 'toggle')
      e.preventDefault()
    })
    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
    })

}(jQuery);

/* ========================================================================
 * Bootstrap: carousel.js v3.3.4
 * http://getbootstrap.com/javascript/#carousel
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // CAROUSEL CLASS DEFINITION
  // =========================

  var Carousel = function (element, options) {
    this.$element    = $(element)
    this.$indicators = this.$element.find('.carousel-indicators')
    this.options     = options
    this.paused      = null
    this.sliding     = null
    this.interval    = null
    this.$active     = null
    this.$items      = null

    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))

    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
  }

  Carousel.VERSION  = '3.3.4'

  Carousel.TRANSITION_DURATION = 600

  Carousel.DEFAULTS = {
    interval: 5000,
    pause: 'hover',
    wrap: true,
    keyboard: true
  }

  Carousel.prototype.keydown = function (e) {
    if (/input|textarea/i.test(e.target.tagName)) return
    switch (e.which) {
      case 37: this.prev(); break
      case 39: this.next(); break
      default: return
    }

    e.preventDefault()
  }

  Carousel.prototype.cycle = function (e) {
    e || (this.paused = false)

    this.interval && clearInterval(this.interval)

    this.options.interval
      && !this.paused
      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))

    return this
  }

  Carousel.prototype.getItemIndex = function (item) {
    this.$items = item.parent().children('.item')
    return this.$items.index(item || this.$active)
  }

  Carousel.prototype.getItemForDirection = function (direction, active) {
    var activeIndex = this.getItemIndex(active)
    var willWrap = (direction == 'prev' && activeIndex === 0)
                || (direction == 'next' && activeIndex == (this.$items.length - 1))
    if (willWrap && !this.options.wrap) return active
    var delta = direction == 'prev' ? -1 : 1
    var itemIndex = (activeIndex + delta) % this.$items.length
    return this.$items.eq(itemIndex)
  }

  Carousel.prototype.to = function (pos) {
    var that        = this
    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))

    if (pos > (this.$items.length - 1) || pos < 0) return

    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
    if (activeIndex == pos) return this.pause().cycle()

    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
  }

  Carousel.prototype.pause = function (e) {
    e || (this.paused = true)

    if (this.$element.find('.next, .prev').length && $.support.transition) {
      this.$element.trigger($.support.transition.end)
      this.cycle(true)
    }

    this.interval = clearInterval(this.interval)

    return this
  }

  Carousel.prototype.next = function () {
    if (this.sliding) return
    return this.slide('next')
  }

  Carousel.prototype.prev = function () {
    if (this.sliding) return
    return this.slide('prev')
  }

  Carousel.prototype.slide = function (type, next) {
    var $active   = this.$element.find('.item.active')
    var $next     = next || this.getItemForDirection(type, $active)
    var isCycling = this.interval
    var direction = type == 'next' ? 'left' : 'right'
    var that      = this

    if ($next.hasClass('active')) return (this.sliding = false)

    var relatedTarget = $next[0]
    var slideEvent = $.Event('slide.bs.carousel', {
      relatedTarget: relatedTarget,
      direction: direction
    })
    this.$element.trigger(slideEvent)
    if (slideEvent.isDefaultPrevented()) return

    this.sliding = true

    isCycling && this.pause()

    if (this.$indicators.length) {
      this.$indicators.find('.active').removeClass('active')
      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
      $nextIndicator && $nextIndicator.addClass('active')
    }

    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
    if ($.support.transition && this.$element.hasClass('slide')) {
      $next.addClass(type)
      $next[0].offsetWidth // force reflow
      $active.addClass(direction)
      $next.addClass(direction)
      $active
        .one('bsTransitionEnd', function () {
          $next.removeClass([type, direction].join(' ')).addClass('active')
          $active.removeClass(['active', direction].join(' '))
          that.sliding = false
          setTimeout(function () {
            that.$element.trigger(slidEvent)
          }, 0)
        })
        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
    } else {
      $active.removeClass('active')
      $next.addClass('active')
      this.sliding = false
      this.$element.trigger(slidEvent)
    }

    isCycling && this.cycle()

    return this
  }


  // CAROUSEL PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.carousel')
      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
      var action  = typeof option == 'string' ? option : options.slide

      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
      if (typeof option == 'number') data.to(option)
      else if (action) data[action]()
      else if (options.interval) data.pause().cycle()
    })
  }

  var old = $.fn.carousel

  $.fn.carousel             = Plugin
  $.fn.carousel.Constructor = Carousel


  // CAROUSEL NO CONFLICT
  // ====================

  $.fn.carousel.noConflict = function () {
    $.fn.carousel = old
    return this
  }


  // CAROUSEL DATA-API
  // =================

  var clickHandler = function (e) {
    var href
    var $this   = $(this)
    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
    if (!$target.hasClass('carousel')) return
    var options = $.extend({}, $target.data(), $this.data())
    var slideIndex = $this.attr('data-slide-to')
    if (slideIndex) options.interval = false

    Plugin.call($target, options)

    if (slideIndex) {
      $target.data('bs.carousel').to(slideIndex)
    }

    e.preventDefault()
  }

  $(document)
    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)

  $(window).on('load', function () {
    $('[data-ride="carousel"]').each(function () {
      var $carousel = $(this)
      Plugin.call($carousel, $carousel.data())
    })
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: collapse.js v3.3.4
 * http://getbootstrap.com/javascript/#collapse
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // COLLAPSE PUBLIC CLASS DEFINITION
  // ================================

  var Collapse = function (element, options) {
    this.$element      = $(element)
    this.options       = $.extend({}, Collapse.DEFAULTS, options)
    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
    this.transitioning = null

    if (this.options.parent) {
      this.$parent = this.getParent()
    } else {
      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
    }

    if (this.options.toggle) this.toggle()
  }

  Collapse.VERSION  = '3.3.4'

  Collapse.TRANSITION_DURATION = 350

  Collapse.DEFAULTS = {
    toggle: true
  }

  Collapse.prototype.dimension = function () {
    var hasWidth = this.$element.hasClass('width')
    return hasWidth ? 'width' : 'height'
  }

  Collapse.prototype.show = function () {
    if (this.transitioning || this.$element.hasClass('in')) return

    var activesData
    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')

    if (actives && actives.length) {
      activesData = actives.data('bs.collapse')
      if (activesData && activesData.transitioning) return
    }

    var startEvent = $.Event('show.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    if (actives && actives.length) {
      Plugin.call(actives, 'hide')
      activesData || actives.data('bs.collapse', null)
    }

    var dimension = this.dimension()

    this.$element
      .removeClass('collapse')
      .addClass('collapsing')[dimension](0)
      .attr('aria-expanded', true)

    this.$trigger
      .removeClass('collapsed')
      .attr('aria-expanded', true)

    this.transitioning = 1

    var complete = function () {
      this.$element
        .removeClass('collapsing')
        .addClass('collapse in')[dimension]('')
      this.transitioning = 0
      this.$element
        .trigger('shown.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    var scrollSize = $.camelCase(['scroll', dimension].join('-'))

    this.$element
      .one('bsTransitionEnd', $.proxy(complete, this))
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
  }

  Collapse.prototype.hide = function () {
    if (this.transitioning || !this.$element.hasClass('in')) return

    var startEvent = $.Event('hide.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    var dimension = this.dimension()

    this.$element[dimension](this.$element[dimension]())[0].offsetHeight

    this.$element
      .addClass('collapsing')
      .removeClass('collapse in')
      .attr('aria-expanded', false)

    this.$trigger
      .addClass('collapsed')
      .attr('aria-expanded', false)

    this.transitioning = 1

    var complete = function () {
      this.transitioning = 0
      this.$element
        .removeClass('collapsing')
        .addClass('collapse')
        .trigger('hidden.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    this.$element
      [dimension](0)
      .one('bsTransitionEnd', $.proxy(complete, this))
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
  }

  Collapse.prototype.toggle = function () {
    this[this.$element.hasClass('in') ? 'hide' : 'show']()
  }

  Collapse.prototype.getParent = function () {
    return $(this.options.parent)
      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
      .each($.proxy(function (i, element) {
        var $element = $(element)
        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
      }, this))
      .end()
  }

  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
    var isOpen = $element.hasClass('in')

    $element.attr('aria-expanded', isOpen)
    $trigger
      .toggleClass('collapsed', !isOpen)
      .attr('aria-expanded', isOpen)
  }

  function getTargetFromTrigger($trigger) {
    var href
    var target = $trigger.attr('data-target')
      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7

    return $(target)
  }


  // COLLAPSE PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.collapse')
      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)

      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.collapse

  $.fn.collapse             = Plugin
  $.fn.collapse.Constructor = Collapse


  // COLLAPSE NO CONFLICT
  // ====================

  $.fn.collapse.noConflict = function () {
    $.fn.collapse = old
    return this
  }


  // COLLAPSE DATA-API
  // =================

  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
    var $this   = $(this)

    if (!$this.attr('data-target')) e.preventDefault()

    var $target = getTargetFromTrigger($this)
    var data    = $target.data('bs.collapse')
    var option  = data ? 'toggle' : $this.data()

    Plugin.call($target, option)
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: dropdown.js v3.3.4
 * http://getbootstrap.com/javascript/#dropdowns
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // DROPDOWN CLASS DEFINITION
  // =========================

  var backdrop = '.dropdown-backdrop'
  var toggle   = '[data-toggle="dropdown"]'
  var Dropdown = function (element) {
    $(element).on('click.bs.dropdown', this.toggle)
  }

  Dropdown.VERSION = '3.3.4'

  Dropdown.prototype.toggle = function (e) {
    var $this = $(this)

    if ($this.is('.disabled, :disabled')) return

    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')

    clearMenus()

    if (!isActive) {
      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
        // if mobile we use a backdrop because click events don't delegate
        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
      }

      var relatedTarget = { relatedTarget: this }
      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $this
        .trigger('focus')
        .attr('aria-expanded', 'true')

      $parent
        .toggleClass('open')
        .trigger('shown.bs.dropdown', relatedTarget)
    }

    return false
  }

  Dropdown.prototype.keydown = function (e) {
    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return

    var $this = $(this)

    e.preventDefault()
    e.stopPropagation()

    if ($this.is('.disabled, :disabled')) return

    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')

    if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
      if (e.which == 27) $parent.find(toggle).trigger('focus')
      return $this.trigger('click')
    }

    var desc = ' li:not(.disabled):visible a'
    var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)

    if (!$items.length) return

    var index = $items.index(e.target)

    if (e.which == 38 && index > 0)                 index--                        // up
    if (e.which == 40 && index < $items.length - 1) index++                        // down
    if (!~index)                                      index = 0

    $items.eq(index).trigger('focus')
  }

  function clearMenus(e) {
    if (e && e.which === 3) return
    $(backdrop).remove()
    $(toggle).each(function () {
      var $this         = $(this)
      var $parent       = getParent($this)
      var relatedTarget = { relatedTarget: this }

      if (!$parent.hasClass('open')) return

      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $this.attr('aria-expanded', 'false')
      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
    })
  }

  function getParent($this) {
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    var $parent = selector && $(selector)

    return $parent && $parent.length ? $parent : $this.parent()
  }


  // DROPDOWN PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.dropdown')

      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.dropdown

  $.fn.dropdown             = Plugin
  $.fn.dropdown.Constructor = Dropdown


  // DROPDOWN NO CONFLICT
  // ====================

  $.fn.dropdown.noConflict = function () {
    $.fn.dropdown = old
    return this
  }


  // APPLY TO STANDARD DROPDOWN ELEMENTS
  // ===================================

  $(document)
    .on('click.bs.dropdown.data-api', clearMenus)
    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
    .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
    .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)

}(jQuery);

/* ========================================================================
 * Bootstrap: modal.js v3.3.4
 * http://getbootstrap.com/javascript/#modals
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // MODAL CLASS DEFINITION
  // ======================

  var Modal = function (element, options) {
    this.options             = options
    this.$body               = $(document.body)
    this.$element            = $(element)
    this.$dialog             = this.$element.find('.modal-dialog')
    this.$backdrop           = null
    this.isShown             = null
    this.originalBodyPad     = null
    this.scrollbarWidth      = 0
    this.ignoreBackdropClick = false

    if (this.options.remote) {
      this.$element
        .find('.modal-content')
        .load(this.options.remote, $.proxy(function () {
          this.$element.trigger('loaded.bs.modal')
        }, this))
    }
  }

  Modal.VERSION  = '3.3.4'

  Modal.TRANSITION_DURATION = 300
  Modal.BACKDROP_TRANSITION_DURATION = 150

  Modal.DEFAULTS = {
    backdrop: true,
    keyboard: true,
    show: true
  }

  Modal.prototype.toggle = function (_relatedTarget) {
    return this.isShown ? this.hide() : this.show(_relatedTarget)
  }

  Modal.prototype.show = function (_relatedTarget) {
    var that = this
    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })

    this.$element.trigger(e)

    if (this.isShown || e.isDefaultPrevented()) return

    this.isShown = true

    this.checkScrollbar()
    this.setScrollbar()
    this.$body.addClass('modal-open')

    this.escape()
    this.resize()

    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))

    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
      })
    })

    this.backdrop(function () {
      var transition = $.support.transition && that.$element.hasClass('fade')

      if (!that.$element.parent().length) {
        that.$element.appendTo(that.$body) // don't move modals dom position
      }

      that.$element
        .show()
        .scrollTop(0)

      that.adjustDialog()

      if (transition) {
        that.$element[0].offsetWidth // force reflow
      }

      that.$element
        .addClass('in')
        .attr('aria-hidden', false)

      that.enforceFocus()

      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })

      transition ?
        that.$dialog // wait for modal to slide in
          .one('bsTransitionEnd', function () {
            that.$element.trigger('focus').trigger(e)
          })
          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
        that.$element.trigger('focus').trigger(e)
    })
  }

  Modal.prototype.hide = function (e) {
    if (e) e.preventDefault()

    e = $.Event('hide.bs.modal')

    this.$element.trigger(e)

    if (!this.isShown || e.isDefaultPrevented()) return

    this.isShown = false

    this.escape()
    this.resize()

    $(document).off('focusin.bs.modal')

    this.$element
      .removeClass('in')
      .attr('aria-hidden', true)
      .off('click.dismiss.bs.modal')
      .off('mouseup.dismiss.bs.modal')

    this.$dialog.off('mousedown.dismiss.bs.modal')

    $.support.transition && this.$element.hasClass('fade') ?
      this.$element
        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
      this.hideModal()
  }

  Modal.prototype.enforceFocus = function () {
    $(document)
      .off('focusin.bs.modal') // guard against infinite focus loop
      .on('focusin.bs.modal', $.proxy(function (e) {
        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
          this.$element.trigger('focus')
        }
      }, this))
  }

  Modal.prototype.escape = function () {
    if (this.isShown && this.options.keyboard) {
      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
        e.which == 27 && this.hide()
      }, this))
    } else if (!this.isShown) {
      this.$element.off('keydown.dismiss.bs.modal')
    }
  }

  Modal.prototype.resize = function () {
    if (this.isShown) {
      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
    } else {
      $(window).off('resize.bs.modal')
    }
  }

  Modal.prototype.hideModal = function () {
    var that = this
    this.$element.hide()
    this.backdrop(function () {
      that.$body.removeClass('modal-open')
      that.resetAdjustments()
      that.resetScrollbar()
      that.$element.trigger('hidden.bs.modal')
    })
  }

  Modal.prototype.removeBackdrop = function () {
    this.$backdrop && this.$backdrop.remove()
    this.$backdrop = null
  }

  Modal.prototype.backdrop = function (callback) {
    var that = this
    var animate = this.$element.hasClass('fade') ? 'fade' : ''

    if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate

      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
        .appendTo(this.$body)

      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
        if (this.ignoreBackdropClick) {
          this.ignoreBackdropClick = false
          return
        }
        if (e.target !== e.currentTarget) return
        this.options.backdrop == 'static'
          ? this.$element[0].focus()
          : this.hide()
      }, this))

      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow

      this.$backdrop.addClass('in')

      if (!callback) return

      doAnimate ?
        this.$backdrop
          .one('bsTransitionEnd', callback)
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
        callback()

    } else if (!this.isShown && this.$backdrop) {
      this.$backdrop.removeClass('in')

      var callbackRemove = function () {
        that.removeBackdrop()
        callback && callback()
      }
      $.support.transition && this.$element.hasClass('fade') ?
        this.$backdrop
          .one('bsTransitionEnd', callbackRemove)
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
        callbackRemove()

    } else if (callback) {
      callback()
    }
  }

  // these following methods are used to handle overflowing modals

  Modal.prototype.handleUpdate = function () {
    this.adjustDialog()
  }

  Modal.prototype.adjustDialog = function () {
    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight

    this.$element.css({
      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
    })
  }

  Modal.prototype.resetAdjustments = function () {
    this.$element.css({
      paddingLeft: '',
      paddingRight: ''
    })
  }

  Modal.prototype.checkScrollbar = function () {
    var fullWindowWidth = window.innerWidth
    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
      var documentElementRect = document.documentElement.getBoundingClientRect()
      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
    }
    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
    this.scrollbarWidth = this.measureScrollbar()
  }

  Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    this.originalBodyPad = document.body.style.paddingRight || ''
    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
  }

  Modal.prototype.resetScrollbar = function () {
    this.$body.css('padding-right', this.originalBodyPad)
  }

  Modal.prototype.measureScrollbar = function () { // thx walsh
    var scrollDiv = document.createElement('div')
    scrollDiv.className = 'modal-scrollbar-measure'
    this.$body.append(scrollDiv)
    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
    this.$body[0].removeChild(scrollDiv)
    return scrollbarWidth
  }


  // MODAL PLUGIN DEFINITION
  // =======================

  function Plugin(option, _relatedTarget) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.modal')
      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)

      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
      if (typeof option == 'string') data[option](_relatedTarget)
      else if (options.show) data.show(_relatedTarget)
    })
  }

  var old = $.fn.modal

  $.fn.modal             = Plugin
  $.fn.modal.Constructor = Modal


  // MODAL NO CONFLICT
  // =================

  $.fn.modal.noConflict = function () {
    $.fn.modal = old
    return this
  }


  // MODAL DATA-API
  // ==============

  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
    var $this   = $(this)
    var href    = $this.attr('href')
    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())

    if ($this.is('a')) e.preventDefault()

    $target.one('show.bs.modal', function (showEvent) {
      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
      $target.one('hidden.bs.modal', function () {
        $this.is(':visible') && $this.trigger('focus')
      })
    })
    Plugin.call($target, option, this)
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: tooltip.js v3.3.4
 * http://getbootstrap.com/javascript/#tooltip
 * Inspired by the original jQuery.tipsy by Jason Frame
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // TOOLTIP PUBLIC CLASS DEFINITION
  // ===============================

  var Tooltip = function (element, options) {
    this.type       = null
    this.options    = null
    this.enabled    = null
    this.timeout    = null
    this.hoverState = null
    this.$element   = null

    this.init('tooltip', element, options)
  }

  Tooltip.VERSION  = '3.3.4'

  Tooltip.TRANSITION_DURATION = 150

  Tooltip.DEFAULTS = {
    animation: true,
    placement: 'top',
    selector: false,
    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
    trigger: 'hover focus',
    title: '',
    delay: 0,
    html: false,
    container: false,
    viewport: {
      selector: 'body',
      padding: 0
    }
  }

  Tooltip.prototype.init = function (type, element, options) {
    this.enabled   = true
    this.type      = type
    this.$element  = $(element)
    this.options   = this.getOptions(options)
    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)

    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
    }

    var triggers = this.options.trigger.split(' ')

    for (var i = triggers.length; i--;) {
      var trigger = triggers[i]

      if (trigger == 'click') {
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
      } else if (trigger != 'manual') {
        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'

        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
      }
    }

    this.options.selector ?
      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
      this.fixTitle()
  }

  Tooltip.prototype.getDefaults = function () {
    return Tooltip.DEFAULTS
  }

  Tooltip.prototype.getOptions = function (options) {
    options = $.extend({}, this.getDefaults(), this.$element.data(), options)

    if (options.delay && typeof options.delay == 'number') {
      options.delay = {
        show: options.delay,
        hide: options.delay
      }
    }

    return options
  }

  Tooltip.prototype.getDelegateOptions = function () {
    var options  = {}
    var defaults = this.getDefaults()

    this._options && $.each(this._options, function (key, value) {
      if (defaults[key] != value) options[key] = value
    })

    return options
  }

  Tooltip.prototype.enter = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget).data('bs.' + this.type)

    if (self && self.$tip && self.$tip.is(':visible')) {
      self.hoverState = 'in'
      return
    }

    if (!self) {
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
      $(obj.currentTarget).data('bs.' + this.type, self)
    }

    clearTimeout(self.timeout)

    self.hoverState = 'in'

    if (!self.options.delay || !self.options.delay.show) return self.show()

    self.timeout = setTimeout(function () {
      if (self.hoverState == 'in') self.show()
    }, self.options.delay.show)
  }

  Tooltip.prototype.leave = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget).data('bs.' + this.type)

    if (!self) {
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
      $(obj.currentTarget).data('bs.' + this.type, self)
    }

    clearTimeout(self.timeout)

    self.hoverState = 'out'

    if (!self.options.delay || !self.options.delay.hide) return self.hide()

    self.timeout = setTimeout(function () {
      if (self.hoverState == 'out') self.hide()
    }, self.options.delay.hide)
  }

  Tooltip.prototype.show = function () {
    var e = $.Event('show.bs.' + this.type)

    if (this.hasContent() && this.enabled) {
      this.$element.trigger(e)

      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
      if (e.isDefaultPrevented() || !inDom) return
      var that = this

      var $tip = this.tip()

      var tipId = this.getUID(this.type)

      this.setContent()
      $tip.attr('id', tipId)
      this.$element.attr('aria-describedby', tipId)

      if (this.options.animation) $tip.addClass('fade')

      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, $tip[0], this.$element[0]) :
        this.options.placement

      var autoToken = /\s?auto?\s?/i
      var autoPlace = autoToken.test(placement)
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'

      $tip
        .detach()
        .css({ top: 0, left: 0, display: 'block' })
        .addClass(placement)
        .data('bs.' + this.type, this)

      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)

      var pos          = this.getPosition()
      var actualWidth  = $tip[0].offsetWidth
      var actualHeight = $tip[0].offsetHeight

      if (autoPlace) {
        var orgPlacement = placement
        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()
        var containerDim = this.getPosition($container)

        placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top'    :
                    placement == 'top'    && pos.top    - actualHeight < containerDim.top    ? 'bottom' :
                    placement == 'right'  && pos.right  + actualWidth  > containerDim.width  ? 'left'   :
                    placement == 'left'   && pos.left   - actualWidth  < containerDim.left   ? 'right'  :
                    placement

        $tip
          .removeClass(orgPlacement)
          .addClass(placement)
      }

      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)

      this.applyPlacement(calculatedOffset, placement)

      var complete = function () {
        var prevHoverState = that.hoverState
        that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        $tip
          .one('bsTransitionEnd', complete)
          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
        complete()
    }
  }

  Tooltip.prototype.applyPlacement = function (offset, placement) {
    var $tip   = this.tip()
    var width  = $tip[0].offsetWidth
    var height = $tip[0].offsetHeight

    // manually read margins because getBoundingClientRect includes difference
    var marginTop = parseInt($tip.css('margin-top'), 10)
    var marginLeft = parseInt($tip.css('margin-left'), 10)

    // we must check for NaN for ie 8/9
    if (isNaN(marginTop))  marginTop  = 0
    if (isNaN(marginLeft)) marginLeft = 0

    offset.top  = offset.top  + marginTop
    offset.left = offset.left + marginLeft

    // $.fn.offset doesn't round pixel values
    // so we use setOffset directly with our own function B-0
    $.offset.setOffset($tip[0], $.extend({
      using: function (props) {
        $tip.css({
          top: Math.round(props.top),
          left: Math.round(props.left)
        })
      }
    }, offset), 0)

    $tip.addClass('in')

    // check to see if placing tip in new offset caused the tip to resize itself
    var actualWidth  = $tip[0].offsetWidth
    var actualHeight = $tip[0].offsetHeight

    if (placement == 'top' && actualHeight != height) {
      offset.top = offset.top + height - actualHeight
    }

    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)

    if (delta.left) offset.left += delta.left
    else offset.top += delta.top

    var isVertical          = /top|bottom/.test(placement)
    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'

    $tip.offset(offset)
    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
  }

  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
    this.arrow()
      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
      .css(isVertical ? 'top' : 'left', '')
  }

  Tooltip.prototype.setContent = function () {
    var $tip  = this.tip()
    var title = this.getTitle()

    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
    $tip.removeClass('fade in top bottom left right')
  }

  Tooltip.prototype.hide = function (callback) {
    var that = this
    var $tip = $(this.$tip)
    var e    = $.Event('hide.bs.' + this.type)

    function complete() {
      if (that.hoverState != 'in') $tip.detach()
      that.$element
        .removeAttr('aria-describedby')
        .trigger('hidden.bs.' + that.type)
      callback && callback()
    }

    this.$element.trigger(e)

    if (e.isDefaultPrevented()) return

    $tip.removeClass('in')

    $.support.transition && $tip.hasClass('fade') ?
      $tip
        .one('bsTransitionEnd', complete)
        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
      complete()

    this.hoverState = null

    return this
  }

  Tooltip.prototype.fixTitle = function () {
    var $e = this.$element
    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
    }
  }

  Tooltip.prototype.hasContent = function () {
    return this.getTitle()
  }

  Tooltip.prototype.getPosition = function ($element) {
    $element   = $element || this.$element

    var el     = $element[0]
    var isBody = el.tagName == 'BODY'

    var elRect    = el.getBoundingClientRect()
    if (elRect.width == null) {
      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
    }
    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null

    return $.extend({}, elRect, scroll, outerDims, elOffset)
  }

  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }

  }

  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
    var delta = { top: 0, left: 0 }
    if (!this.$viewport) return delta

    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
    var viewportDimensions = this.getPosition(this.$viewport)

    if (/right|left/.test(placement)) {
      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
      if (topEdgeOffset < viewportDimensions.top) { // top overflow
        delta.top = viewportDimensions.top - topEdgeOffset
      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
      }
    } else {
      var leftEdgeOffset  = pos.left - viewportPadding
      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
        delta.left = viewportDimensions.left - leftEdgeOffset
      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
      }
    }

    return delta
  }

  Tooltip.prototype.getTitle = function () {
    var title
    var $e = this.$element
    var o  = this.options

    title = $e.attr('data-original-title')
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)

    return title
  }

  Tooltip.prototype.getUID = function (prefix) {
    do prefix += ~~(Math.random() * 1000000)
    while (document.getElementById(prefix))
    return prefix
  }

  Tooltip.prototype.tip = function () {
    return (this.$tip = this.$tip || $(this.options.template))
  }

  Tooltip.prototype.arrow = function () {
    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
  }

  Tooltip.prototype.enable = function () {
    this.enabled = true
  }

  Tooltip.prototype.disable = function () {
    this.enabled = false
  }

  Tooltip.prototype.toggleEnabled = function () {
    this.enabled = !this.enabled
  }

  Tooltip.prototype.toggle = function (e) {
    var self = this
    if (e) {
      self = $(e.currentTarget).data('bs.' + this.type)
      if (!self) {
        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
        $(e.currentTarget).data('bs.' + this.type, self)
      }
    }

    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
  }

  Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
    })
  }


  // TOOLTIP PLUGIN DEFINITION
  // =========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.tooltip')
      var options = typeof option == 'object' && option

      if (!data && /destroy|hide/.test(option)) return
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.tooltip

  $.fn.tooltip             = Plugin
  $.fn.tooltip.Constructor = Tooltip


  // TOOLTIP NO CONFLICT
  // ===================

  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
    return this
  }

}(jQuery);

/* ========================================================================
 * Bootstrap: popover.js v3.3.4
 * http://getbootstrap.com/javascript/#popovers
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // POPOVER PUBLIC CLASS DEFINITION
  // ===============================

  var Popover = function (element, options) {
    this.init('popover', element, options)
  }

  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')

  Popover.VERSION  = '3.3.4'

  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
    placement: 'right',
    trigger: 'click',
    content: '',
    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
  })


  // NOTE: POPOVER EXTENDS tooltip.js
  // ================================

  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)

  Popover.prototype.constructor = Popover

  Popover.prototype.getDefaults = function () {
    return Popover.DEFAULTS
  }

  Popover.prototype.setContent = function () {
    var $tip    = this.tip()
    var title   = this.getTitle()
    var content = this.getContent()

    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
    ](content)

    $tip.removeClass('fade top bottom left right in')

    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
    // this manually by checking the contents.
    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
  }

  Popover.prototype.hasContent = function () {
    return this.getTitle() || this.getContent()
  }

  Popover.prototype.getContent = function () {
    var $e = this.$element
    var o  = this.options

    return $e.attr('data-content')
      || (typeof o.content == 'function' ?
            o.content.call($e[0]) :
            o.content)
  }

  Popover.prototype.arrow = function () {
    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
  }


  // POPOVER PLUGIN DEFINITION
  // =========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.popover')
      var options = typeof option == 'object' && option

      if (!data && /destroy|hide/.test(option)) return
      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.popover

  $.fn.popover             = Plugin
  $.fn.popover.Constructor = Popover


  // POPOVER NO CONFLICT
  // ===================

  $.fn.popover.noConflict = function () {
    $.fn.popover = old
    return this
  }

}(jQuery);

/* ========================================================================
 * Bootstrap: scrollspy.js v3.3.4
 * http://getbootstrap.com/javascript/#scrollspy
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
  // ==========================

  function ScrollSpy(element, options) {
    this.$body          = $(document.body)
    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target || '') + ' .nav li > a'
    this.offsets        = []
    this.targets        = []
    this.activeTarget   = null
    this.scrollHeight   = 0

    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
    this.refresh()
    this.process()
  }

  ScrollSpy.VERSION  = '3.3.4'

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.getScrollHeight = function () {
    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
  }

  ScrollSpy.prototype.refresh = function () {
    var that          = this
    var offsetMethod  = 'offset'
    var offsetBase    = 0

    this.offsets      = []
    this.targets      = []
    this.scrollHeight = this.getScrollHeight()

    if (!$.isWindow(this.$scrollElement[0])) {
      offsetMethod = 'position'
      offsetBase   = this.$scrollElement.scrollTop()
    }

    this.$body
      .find(this.selector)
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#./.test(href) && $(href)

        return ($href
          && $href.length
          && $href.is(':visible')
          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        that.offsets.push(this[0])
        that.targets.push(this[1])
      })
  }

  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.getScrollHeight()
    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i

    if (this.scrollHeight != scrollHeight) {
      this.refresh()
    }

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
    }

    if (activeTarget && scrollTop < offsets[0]) {
      this.activeTarget = null
      return this.clear()
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
        && this.activate(targets[i])
    }
  }

  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target

    this.clear()

    var selector = this.selector +
      '[data-target="' + target + '"],' +
      this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }

  ScrollSpy.prototype.clear = function () {
    $(this.selector)
      .parentsUntil(this.options.target, '.active')
      .removeClass('active')
  }


  // SCROLLSPY PLUGIN DEFINITION
  // ===========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.scrollspy

  $.fn.scrollspy             = Plugin
  $.fn.scrollspy.Constructor = ScrollSpy


  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
  }


  // SCROLLSPY DATA-API
  // ==================

  $(window).on('load.bs.scrollspy.data-api', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      Plugin.call($spy, $spy.data())
    })
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: tab.js v3.3.4
 * http://getbootstrap.com/javascript/#tabs
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // TAB CLASS DEFINITION
  // ====================

  var Tab = function (element) {
    this.element = $(element)
  }

  Tab.VERSION = '3.3.4'

  Tab.TRANSITION_DURATION = 150

  Tab.prototype.show = function () {
    var $this    = this.element
    var $ul      = $this.closest('ul:not(.dropdown-menu)')
    var selector = $this.data('target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    if ($this.parent('li').hasClass('active')) return

    var $previous = $ul.find('.active:last a')
    var hideEvent = $.Event('hide.bs.tab', {
      relatedTarget: $this[0]
    })
    var showEvent = $.Event('show.bs.tab', {
      relatedTarget: $previous[0]
    })

    $previous.trigger(hideEvent)
    $this.trigger(showEvent)

    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return

    var $target = $(selector)

    this.activate($this.closest('li'), $ul)
    this.activate($target, $target.parent(), function () {
      $previous.trigger({
        type: 'hidden.bs.tab',
        relatedTarget: $this[0]
      })
      $this.trigger({
        type: 'shown.bs.tab',
        relatedTarget: $previous[0]
      })
    })
  }

  Tab.prototype.activate = function (element, container, callback) {
    var $active    = container.find('> .active')
    var transition = callback
      && $.support.transition
      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)

    function next() {
      $active
        .removeClass('active')
        .find('> .dropdown-menu > .active')
          .removeClass('active')
        .end()
        .find('[data-toggle="tab"]')
          .attr('aria-expanded', false)

      element
        .addClass('active')
        .find('[data-toggle="tab"]')
          .attr('aria-expanded', true)

      if (transition) {
        element[0].offsetWidth // reflow for transition
        element.addClass('in')
      } else {
        element.removeClass('fade')
      }

      if (element.parent('.dropdown-menu').length) {
        element
          .closest('li.dropdown')
            .addClass('active')
          .end()
          .find('[data-toggle="tab"]')
            .attr('aria-expanded', true)
      }

      callback && callback()
    }

    $active.length && transition ?
      $active
        .one('bsTransitionEnd', next)
        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
      next()

    $active.removeClass('in')
  }


  // TAB PLUGIN DEFINITION
  // =====================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.tab')

      if (!data) $this.data('bs.tab', (data = new Tab(this)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.tab

  $.fn.tab             = Plugin
  $.fn.tab.Constructor = Tab


  // TAB NO CONFLICT
  // ===============

  $.fn.tab.noConflict = function () {
    $.fn.tab = old
    return this
  }


  // TAB DATA-API
  // ============

  var clickHandler = function (e) {
    e.preventDefault()
    Plugin.call($(this), 'show')
  }

  $(document)
    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)

}(jQuery);

/* ========================================================================
 * Bootstrap: affix.js v3.3.4
 * http://getbootstrap.com/javascript/#affix
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // AFFIX CLASS DEFINITION
  // ======================

  var Affix = function (element, options) {
    this.options = $.extend({}, Affix.DEFAULTS, options)

    this.$target = $(this.options.target)
      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))

    this.$element     = $(element)
    this.affixed      = null
    this.unpin        = null
    this.pinnedOffset = null

    this.checkPosition()
  }

  Affix.VERSION  = '3.3.4'

  Affix.RESET    = 'affix affix-top affix-bottom'

  Affix.DEFAULTS = {
    offset: 0,
    target: window
  }

  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
    var scrollTop    = this.$target.scrollTop()
    var position     = this.$element.offset()
    var targetHeight = this.$target.height()

    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false

    if (this.affixed == 'bottom') {
      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
    }

    var initializing   = this.affixed == null
    var colliderTop    = initializing ? scrollTop : position.top
    var colliderHeight = initializing ? targetHeight : height

    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'

    return false
  }

  Affix.prototype.getPinnedOffset = function () {
    if (this.pinnedOffset) return this.pinnedOffset
    this.$element.removeClass(Affix.RESET).addClass('affix')
    var scrollTop = this.$target.scrollTop()
    var position  = this.$element.offset()
    return (this.pinnedOffset = position.top - scrollTop)
  }

  Affix.prototype.checkPositionWithEventLoop = function () {
    setTimeout($.proxy(this.checkPosition, this), 1)
  }

  Affix.prototype.checkPosition = function () {
    if (!this.$element.is(':visible')) return

    var height       = this.$element.height()
    var offset       = this.options.offset
    var offsetTop    = offset.top
    var offsetBottom = offset.bottom
    var scrollHeight = $(document.body).height()

    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)

    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)

    if (this.affixed != affix) {
      if (this.unpin != null) this.$element.css('top', '')

      var affixType = 'affix' + (affix ? '-' + affix : '')
      var e         = $.Event(affixType + '.bs.affix')

      this.$element.trigger(e)

      if (e.isDefaultPrevented()) return

      this.affixed = affix
      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null

      this.$element
        .removeClass(Affix.RESET)
        .addClass(affixType)
        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
    }

    if (affix == 'bottom') {
      this.$element.offset({
        top: scrollHeight - height - offsetBottom
      })
    }
  }


  // AFFIX PLUGIN DEFINITION
  // =======================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.affix')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.affix

  $.fn.affix             = Plugin
  $.fn.affix.Constructor = Affix


  // AFFIX NO CONFLICT
  // =================

  $.fn.affix.noConflict = function () {
    $.fn.affix = old
    return this
  }


  // AFFIX DATA-API
  // ==============

  $(window).on('load', function () {
    $('[data-spy="affix"]').each(function () {
      var $spy = $(this)
      var data = $spy.data()

      data.offset = data.offset || {}

      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
      if (data.offsetTop    != null) data.offset.top    = data.offsetTop

      Plugin.call($spy, data)
    })
  })

}(jQuery);

Added modules/bootstrap/js/bootstrap.min.js.















>
>
>
>
>
>
>
1
2
3
4
5
6
7
/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="menu"]',g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class="modal-backdrop '+e+'" />').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){
var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);

Added modules/bootstrap/js/jquery.min.js.









>
>
>
>
1
2
3
4
/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=mb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=nb(b);function qb(){}qb.prototype=d.filters=d.pseudos,d.setFilters=new qb,g=gb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?gb.error(a):z(a,i).slice(0)};function rb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)
},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec=/#.*$/,fc=/([?&])_=[^&]*/,gc=/^(.*?):[ \t]*([^\r\n]*)$/gm,hc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ic=/^(?:GET|HEAD)$/,jc=/^\/\//,kc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lc={},mc={},nc="*/".concat("*"),oc=a.location.href,pc=kc.exec(oc.toLowerCase())||[];function qc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rc(a,b,c,d){var e={},f=a===mc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function uc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:oc,type:"GET",isLocal:hc.test(pc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sc(sc(a,n.ajaxSettings),b):sc(n.ajaxSettings,a)},ajaxPrefilter:qc(lc),ajaxTransport:qc(mc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gc.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||oc)+"").replace(ec,"").replace(jc,pc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pc[1]&&h[2]===pc[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pc[3]||("http:"===pc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rc(lc,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ic.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fc.test(d)?d.replace(fc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rc(mc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tc(k,v,f)),u=uc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vc=/%20/g,wc=/\[\]$/,xc=/\r?\n/g,yc=/^(?:submit|button|image|reset|file)$/i,zc=/^(?:input|select|textarea|keygen)/i;function Ac(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wc.test(a)?d(a,e):Ac(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ac(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ac(c,a[c],b,e);return d.join("&").replace(vc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zc.test(this.nodeName)&&!yc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xc,"\r\n")}}):{name:b.name,value:c.replace(xc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bc=0,Cc={},Dc={0:200,1223:204},Ec=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cc)Cc[a]()}),k.cors=!!Ec&&"withCredentials"in Ec,k.ajax=Ec=!!Ec,n.ajaxTransport(function(a){var b;return k.cors||Ec&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Dc[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fc=[],Gc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hc)return Hc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ic=a.document.documentElement;function Jc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ic;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ic})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kc=a.jQuery,Lc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lc),b&&a.jQuery===n&&(a.jQuery=Kc),n},typeof b===U&&(a.jQuery=a.$=n),n});

Added modules/bootstrap/js/npm.js.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
require('../../js/transition.js')
require('../../js/alert.js')
require('../../js/button.js')
require('../../js/carousel.js')
require('../../js/collapse.js')
require('../../js/dropdown.js')
require('../../js/modal.js')
require('../../js/tooltip.js')
require('../../js/popover.js')
require('../../js/scrollspy.js')
require('../../js/tab.js')
require('../../js/affix.js')

Added modules/bootstrap/pkgIndex.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd::bootstrap 0.1 [list source [file join $dir bootstrap.tcl]]

Added modules/community/acl.md.

Added modules/community/acl.tcl.

Added modules/community/community.md.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
*httpd.community* is a decendent of . It adds an sqlite based user, group, and access control system. It is implemented in [community.tcl](finfo?name=modules/community/community.tcl).

## Ancestors

* [httpd.taourl](../directoo/taourl.md)
* [yggdrasil](../tao-sqlite/yggdrasil.md)

## Required Packages

Community relies on the following external packages:

* sha1 from [tcllib](http://core.tcl.tk/tcllib)
* sqlite3 from [sqlite](http://www.sqlite.org)

Community uses the following internal packages:

* tao from [tao](../tao/tao.md)
* tao-sqlite [tao-sqlite](../tao-sqlite/tao-sqlite.md)

## Properties

* create\_sql - An SQL script that implements the schema

## Options

* filename - Path to a file which stores the sqlite database for the community (default in-memory)
* virtual - Root Url of this object.

## Attached Objects

Community objects (and their derived classes) contain an embedded sqlite
database. This database can be accessed via that \<db\> method.

## Methods

### method Database\_Functions

Adds the following functions to the database:

* uuid\_generate() - Generates sha1 UUIDs on demand
* sha1() - Returns the SHA1 hash of the input

### aclAccessTypes

Returns a list of all possible rights.

### aclRights *aclname* *user\_or\_group\_id*

Return a list of rights that the user or group to the access control list (specified by name.)

### method httpdSessionLoad *sock* *prefix* *suffix*

This method looks for a sessionid cookie or a sessionid field in the GET or POST query, and
pairs it with a session in the *session* table. If no session is found, a new session is generated
for an anonymous user.

### method httpdSessionSave *sock*

This method compares the current value of **result\(session\)** to **result\(session\_delta\)** (a copy
of the session when the pageview began. Fields that are in the delta, but not in the current session are delete
from **session\_property**. Fields that are present in the session but not the delta are inserted into
**session\_property**. Fields present in both, but with a different value, are updated.

The server will generate a cookie called **sessionid** which will be loaded on the next page view.

Added modules/community/community.tcl.





























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
###
# Facilities for user, group, and community management
###
package require tao
package require sqlite3
package require tao-sqlite
package require md5 2
package require sha1 2

package require httpd::directoo
package require httpd::cookie	;# Cookie_GetSock Cookie_Make
package require httpd::doc	;# Doc_Root
package require httpd::utils	;# Stderr file iscommand randomx
package require httpd::jshash   ;# Javascript password hashes
package require httpd::bootstrap
package require cron

tao::class community.layer {
  superclass httpd.url tao::layer taodb::table

  ###
  # Code to produce the schema in sql
  ###
  property schema create_sql {}
  property schema version 0.1
  property module {}
  
  constructor {sharedobjects threadargs args} {
    foreach {organ object} $sharedobjects {
      my graft $organ $object
    }
    my graft layer [self]
    my configurelist [::tao::args_to_options {*}$args]
    ::Url_PrefixInstall [my cget virtual] [namespace code {my httpdDirect}] {*}$threadargs
  }
  
  destructor {
    catch {::Url_PrefixRemove [my cget virtual]}
  }
  
  method schema_check {} {
    set module [my property module]
    set version [my property schema version]
    ###
    # Create our schema if it doesn't exist
    ###
    if {![my <db> exists {select version from module where name=:module}]} {
      my <db> eval [my property schema create_sql]
      my <db> eval {insert or replace into module(name,version) VALUES (:module,:version)}
      # Send a signal to child classes calling us through [next]
      return 1
    }
    ###
    # From here on out, swap out components to incrementally update
    # the schema
    ###
    return 0
  }
  
  method initialize {} {
    my schema_check
  }

  #
  #	Use the url prefix, suffix, and cgi values (set with the
  #	ncgi package) to create a Tcl command line to invoke.
  #
  # Arguments:
  #	suffix		The part of the url after the domain prefix.
  #
  # Results:
  #	Returns a Tcl command line.
  #
  # Side effects:
  #	If the suffix (and query args) do not map to a Tcl procedure,
  #	returns empty string.
  method httpdMarshalArguments resultObj {
    set prefix [$resultObj cget url_prefix]
    set suffix [$resultObj cget url_suffix]
    set uuid {}
    if { $suffix in {/ {}} } {
      set method /html
    } else {
      set parts [split [string trim $suffix /] /]
      set uuid [lindex $parts 0]
      set method /html/[join [lrange $parts 1 end] /]
    }
    set pkey  [my property schema primary_key]
    foreach {name value} [$resultObj query] {
      if { $name in [list uuid $pkey]} {
        set uuid $value
      }
      if { $name eq "method" } {
        set method /html/$value
        break
      }
    }
    if {$uuid ne {}} {
      resultObj configure uuid $uuid
    }
    return [list my $method $resultObj]
  }
  
  ###
  # topic: 88c79c0e9188a477f535b66b01631961
  ###
  method node_is_managed unit {
    set prefix [my cget prefix]
    if { $unit eq $prefix } {
      return 1
    }
    set table [my property schema table]
    set pkey  [my property schema primary_key]
    return [my <db> exists "select $pkey from $table where $pkey=:unit"]
  }
  
  ###
  # Return a command if this object hijacks a method
  # from the community
  ###
  method url_is_managed resultObj {
   return {}
  }
  
  method task_hourly {} {}
  method task_daily {} {}
  
  method /html resultObj {
    $resultObj puts [my <community> pageHeader]
    $resultObj puts "Node: [$resultObj cget uuid]
    $resultObj puts [my <community> pageFooter]
  }
}

tao::class community.layer.user {
  superclass community.layer

  property module user
  property schema version 1.0  
  property schema table users
  property schema primary_key userid
  property schema create_sql {
    CREATE TABLE if not exists users (
      userid string default (uuid_generate()),
      username  STRING,
      password  STRING,
      name  STRING,
      email  STRING,
      type  STRING,
      primary key (userid)
    );
    CREATE UNIQUE INDEX if not exists username  on users (username);
    
    create table if not exists user_property (
      userid    string references users (userid) ON UPDATE CASCADE ON DELETE CASCADE,
      field      string,
      value      string,
      primary key (userid,field)
    );
insert into users(userid,username,password) VALUES ('local.webmaster','webmaster',sha1((select value from config where name='community-id')||'password'));
insert into users(userid,username,password) VALUES ('local.anonymous','anonymous','');  
  }
  
  method /html resultObj {    
    set uuid [$resultObj cget uuid]
    set method [lindex $parts 1]
    
    set props [my <db> eval {select field,value from user_property where userid=:uuid}]
    my <db> eval {select * from users where userid=:uuid} record break
    $resultObj configure title "User $record(username)"
    $resultObj puts [my <community> pageHeader]    
    $resultObj puts "<TABLE>"
    foreach {field value} [array get record] {
      $resultObj puts "<TR><TH>$field</TH><TD>$value</TD></TR>"
    }    
    foreach {field value} $props {
      $resultObj puts "<TR><TH>$field</TH><TD>$value</TD></TR>"
    }
    my <db> eval {select distinct acl_name from acl} {
      $resultObj puts "<TR><TH>Rights $acl_name</TH><Td>[my aclRights $acl_name $record(userid)]</TD></TR>"
    }
    $resultObj puts "</TABLE>"
    $resultObj puts <hr>
    $resultObj puts "<hr>Session<p>"
    $resultObj puts "<TABLE>"
    foreach {field value} [$resultObj session dump] {
      $resultObj puts "<TR><TH>$field</TH><TD>$value</TD></TR>"
    }
    $resultObj puts "</TABLE>"
    $resultObj puts "<hr>ENV<p>"
    $resultObj puts "<TABLE>"
    foreach {field value} [$resultObj cgi dump] {
      $resultObj puts "<TR><TH>$field</TH><TD>$value</TD></TR>"
    }
    $resultObj puts "</TABLE>"
    $resultObj puts [my <community> pageFooter]    

  }
  

}

tao::class community.layer.group {
 superclass community.layer

  property module group
  property schema version 1.0  
  property schema table groups
  property schema primary_key groupid
  property schema create_sql {
    CREATE TABLE if not exists groups (
      groupid string default (uuid_generate()),
      groupname STRING,
      acl_name  string references acl (acl_name) ON UPDATE CASCADE ON DELETE SET NULL,
      primary key (groupid)
    );
    CREATE TABLE if not exists group_members (
      groupid string references groups (groupid) ON UPDATE CASCADE ON DELETE CASCADE,
      userid string references users (userid) ON UPDATE CASCADE ON DELETE CASCADE
    );
    create table if not exists group_property (
      groupid    string references groups (groupid) ON UPDATE CASCADE ON DELETE CASCADE,
      field      string,
      value      string,
      primary key (groupid,field)
    );
insert into groups(groupid,groupname) VALUES ('local.wheel','wheel');
insert into group_members(userid,groupid) VALUES ('local.webmaster','local.wheel');
  }
}

tao::class community.layer.session {
  superclass community.layer
  property module session

  property module session
  property schema version 1.0  
  property schema table session
  property schema primary_key sesid
  
  property schema create_sql {
    CREATE TABLE session (
      sesid string default (uuid_generate()),
      userid string references users (userid) ON UPDATE CASCADE ON DELETE CASCADE,
      expires   int,
      primary key (sesid)
    );
    
    create table if not exists session_property (
      sesid    string references session (sesid) ON UPDATE CASCADE ON DELETE CASCADE,
      field      string,
      value      string,
      primary key (sesid,field)
    );
  }
  
  method task_hourly {} {
    set now [clock seconds]
    my <db> eval {delete from session where expires<:now;}
  }
}

tao::class community.layer.acl {
  superclass community.layer
  property module acl

  property module acl
  property schema version 1.0  
  property schema table acl
  property schema primary_key acl_name
  
  property schema create_sql {
    CREATE TABLE acl (
    parent   string references acl (acl_name) ON UPDATE CASCADE ON DELETE SET NULL,
    acl_name text not null,
    primary key (acl_name)
    );
    CREATE TABLE acl_grants (
    acl_name  string references acl (acl_name) ON UPDATE CASCADE ON DELETE SET NULL,
    userid    string references users (userid) ON UPDATE CASCADE ON DELETE SET NULL,
    grant     int default 1,
    right     text,
    UNIQUE (acl_name,userid,right)
    );
    
insert into acl (acl_name) VALUES ('admin');
insert into acl_grants (acl_name,userid,grant,right) VALUES ('admin','local.wheel',1,'all');

insert into acl (acl_name) VALUES ('default');
insert into acl_grants (acl_name,userid,grant,right) VALUES ('default',NULL,1,'view');
  }
}

tao::class httpd.community {  
  superclass httpd.url taodb::connection.sqlite
  
  option virtual {}
  option community-id {}

  ###
  # This class extents the yggdrasil schema to
  # include session management, user management,
  # and access control lists
  ###
  property schema create_sql {
    CREATE TABLE if not exists config(
      name TEXT PRIMARY KEY,
      value ANY
    );
    CREATE TABLE if not exists module(
      name TEXT PRIMARY KEY,
      version ANY
    );
--- POPULATE WITH DATA ---
insert into config(name,value) VALUES ('community-id',uuid_generate());
  }
  
  destructor {
    next
    cron::cancel [self].session_flush
    cron::cancel [self].backup_db
  }
  
  method Shared_Organs {} {
    set shared {}
    dict set shared db [my organ db]
    dict set shared community [self]
    return $shared
  }
  
  method active_layers {} {
    return {
      user    {prefix uid class community.layer.user}
      group   {prefix gid class community.layer.group}
      session {prefix sesid class community.layer.session}
      acl     {prefix acl class community.layer.acl}
    }
  }

  ###
  # topic: 81232b0943dce1f2586e0ac6159b1e2e
  ###
  method activate_layers {{force 0}} {
    set self [self]
    my variable layers
    set result {}
    set active [my active_layers]

    ###
    # Destroy any layers we are not using
    ###
    set lbefore [get layers]
    foreach {lname obj} $lbefore {
      if {![dict exists $active $lname] || $force} {
        $obj destroy
        dict unset layers $lname
      }
    }

    ###
    # Create or Morph the objects to represent
    # the layers, and then stitch them into
    # the application, and the application to
    # the layers
    ###
    set shared [my Shared_Organs]
    set root [my cget virtual]
    set threadargs [my cget threadargs]
    foreach {lname info} $active {
      set created 0
      set prefix [dict get $info prefix]
      set class  [dict get $info class]
      set layer_obj [my SubObject layer $lname]
      dict set layers $lname $layer_obj
      if {[info command $layer_obj] == {} } {
        $class create $layer_obj $shared $threadargs virtual $root/$prefix prefix $prefix layer_name $lname threadargs $threadargs
        set created 1
        foreach {organ object} $shared {
          $layer_obj graft $organ $object
        }
      } else {
        foreach {organ object} $shared {
          $layer_obj graft $organ $object
        }
        $layer_obj morph $class
      }
      ::ladd result $layer_obj
      $layer_obj event subscribe [self] *
      $layer_obj initialize
    }
    my action activate_layers
    return $result
  }

  method initialize {} {
    if {[my cget filename] eq {}} {
      my configure filename :memory:
    }
    my Database_Attach [my cget filename]
    my configurelist [my <db> eval {select name,value from config}]
    if {[my cget community-id] eq {}} {
      my configure community-id [::tao::uuid_generate]
    }
    my activate_layers
    ###
    # Clean up expired sessions
    ### 
    cron::every [self].hourly [expr {3600}] [namespace code {my task_hourly}]
    
    ###
    # Back up the database every day
    ###
    cron::every [self].daily [expr {3600*24}] [namespace code {my task_daily}]
  }

  method task_hourly {} {
    my variable layers
    foreach {name obj} $layers {
      $obj task_hourly
    }
  }
  
  method task_daily {} {
    my variable layers
    my Database_Backup
    foreach {name obj} $layers {
      $obj task_hourly
    }
  }
  
  method Database_Create {} {
    my <db> eval [my schema create_sql]
  }
  
  method ClockFormat {time {format {}}} {
    if { $format eq {} } {
      return [clock format $time]
    }
    return [clock format $time -format $format]
  }
  
  method ClockScan {time {format {}}} {
    if { $format eq {} } {
      return [clock format $time]
    }
    return [clock scan $time -format $format]
  }

  method Database_Functions {} {
    set seed [info hostname]
    my <db> function uuid_generate ::tao::uuid_generate
    my <db> function sha1    {::sha1::sha1 -hex}
    my <db> function now   {clock seconds}
    my <db> function clock_format [namespace code {my ClockFormat}]
    my <db> function clock_scan   [namespace code {my ClockScan}]

  }

  method aclAccessTypes {} {
    set aclAccessTypes {admin edit view}
    foreach type [my <db> eval "select distinct right from acl_grants order by right"] {
        logicset add aclAccessTypes $type
    }     
    return $aclAccessTypes    
  }

  method aclRights {aclname userid} {
    set parentlist {}
    set thisnode $aclname
    
    while 1 {
      set parentlist [linsert $parentlist 0 $thisnode]
      set parent [my one "select parent from acl where acl_name=:thisnode"]
      if { $parent == {} } { 
          break
      }
      # Something is mislinked, stop early
      if {$parent in $parentlist} break
      set thisnode $parent
    }
  
    ###
    #  Build grouplist
    ###
    set rights {}
    ###
    # Apply default rights
    ###
    foreach {right grant} [my <db> eval "select right,grant from acl_grants where acl_name='default'"] {
      if { $grant == "0"} {
          if { $right == "all" } { 
              set rights {}
          } else {
              logicset remove rights $right
          }
      } else {
        if { $right eq "all" } {
          logicset add rights {*}[my aclAccessTypes]
        } else {
          logicset add rights $right
        }
      }
    }
    
    foreach p $parentlist {
        set stmt "select right,grant from acl_grants where \
  acl_name=:p and userid=:userid or userid=(select username from users where userid=:userid) or userid in (select groupid from group_members where userid=:userid);
  "
      foreach {right grant} [my <db> eval $stmt] {
        if { $grant == "0"} {
            if { $right == "all" } { 
                set rights {}
            } else {
                logicset remove rights $right
            }
        } else {
          if { $right eq "all" } {
            logicset add rights {*}[my aclAccessTypes]
          } else {
            logicset add rights $right
          }
        }
      }
    }
    return $rights
  }
  
  #
  #	Use the url prefix, suffix, and cgi values (set with the
  #	ncgi package) to create a Tcl command line to invoke.
  #
  # Arguments:
  #	suffix		The part of the url after the domain prefix.
  #
  # Results:
  #	Returns a Tcl command line.
  #
  # Side effects:
  #	If the suffix (and query args) do not map to a Tcl procedure,
  #	returns empty string.
  method httpdMarshalArguments resultObj {
    my variable layers
    ###
    # Try to pass the page off to one of my layers
    ###
    foreach {lname layer} $layers {
      if {[set cmd [$layer url_is_managed $resultObj]] ne {}} {
        return $cmd
      }
    }
    ###
    # Otherwise look for a local method
    ###
    return [next $resultObj]
  }
  
  method httpdSessionLoad {resultObj prefix suffix} {
    set found 0
    set sessionid {}
    set userid    {}
    
    ###
    # Look for a session id in the query
    ###
    foreach {field value} [$resultObj query] {
      if {$field eq "sessionid"} {
        set stmt {select userid from session where sesid=:value}
        if {[my <db> exists $stmt]} {
          set userid [my <db> one $stmt]
          set sessionid $value
          break
        }
      }
    }
    if {$sessionid eq {}} {
      ###
      # Look for a sessionid in cookies
      ###
      foreach {value} [$resultObj cookie_get sessionid] {
        set stmt {select userid from session where sesid=:value}
        if {[my <db> exists $stmt]} {
          set userid [my <db> one $stmt]
          set sessionid $value
          break
        }
      }
    }
    if {![my <db> exists {select username from users where userid=:userid}]} {
      set userid local.anonymous
      set username anonymous
      set anonymous 1
    } else {
      set username [my <db> one {select username from users where userid=:userid}]
      if { $userid == "local.anonymous" } {
        set anonymous 1
      } else {
        set anonymous 0
      }
    }
    if {$sessionid eq {}} {
      set sessionid [::tao::uuid_generate]
      my <db> eval {
insert into session(sesid,userid) VALUES (:sessionid,:userid);
      }
    }

    $resultObj configure \
      sessionid $sessionid \
      userid $userid \
      username $username
    
    set session [my <db> eval {select field,value from session_property where sesid=:sessionid}]
    dict set session userid $userid
    dict set session username $username
    dict set session anonymous $anonymous
    $resultObj session build $session

    # Save any return cookies which have been set.
    # This works with the Doc_SetCookie procedure that populates
    # the global cookie array.

    set expdate  [expr {14*86400}]
    set expires  [expr {[clock seconds]+$expdate}]
    my <db> eval {update session set expires=:expires where sesid=:sesid;}
    $resultObj cookie_set sessionid $sessionid $expdate
  }
    
  method httpdSessionSave result {
    dict unset result body

    set sesid   [dict get $result sessionid]
    set session [dict get $result session]
    set session_delta [my <db> eval {select field,value from session_property where sesid=:sesid}]
    set add {}
    set delete {}
    set modify {}

    foreach {field value} $session {
      if {![dict exists $session_delta $field]} {
        lappend add $field $value
      } elseif {$value != [dict get $session_delta $field]} {
        lappend modify $field $value
      }
    }
    foreach {field value} $session_delta {
      if {![dict exists $session $field]} {
        lappend delete $field $value
      }
    }

    if {[llength $add]||[llength $delete]||[llength $modify]} {
      my db eval "BEGIN TRANSACTION"
      foreach {field value} $add {
        my <db> eval {insert or replace into session_property(sesid,field,value) VALUES (:sessionid,:field,:value);}
      }
      foreach {field value} $modify {
        my <db> eval {update session_property set value=:value where sesid=:sessionid and field=:field;}
      }
      foreach {field value} $delete {
        my <db> eval {delete from session_property where sesid=:sessionid and field=:field;}
      }
      my <db> eval "COMMIT"
    }
  }
  
  method pageHeader {} {
    return {
<HTML>
<HEAD>
    <TITLE>@TITLE@</TITLE>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
</HEAD>
<BODY>
    }
  }
  
  method pageFooter {} {
    return {
<script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/jquery.min.js"></script>
</BODY></HTML>
    }
  }

  method /html/logout resultObj {
    set sesid [$resultObj cget sessionid]
    my <db> eval {
update session set userid='local.anonymous' where sesid=:sesid;
delete from session_property where sesid=:sesid;
}
    $resultObj session build username anonymous userid local.anonymous anonymous 1
    $resultObj configure login-message {You have been logged out}
    my /html/login $resultObj
  }
  
  method /html/login resultObj {
    set sessionid [$resultObj cget sessionid]
    $resultObj reset
    $resultObj puts <html>
    $resultObj puts {
  <head>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
    <script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="/bootstrap/js/jquery.min.js"></script>
    <TITLE>Log In</TITLE>
    <script type="text/javascript" src="/jshash/sha1-min.js"></script>
    <script type="text/javascript">  
function login() {
  
    var p = hex_sha1(document.getElementById('key').value+document.getElementById('pass').value);  
    var k = document.getElementById('sesid').value;  

    var h = hex_sha1(k+p);  
    var hash = document.getElementById('hash');  
    hash.value = h;
    var f = document.getElementById('finalform');  
    f.submit();  
}  
    </script>
  </head>
    }    
    $resultObj puts {
  <body>
    }
    set msg [$resultObj cget login-message]
    if { $msg ne {} } {
      $resultObj puts "<pre><font color=ÓredÓ face=Ósans-serifÓ size=Ó1Ó>$msg</font></pre><hr>"
    }
    $resultObj puts {
<table>
<form action="authenticate" method="post" id="finalform">
<tr><th>Username:</th><td><input name="uid" id="uid" /></td></tr>
<input type="hidden" name="hash" id="hash" />  
</form>
    }
    $resultObj puts {<form action="javascript:login()" method="post" >}
    $resultObj puts "<input type=\"hidden\" id=\"key\" value=\"[my cget community-id]\" />"  
    $resultObj puts "<input type=\"hidden\" id=\"sesid\" value=\"$sessionid\" />"  
    $resultObj puts {
<tr><th>Password:</th><td><input type="password" id="pass" /></td></tr>
<tr><th>&nbsp</th></th><td><input type="submit" value="Log In" /></td></tr>
</table>
    </form>  

  </body>
    }
    $resultObj puts </html>
  }

  method /html/authenticate resultObj {
    set sessionid [$resultObj cget sessionid]
    foreach {field value} [$resultObj query] {
      if {$field eq "uid"} {
        set username $value
        foreach {field value} [$resultObj query] {
          if {$field eq "hash"} {
            set passhash [my <db> one {select password from users where username=:username}]
            set realhash [::sha1::sha1 -hex "$sessionid$passhash"]
            if { $realhash eq $value } {
              set userid [my <db> one {select userid from users where username=:username}]
              my <db> eval {
update session set userid=:userid where sesid=:sessionid;
}
              $resultObj session set username $username
              $resultObj session set userid $userid
              set root [my cget virtual]
              $resultObj puts "<HTML><HEAD><META HTTP-EQUIV=\"Refresh\" CONTENT=\"1; URL=$root\"></HEAD>"
              $resultObj puts {
<BODY>
You are now being logged in. You will be redirected in a moment.
<p>
              }
              $resultObj puts "<A href=\$root\>Home...</a>"
              $resultObj puts </BODY></HTML>
              return
            }
          }
        }
      }
    }
    $resultObj configure login-message {Password or Username was incorrect or invalid.}
    my /html/login $resultObj
  }
  
  method /html/env resultObj {
    if {[$resultObj session anonymous]} {
      $resultObj configure code 401
      return
    }
    $resultObj puts [my pageHeader]
    $resultObj puts "<TABLE>"
    foreach {field value} [$resultObj cgi dump] {
      $resultObj puts "<TR><TH>$field</TH><TD>$value</TD></TR>"
    }    
    $resultObj puts "</TABLE>"
    $resultObj puts [my pageFooter]
  }

  method /html/session resultObj {
    if {[$resultObj session anonymous]} {
      $resultObj configure code 401
      return
    }
    $resultObj puts [my pageHeader]
    $resultObj puts "<TABLE>"
    foreach {field value} [$resultObj session dump] {
      $resultObj puts "<TR><TH>$field</TH><TD>$value</TD></TR>"
    }    
    $resultObj puts "</TABLE>"
    $resultObj puts [my pageFooter]
  }
}

package provide httpd::community 0.1

Added modules/community/pkgIndex.tcl.

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd::community 0.1 [list source [file join $dir community.tcl]]
package ifneeded httpd::acl 0.1 [list source [file join $dir acl.tcl]]

Added modules/compat/compat.tcl.

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
package provide httpd::compat 4.0

namespace eval ::httpd {}
set ::httpd::compat_dir [file dirname [file normalize [info script]]]

proc httpd::compat_level level {
  set cfiles {}
  foreach file [lsort -dictionary -decreasing [glob -nocomplain [file join $::httpd::compat_dir version-*.tcl]]] {
    set version [lindex [split [file tail $file] -] 1]
    if { "$version" >= $level } { source $file }
  }
}

Added modules/compat/pkgIndex.tcl.





>
>
1
2
package ifneeded httpd::compat 4.0 [list source [file join $dir compat.tcl]]

Added modules/compat/version-3.3.tcl.







































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# compat.tcl
#@c Compatibility layer - deprecated
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# Colin McCormack (c) 2002
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#

foreach {oldname newname} {
    Doc_Cookie	        Cookie_Get
    Doc_GetCookie	Cookie_Get
    Doc_SetCookie	Cookie_Set
    Doc_IsLinkToSelf	Url_IsLinkToSelf
    Doc_Redirect	Redirect_To
    Doc_RedirectSelf	Redirect_Self
    Doc_IsLinkToSelf	Url_IsLinkToSelf
    Doc_IndexFile	DirList_IndexFile
    Doc_Webmaster	Httpd_Webmaster
    Doc_CheckTemplates	Template_Check
    Doc_TemplateInterp	Template_Interp
    Doc_TemplateLibrary	Template_Library
    Doc_Dynamic		Template_Dynamic
    Doc_Subst		Subst_ReturnFile
    Doc_TemplateScope	Subst_Scope
    Doc_SubstInstall    Subst_Install

    Url_Redirect	Redirect_Url
    Url_RedirectSelf	Redirect_UrlSelf

} {
    interp alias {} $oldname {} $newname
}

Added modules/compat/version-3.4.tcl.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9

# Compat routines with 3.4 routines

catch {interp alias {} Doc_Dynamic {} Template_Dynamic}
catch {interp alias {} Doc_Redirect {} Redirect_To}
catch {interp alias {} Doc_RedirectSelf {} Redirect_Self}

catch {interp alias {} Doc_Webmaster {} Httpd_Webmaster}
catch {interp alias {} Httpd_RedirectDir {} Redirect_Dir}

Added modules/compat/version-3.5.tcl.







>
>
>
1
2
3
###
# script to maintain compadibilty with Tclhttpd 3.5
###

Added modules/directoo/directoo.md.































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# The httpd.url class

[Implementation](finfo?name=modules/httpd/directoo.tcl)

*httpd.url* is a TclOO class. The first argument (after the name of the new object) is the virtual root for this object. For more complex classes, the second argument is a key/value list of configuration options. Any arguments after that are passed to *Url_PrefixInstall*

## Variables

### env

An array which contains CGI data. It is populated every page view *Cgi_SetEnv* in Tclhttpd.

### result

An array which contains the meta information and content about the page view in progress. Important fields:

* code - HTTP code to return (default 400)
* body - The block of data to be sent via *Httpd_ReturnData* or *Httpd_ReturnCacheableData* at the conclusion of the operation.
* content-type - The type of content in *block* (default text/html)

## Methods

### method configurelist *keyvaluelist*

Pass configuration items as a key/value list.

### method cget *field*

Retrieve the value of a configuration item

### /html

A method which implements the default root page of the object.

### method initialize

A method which is called in the constructor, after the configuration items have been applied and the domain registered with Tclhttpd.

### method httpdCookieSet *field* *value* *?expire?*

Set a cookie named *field* and value of *value*. If *expire* is a postitive integer,
it indicates how long (in seconds) this cookie should last.

Note: Cookies destined for "localhost" are mapped to null so
browser will honor them properly.

### method httpdHostName

Return the host name by which this page was accessed. Derived
from env\(HTTP\_HOST\).


### method httpdDirect *sock* *suffix*

This method is the first called when resolving a dynamic page. It calles *httpdSessionLoad* to load the session, *httpdMarshalArguments* do compute the method to call. On error, this method returns an error message. On success it calls *httpdSessionSave*, before sending the resulting data out to TclHttpd via the *Httpd_ReturnData* or *Httpd_ReturnCacheableData* procs.

### method httpdMarshalArguments *sock* *suffix*

Calculate the command which will implement the current page view.

### method httpdSessionLoad *sock *prefix* *suffix*

Initializes the *result* variable, and load session data from either cookies or the incoming GET/POST query. This method also calls the *Cgi_SetEnv* and *Url_QuerySetup* procs from Tclhttpd. Rather than populate the global *env* variable, Cgi_SetEnv populates the private *env* variable for this object.

### method httpdSessionSave *sock*

Updates the current session, and writes cookies back to the browser.

### method reset

Reset the current value of result(body)

### method puts

Append to the value of result(body). Accepts multiple arguments. An implied \n is appended at the tail end.

### method unknown *args*

Handler for unknown, incomplete, or invalid queries.

Added modules/directoo/directoo.tcl.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
###
# This package adds support for direct URLs implemented by
# TclOO Objects. They need a little extra massaging as an
# object may have its own rules about which method is being
# exercised
#
# Derived from direct.tcl
###

package provide httpd::directoo 0.1

package require httpd	;# Httpd_Redirect Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::doc_error	;# Doc_NotFound
package require httpd::url	;# Url_PrefixInstall Url_PrefixRemove Url_QuerySetup
package require httpd::utils	;# file iscommand
package require TclOO
package require tao

###
# Class that represents a web page in
# progress
###
tao::class httpd.result {
  superclass
  
  variable sock
  variable data
  variable state
  variable body
  variable cookie
  variable query
  variable session_data
  
  option cache-until {type unixtime default 0}
  option url_prefix {}
  option url_suffix {}
  option code {
    default 200
  }
  option content-type {
    default text/html
  }
  option title {}
  option redirect {}
  
  constructor {newsock prefix suffix} {
    my variable sock cgienv
    set sock $newsock
    my configurelist [list url_prefix $prefix url_suffix $suffix]

    # Set up the environment a-la CGI.
    ::Cgi_SetEnv $sock $prefix$suffix [my varname cgienv]

    # Prepare an argument data from the query data.
    my variable query
    ::Url_QuerySetup $sock
    set query [ncgi::nvlist]
  }
  
  destructor {
    
  }
  
  method sock {} {
    my variable sock
    return $sock
  }
  
  method data_get {field} {
    my variable sock
    upvar #0 Httpd$sock data
    if {![info exists data($field)]} {
      return {}
    }
    return $data(field)
  }
  
  method cgi {method args} {
    my variable cgienv
    switch $method {
      dump {
        return [array get cgienv]
      }
      get {
        set field [lindex $args 0]
        if {[info exists cgienv($field)]} {
          return $cgienv($field)
        }
        return {}
      }
      varname {
        return [my varname cgienv]
      }
      default {
        error "Valid: dump,get,varname"
      }
    }
  }

  method httpdHostName {} {
    my variable cgienv
    return [lindex [split [get cgienv(HTTP_HOST)] :] 0]
  }
  
  ###
  # Return a dict with:
  # * body
  # * content-type
  # * code (200,404,etc)
  # * cache-until (Unix datestamp when cache of this data expires, or 0)
  ###
  method httpReply {} {
    my variable body session_data
    set result {}
    dict set result content-type [my cget content-type]
    dict set result code         [my cget code]
    dict set result cache-until  [my cget cache-until]
    dict set result redirect     [my cget redirect]
    dict set result sessionid    [my cget sessionid]
    dict set result session       $session_data
    dict set result body $body

    return $result
  }
  
  method body {} {
    my variable body
    set title [my cget title]
    return [string map [list @TITLE@ $title] $body]
  }
  
  method query {} {
    my variable query
    return $query
  }
  
  method reset {} {
    my variable body
    set body {}
  }
  
  method puts args {
    my variable body
    append body {*}$args \n
  }
  
  #
  #@c	Return a *list* of cookie values, if present, else ""
  #@c	It is possible for multiple cookies with the same key
  #@c	to be present, so we return a list.
  #@c     This always gets the cookie state associated with the specified
  #@c     socket, unlike Cookie_Get that looks at the environment.
  #
  # Arguments:
  #@a	cookie	The name of the cookie (the key)
  #@a	sock	A handle on the socket connection
  # Returns:
  #@r	a list of cookie values matching argument
  method cookie_get {cookie} {
    my variable sock
    upvar #0 Httpd$sock data
    set result ""
    set rawcookie ""
    if {[info exist data(mime,cookie)]} {
        set rawcookie $data(mime,cookie)
    }
    foreach pair [split $rawcookie \;] {
        lassign [split [string trim $pair] =] key value
        if {[string compare $cookie $key] == 0} {
            lappend result $value
        }
    }
    return $result
  }
    
  #$c	make a cookie from name value pairs
  #
  # Arguments:
  #	args	Name value pairs, where the names are:
  #@a		-name	Cookie name
  #@a		-value	Cookie value
  #@a		-path	Path restriction
  #@a		-domain	domain restriction
  #@a		-expires	Time restriction
  #@a		-secure Append "secure" to cookie attributes
  #@r	a formatted cookie
  
  method cookie_make {args} {
    array set opt $args
    set line "$opt(-name)=$opt(-value) ;"
    foreach extra {path domain} {
        if {[info exist opt(-$extra)]} {
            append line " $extra=$opt(-$extra) ;"
        }
    }
    if {[info exist opt(-expires)]} {
        switch -glob -- $opt(-expires) {
            *GMT {
                set expires $opt(-expires)
            }
            default {
                set expires [clock format [clock scan $opt(-expires)] \
                        -format "%A, %d-%b-%Y %H:%M:%S GMT" -gmt 1]
            }
        }
        append line " expires=$expires ;"
    }
    if {[info exist opt(-secure)]} {
        append line " secure "
    }
    return $line
  }
  
  method cookie_set {field value {expire {}}} {
    my variable sock
    upvar #0 Httpd$sock data
    
    foreach host [my httpdHostName] {
      if { $host eq "localhost" } { set host {} }
      set cookie_args [list -name $field \
        -value $value \
        -domain $host \
        -path [my cget virtual]]
      if {[string is integer expire]} {
        lappend cookie_args -expires [clock format [expr [clock seconds] + [set expire]] -format "%Y-%m-%d"]
      }
      # Appending to the data(set-cookie) elimates the entire
      # kangaroo code that normally goes on with httpd
      lappend data(set-cookie) [my cookie_make {*}$cookie_args]
    }
  }
  
  method session {method args} {
    my variable session_data
    switch $method {
      anonymous {
        if {[dict getnull $session_data username] in {{} nobody anonymous}} {
          return 1
        }
        return 0
      }
      build {
        set session_data [::tao::args_to_options {*}$args]
      }
      dump {
        return $session_data
      }
      get {
        return [dict getnull $session_data [lindex $args 0]]
      }
      userid {
        set userid [dict getnull $session_data userid]
        if { $userid eq {} } {
          return local.anonymous
        }
        return $userid
      }
      set {
        #dict set session_data {*}args
        foreach {key value} [::tao::args_to_options {*}$args] {
          dict set session_data $key $value
        }
      }
      unset {
        dict unset session_data {*}args
      }
      varname {
        return [my varname session_data]
      }
      default {
        error "Valid: build.dump,get,set,unset,varname"
      }
    }
  }
}

###
# Create a standalone class suitable for using in a pure tcloo
# environment
###
tao::class httpd.url {
  superclass 
  aliases httpd.meta httpd.taourl
  
  property options_strict 0
  option virtual {}
  option threadargs {}
  
  #method Option_set::virtual newvalue {
  #  
  #}
  
  constructor {virtual {localopts {}} args} {
    my configurelist [list virtual $virtual threadargs $args {*}$localopts]
    ::Url_PrefixInstall $virtual [namespace code {my httpdDirect}] {*}$args
    my initialize
  }
  

  destructor {
    catch {::Url_PrefixRemove [my cget virtual]}
  }
  
  method initialize {} {}
  
  # This calls out to the Tcl procedure named "$prefix$suffix",
  # with arguments taken from the form parameters.
  # Example:
  # httpdDirect /device Device
  # if the URL is /device/a/b/c, then the Tcl command to handle it
  # should be
  # [self] /html/Device/a/b/c
  # You can define the content type for the results of your procedure by
  # defining a global variable with the same name as the procedure:
  # set Device/a/b/c text/plain
  #  The default type is text/html
  #
  #	This function returns the result of evaluating the direct
  #	url.  Usually, this involves returning a page, but a redirect
  #	could also occur.
  #
  # Arguments:
  # 	sock	The socket back to the client.
  #	code	The return code from evaluating the direct url.
  #	result	The return string from evaluating the direct url.
  #	type	The mime type to use for the result.  (Defaults to text/html).
  #	
  #
  # Results:
  #	None.
  #
  # Side effects:
  #	If code 302 (redirect) is passed, calls Httpd_Redirect to 
  #	redirect the current request to the url in result.
  #	If code 0 is passed, the result is returned to the client.
  #	If any other code is passed, an exception is raised, which
  #	will cause a stack trace to be returned to the client.
  #


  method httpdDirect {sock suffix} {
    set prefix [my cget virtual]
    set resultObj [httpd.result new $sock $prefix $suffix]
    my httpdSessionLoad $resultObj $prefix $suffix
    set cmd [my httpdMarshalArguments $resultObj]
    # Eval the command.  Errors can be used to trigger redirects.

    if [catch $cmd] {
      ::Httpd_ReturnData $sock text/html "<HTML><BODY>Error: <PRE><VERBATIM>$::errorInfo</VERBATIM></PRE></BODY></HTML>" 505
      $resultObj destroy
      return
    }
    set result [$resultObj httpReply]
    set code [dict get $result code]
    if {[string index $code 0] in {0 2}} {
      # Normal reply
      my httpdSessionSave $result
    }
    
    switch $code {
      401 {
        ::Httpd_ReturnData $sock text/html $::HttpdAuthorizationFormat $code
      }
      404 {
        ::Doc_NotFound $sock
      }
      302 {
        # Redirect.
        ::Httpd_Redirect [dict get $result redirect] $sock
      }
      default {
        if {[dict get $result cache-until] > 0} {
          ::Httpd_ReturnCacheableData $sock [dict get $result content-type] [dict get $result body] [dict get $result cache-until] [dict get $result code]
        } else {
          ::Httpd_ReturnData $sock [dict get $result content-type] [dict get $result body] [dict get $result code]
        }
      }
    }
    $resultObj destroy

  }
  
  method httpdSessionLoad {resultObj prefix suffix} {}
  
  method httpdSessionSave result {}
  
  #
  #	Use the url prefix, suffix, and cgi values (set with the
  #	ncgi package) to create a Tcl command line to invoke.
  #
  # Arguments:
  #	suffix		The part of the url after the domain prefix.
  #
  # Results:
  #	Returns a Tcl command line.
  #
  # Side effects:
  #	If the suffix (and query args) do not map to a Tcl procedure,
  #	returns empty string.
  method httpdMarshalArguments resultObj {
    set prefix [$resultObj cget url_prefix]
    set suffix [$resultObj cget url_suffix]

    if { $suffix in {/ {}} } {
      set method /html
    } else {
      set method /html$suffix
    }
    foreach {name value} [$resultObj query] {
      if { $name eq "method" } {
        set method /html/$value
        break
      }
    }
    return [list my $method $resultObj]
  }
  
  method unknown {args} {
    if {[string range [lindex $args 0] 0 4] eq "/html"} {
      my HtmlNotFound {*}$args
      return
    }
    next {*}$args
  }
  
  ###
  # title: Implement html content at a toplevel
  ###
  method /html resultObj {
    $resultObj reset
    $resultObj configure title {Welcome!}
    $resultObj puts [my pageHeader]
    $resultObj puts {
Hello World
    }
    $resultObj puts [my pageFooter]
  }
  
  method HtmlNotFound args {
    set resultObj [lindex $args 0]
    $resultObj configure code 404
    $resultObj configure title {Page Not Found}
  }
  
  method pageHeader {} {
    return {
<HTML>
<HEAD>
    <TITLE>@TITLE@</TITLE>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
</HEAD>
<BODY>
    }
  }
  
  method pageFooter {} {
    return {
<script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/jquery.min.js"></script>
</BODY></HTML>
    }
  }

}

Added modules/directoo/pkgIndex.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd::directoo 0.1 [list source [file join $dir directoo.tcl]]

Added modules/httpd/MakeIndex.





















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/tclsh

# First, auto-generate the standard direct-style package index

pkg_mkIndex -verbose -direct . *.tcl
return

file rename -force pkgIndex.tcl pkgIndex.tcl.direct
set in [open pkgIndex.tcl.direct r]
set out [open pkgIndex.tcl w]

# Now generate a new version that hides the sub-packages

puts $out [gets $in]
# Tcl package index file, version 1.1

puts $out "
# This file is generated by the MakeIndex script in the tclhttpd 
# lib directory.  The goal is to not pollute the package namespace
# until you package require httpd
"

# Skip the other comment block.  We know the line for
# httpd comes first.

while {[gets $in line] >= 0} {
    if {[regexp {package ifneeded httpd ([^ ]+)} $line x version]} {
	puts $out "package ifneeded httpd $version \""
	puts $out "\tsource \\\[file join \[list \$dir] httpd.tcl\\\]"
	break
    }
}

# Now reformat the other lines slightly to protect the
# list and file join commands, but let the $dir get expanded

while {[gets $in line] >= 0} {
    regsub -all {[][]} $line {\\&} line
    regsub -all {\$dir} $line {[list &]} line
    puts $out \t$line
}
puts $out "\""

Added modules/httpd/admin.tcl.



























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# URL-based administration

# Copyright
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: admin.tcl,v 1.9 2004/10/22 03:43:06 coldstore Exp $


package provide httpd::admin 1.0

package require httpd::auth	;# AuthVerifyBasic
package require httpd::counter	;# Count Counter_Reset
package require httpd::direct	;# DirectDomain Direct_Url
package require httpd::redirect	;# Redirect_Url
#package require httpd::utils	;# file

proc Admin_Url {dir} {
    Direct_Url $dir Admin
}

proc Admin/redirect {old new} {
    global Doc Httpd
    if {[string length $old] == 0} {
	return "<h1>Redirect URL</h1>\n\
		<form action=redirect method=post>\n\
		OLD: <input type=input name=old><br>\n\
		NEW: <input type=input name=new><br>\n\
		<input type=submit value=\"Redirect URL\"></form>"
    }
    if {[string length $new] == 0} {
	return "<h1>Redirect URL</h1>\n\
		<form action=redirect method=post>\n\
		<input type=hidden name=old value=$old>\n\
		OLD: $old<br>\n\
		NEW: <input type=input name=new><br>\n\
		<input type=submit value=\"Redirect URL\"></form>"
    }
    set server $Httpd(name)
    if {$Httpd(port) != 80} {
	append server :$Httpd(port)
    }
    if {![regexp ^http: $new]} {
	set new http://$server$new
    }

    ####
    # Need password protection for this page
    ####

    return "<h1>Redirect Form Disabled</h1>\n\
	   Redirect_Url $old http:$server$new"

    Redirect_Url $old $new
    if {[info exists Doc(notfound,$old)]} {
	unset Doc(notfound,$old)
    }
    return <h1>ok</h1>
}

proc Admin/reset/counter {name} {
    
if {0} {
    # Ugh - get the socket handle in the DirectDomain procedure
    upvar 1 sock sock
  
    # Need a way to register administrator passwords
    # For now we just allow this to happen.

    if {![AuthVerifyBasic $sock $admin(authfile)]} {
	return "Password Check Failed"
    }
}
    Counter_Reset $name
    return "Reset Counter $name"
}

Added modules/httpd/auth.tcl.











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# auth.tcl
#
# Basic authentication
# This module parses .htaccess files and does the Basic Authentication
# protocol.  There is some generality in here to support multiple
# authentication schemes, but in practice only Basic is used right now.
#
# Each .htaccess file is parsed once and the information is kept in a
# Tcl global array named auth$filename, and upvar aliases this to "info".
# "info" contains the info provided by the .htaccess file ( info(htaccessp,..) )
#
# The AuthUserFile and the AuthGroupFile are parsed and stored
# in authentication array auth$filename.
#
# Authentication arrays need not be associated with physical files.
# To create an authentication array:
#	array set auth$pseudo [list mtime 0 user,$u password group,$g group]
#
# Configuration creates an authentication array authdefault, for bootstrapping.
#
# There is also support for ".tclaccess" files in each directory.
# These contain hook code that define password checking procedures
# that apply at that point in the hierarchy.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# Piet Vloet (c) 2001
# Brent Welch (c) 2001
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: auth.tcl,v 1.25 2006/11/09 23:41:41 coldstore Exp $

package provide httpd::auth 2.0

package require base64

package require httpd	;# Httpd_Error Httpd_RequestAuth
package require httpd::config	;# Config
package require httpd::digest	;# Digest_Passwd
package require httpd::log	;# Log
package require httpd::passgen	;# Passgen_Generate Passgen_Salt
package require httpd::utils	;# K Stderr file
package require tclcrypt	;# crypt

set Auth_DigestOnly 0;	# set this to 1 to only use Digest auth

# Crypto packages
if {[catch {package require crypt}] || [catch {crypt foo ba}]} {
    # if we don't have a C library, fall back to pure tcl crypt
    package require tclcrypt
}

# set default user/group files
if {![info exists Config(AuthUserFile)]} {
    set Config(AuthUserFile) default
}
if {![info exists Config(AuthGroupFile)]} {
    set Config(AuthGroupFile) default
}

# Authentication bootstrap.
#
# The /htaccess URL allows admins to create passwords and groups,
# and .htaccess files per directory, however it is necessary to have a
# password to bootstrap this process.
#
# The approach taken is to allow the administrator to give plaintext
# passwords via Config, or (failing that) to generate and Log a random
# password at runtime.  A new random password will be created on each 
# server startup.
#
# Here, we create a default authentication array from Config(Auth)

array set authdefault {mtime -1}
package require httpd::passgen	;# random password generation

# Auth_InitCrypt --
# Attempt to turn on the crypt feature used to store crypted passwords.

proc Auth_InitCrypt {} {
    global authdefault
    global Config

    if {[info exists Config(Auth)]} {
	foreach {var val} $Config(Auth) {
	    if {[string match user,* $var]} {
		# encrypt the password
		set salt [Passgen_Salt]
		set val [crypt $val $salt]
	    }
	    set authdefault($var) $val
	}
    } else {
	# we weren't given an Auth Config - generate a default for webmaster
	# and write it to Stderr
	
	set webmaster_password [Passgen_Generate]
	set salt [Passgen_Salt]
	set authdefault(user,webmaster) [crypt $webmaster_password $salt]
	set authdefault(group,webmaster) webmaster
	set authdefault(user,webmaster@webmaster) [Digest_Passwd webmaster webmaster $webmaster_password]
	# This lets the admin see this important password during startup.
        # It is also displayed by the Tk srvui interface.
	Stderr "User \"webmaster\" default password \"$webmaster_password\""
    }
}

proc Auth_AccessFile {args} {
    Stderr "Auth_AccessFile is obsolete: use Auth_InitCrypt instead"
    Auth_InitCrypt
}

# Auth_Check --
# This looks for access files along the path.
# It returns a "cookie" that is checked by Auth_Verify.
# NOTE: this looks for the lowest (i.e., deepest) access file
# and only returns information about one. Consider changing
# Auth_Check/Auth_Verify to check all files.

proc Auth_Check {sock directory pathlist} {
    global auth
    set cookie {}

    # Make sure we do checks in the root
    if {$pathlist==""} {
	 set pathlist ./
    }

    # Look for the .htaccess files that keep Basic Authtication info
    # or .tclaccess files with a general authorization callback
    set path $directory
    foreach component $pathlist {
        if {![file isdirectory $path]} {
            # Don't bother looking if we are in an "artificial"
            # url domain that isn't mapped to files.
            break
        }
	foreach {name type} {.htaccess Basic .tclaccess Tcl} {
	    set file [file join $path $name]
	    if {[file exists $file]} {
		set cookie [list $type $file]
		# Keep looking for cookie files lower in the directory tree
            }
	}
	set path [file join $path $component]
    }

    # Block access to the access control files themselves.
    # We toss in a block against the .tml files as well,
    # although that isn't strictly clean modularity.
    set tail [file tail $path]
    if {$tail == ".tclaccess" ||
          $tail == ".htaccess" ||
          $tail == ".tml"} {
        set cookie [list Deny $path]
        return $cookie
    }

    return $cookie
}

proc Auth_Verify {sock cookie} {
    if {[llength $cookie] == 0} {
	return 1
    }
    set type [lindex $cookie 0]
    set key [lindex $cookie 1]
    if {$type == "Deny"} {
        return 0
    } else {
        return [AuthVerify$type $sock $key]
    }
}

# Auth_VerifyCallback -- 
#
#       Check for a Basic authorization string, and use a callback
#       to verify the password
#
# Arguments:
#       sock            Handle on the client connection
#       realm           Realm for basic authentication.  This appears
#                       in the password prompt from the browser.
#       callback        Tcl command to check the password.  This gets
#                       as arguments the sock, realm, username and password.
#
# Results:
#                       return 1 or 0, 1 for success.

proc Auth_VerifyCallback {sock realm callback} {
    upvar #0 Httpd$sock data

    if {![info exists data(mime,authorization)]} {
	set ok 0
    } else {
	set parts [split $data(mime,authorization)]
	set type [lindex $parts 0]
	set code [lindex $parts 1]
	if {[string compare $type Basic] != 0} {
	    set user {}
	    set pass {}
	} else {
	    set parts [split [base64::decode $code] :]
	    set user [lindex $parts 0]
	    set pass [lindex $parts 1]
	}
	set ok [eval $callback {$sock $realm $user $pass}]
    }
    if {!$ok} {
	Httpd_RequestAuth $sock Basic $realm
	return 0
    } else {
	set data(auth_type) Basic
	set data(remote_user) $user
	set data(session) $realm,$user
	return 1
    }
}

# AuthVerifyTcl --
#
#       "Tcl" verification uses a .tclaccess file that defines the
#       realm and callback to use to check the password.
#
# Arguments:
#       sock    Handle on the client connection
#       file    Tcl source file that contains set commands for
#               realm and callback
#
# Results:
#       1 for success, 0 for access denied.

proc AuthVerifyTcl {sock file} {
    upvar #0 Httpd$sock data


    # The file contains definitions for the "realm" variable
    # and the "callback" script value.

    set realm Realm
    set callback AuthNullCallback
    catch {source $file}

    return [Auth_VerifyCallback $sock $realm $callback]
}

proc AuthNullCallback {sock realm user pass} {
    upvar #0 Httpd$sock data
    global auth
    if {[info exists auth($realm,$user)]} {
	switch -exact -- $auth($realm,$user) \
	    $pass {
		Stderr "Session: $realm,$user"
		return 1
	    } \
	    PasswordRequired {
		set auth($realm,$user) $pass
		Stderr "Session: $realm,$user"
		return 1
	    } \
	    default {
		return 0
	    }
    } else {
	set auth($realm,$user) PasswordRequired
	return 0
    }
}

# AuthUserOp - see if the user is permitted to perform a requested
# operation (PUT, GET, etc)
# The .htaccess file is searched for the user or a group containing
# the user, to ascertain whether the user could possibly perform
# the op before the proffered credentials are checked.

proc AuthUserOp {sock file op user} {
    upvar #0 auth$file info
    upvar #0 Httpd$sock data

    if {[info exists info(htaccessp,require,$op,group)]} {
	if {![AuthGroupCheck $sock $file \
		  $info(htaccessp,require,$op,group) $user]} {
	    return 0   ;# Not in a required group
	}
    }
    if {[info exists info(htaccessp,require,$op,user)]} {
	if {![AuthUserCheck $sock $file \
		  $info(htaccessp,require,$op,user) $user]} { 
	    return 0   ;# Not the required user
	}
    }
    return 1
}

# AuthVerifyBasic - see if the user is granted access.
# First domain based protection is performed. In the case the
# user is not in the domain user based protection is performed.
# The user must be in a group or mentioned as user. The password
# must match the user's entry.  If neither group nor user are
# required for the operation, then the check passes.

proc AuthVerifyBasic {sock file} {
    upvar #0 auth$file info
    upvar #0 Httpd$sock data

    set user ""

    AuthParseHtaccess $sock $file
    set op $data(proto) ;# GET, POST etc.
    set realm $info(htaccessp,name)

    # check whether the operation is controlled
    if {[info exists info(htaccessp,order,$op)]} {
	if {! [AuthVerifyNet $sock $file $op]} {
	    # it is controlled and network address is excluded
	    Httpd_Error $sock 403
	    return 0
	}
    }
    if {![info exists info(htaccessp,require,$op,group)] &&
	    ![info exists info(htaccessp,require,$op,user)]} {
	# No "require group .." or "require user .." in .htaccess file
	return 1
    }

    set ok 0

    # the operation requires a user or group - check authorization
    if {[info exists data(mime,authorization)]} {
	# client has sent auth data
	set parts [split $data(mime,authorization)]
	set type [lindex $parts 0]

	switch -- [string tolower $type] {
	    digest {
		# unpack the digest request
		Digest_Get $sock $parts

		# check that the proferred user can have access
		set user $data(digest,username)
		set ok [AuthUserOp $sock $file $op $user]

		if {$ok} {
		    # now check the Digest credentials
		    set ok [Digest_Request $sock $realm $file]
		}
	    }
	    basic {
		set code [lindex $parts 1]
		set parts [split [base64::decode $code] :]

		# check that the proferred user can have access
		set user [lindex $parts 0]
		set ok [AuthUserOp $sock $file $op $user]

		if {$ok} {
		    # now check the Basic credentials
		    set pass [lindex $parts 1]
		    set crypt [AuthGetPass $sock $file $user]
		    set salt [string range $crypt 0 1]
		    set crypt2 [crypt $pass $salt]
		    if {[string compare $crypt $crypt2] != 0} {
			set ok 0        ;# Not the right password
		    }
		}
	    }
	    default {
		# this is an unknown auth method - it's not ok, we can't handle it
		set ok 0
	    }
	}
    }

    if {! $ok} {
	# client hasn't sent auth or auth doesn't satisfy
	global Auth_DigestOnly
	if {!$Auth_DigestOnly && ($info(htaccessp,type) == "Basic")} {
	    Httpd_RequestAuth $sock Basic $realm
	} else {
	    # make Digest the default
	    Digest_Challenge $sock $realm $user
	}
    } else {
	# client is permitted and credentials check out
	set data(auth_type) $type
	set data(remote_user) $user
	set data(session) $realm,$user
    }

    return $ok
}

proc AuthUserCheck  {sock file users user } {
    return [expr {[lsearch $users $user] >= 0}]
}

# Parse the AuthGroupFile and find the user in it.
# The information is built up in the array:
#	auth$info(htaccessp,groupfile)
#
# To create an authentication array, unconnected to a physical file:
# array set auth$pseudo [list mtime 0 user,$u password group,$g group]
#
# If the .htaccess file didn't specify a groupfile, it defaults to an authentication
# array authdefault, which contains configured default passwords and groups

proc AuthGroupCheck {sock file groups user} {
    upvar #0 auth$file info
    upvar #0 auth$info(htaccessp,groupfile) group

    if {[catch {file mtime $info(htaccessp,groupfile)} mtime]} {
	set mtime -1	;# the file may not exist
    }

    # Only parse the group file if it has changed
    if {![info exists group(mtime)] || ($mtime > $group(mtime))} {
	catch {unset group(mtime)}	;# unset to catch errors
	foreach i [array names group "group*"] {
	    unset group($i)
	}
	if {[catch {open $info(htaccessp,groupfile)} in]} {
	    return 0
	}
	while {[gets $in line] >= 0} {
	    if {[regexp {^([^:]+):[      ]*(.+)} $line x key value]} {
		set group(group,$key) [split $value " ,"]
	    }
	}
	close $in
	set group(mtime) $mtime
    }

    foreach index $groups {
	if {[info exist group(group,$index)]} {
	    if {[lsearch $group(group,$index) $user] >= 0} {
		return 1
	    }
	}
    }
    return 0
}

# Parse the AuthUserFile and return the user's information.
# The information is built up in the array:
#	auth$info(htaccessp,userfile)
# 
# To create an authentication array, unconnected to a physical file:
# array set auth$pseudo [list mtime 0 user,$u password group,$g group]
#
# If the .htaccess file didn't specify a userfile, it defaults to an authentication
# array authdefault, which contains configured default passwords and groups

proc AuthGetPass {sock file user} {
    upvar #0 auth$file info
    upvar #0 auth$info(htaccessp,userfile) passwd

    if {[catch {file mtime $info(htaccessp,userfile)} mtime]} {
	set mtime -1	;# the file may not exist
    }

    if {![info exists passwd(mtime)] || ($mtime > $passwd(mtime))} {
	catch {unset passwd(mtime)}	;# unset to catch errors
	foreach i [array names passwd "user*"] {
	    unset passwd($i)
	}
	if {[catch {open $info(htaccessp,userfile)} in]} {
	    return *
	}
	while {[gets $in line] >= 0} {
	    if {[regexp {^([^:]+):[      ]*([^:]+)} $line x key value]} {
		set passwd(user,$key) $value
	    }
	}
	close $in
	set passwd(mtime) $mtime
    }
    if {[info exists passwd(user,$user)]} {
	return $passwd(user,$user)
    } else {
	return *
    }
}

# Check the allow/deny lists for this operation

proc AuthVerifyNet {sock file op} {
    upvar #0 auth$file info
    set order [split $info(htaccessp,order,$op) ,]
    set peer [fconfigure $sock -peername]
    set rname [string tolower [lindex $peer 1]]
    set raddr [lindex $peer 0]
    set ok 0
    foreach way $order {
	if {![info exists info(htaccessp,network,$way,$op)]} {
	    continue
	}
	foreach addr $info(htaccessp,network,$way,$op) {
	    if {[AuthNetMatch $sock $addr $rname $raddr]} {
		if {[string compare $way "allow"] == 0} {
		    set ok 1
		} else {
		    set ok 0
		}
	    }
	}
    }
    if {! $ok} {
	Log $sock AuthVerifyNet "access denied to $rname in [file tail [file dirname $file]]"
    }
    return $ok
}

proc AuthNetMatch {sock addr rname raddr} {
    if {[string compare $addr "all"] == 0} {
	return 1
    }
    if {[string match *$addr $rname] || [string match ${addr}* $raddr]} {
	return 1
    }
    return 0
}

# Parse the htaccess file.  Uhler would probably regsub/subst this,
# but here we just call a Tcl proc to handle each "command" in the file.
# The information is built up in the info array.

proc AuthParseHtaccess {sock file} {
    upvar #0 auth$file info
    set mtime [file mtime $file]
    if {![info exists info] || ($mtime > $info(htaccessp,mtime))} {
	# Parse .htaccess file
	foreach i [array names info "htaccessp*"] {
	    unset info($i)
	}
	set info(htaccessp,mtime) $mtime

	global Config
	set info(htaccessp,userfile) $Config(AuthUserFile)
	set info(htaccessp,groupfile) $Config(AuthGroupFile)

	set info(htaccessp,name) Digest
	if {[catch {open $file} in]} {
	    return 1
	}
	set state [list vars]
	foreach line [split [read $in] \n] {
	    if {[regexp ^# $line] || [string length [string trim $line]] == 0} {
		continue
	    }
	    if {[regexp <(.+)> $line x tag]} {
		set line $tag
	    }
	    set words [split $line]
	    set cmd [string tolower [lindex $words 0]]
	    if {[catch {
		eval {Ht-$cmd auth$file} [lrange $words 1 end]
	    } err]} {
		Log $sock Error $err
	    }
	}
	close $in
    }
    return 1
}
proc Ht-authtype {infoName type} {
    upvar #0 $infoName info
    set info(htaccessp,type) $type
}
proc Ht-authname {infoName name} {
    upvar #0 $infoName info
    set info(htaccessp,name) $name
}

proc Ht-authuserfile {infoName file} {
    upvar #0 $infoName info
    set info(htaccessp,userfile) $file
}

proc Ht-authgroupfile {infoName file} {
    upvar #0 $infoName info
    set info(htaccessp,groupfile) $file
}

proc Ht-limit {infoName args} {
    upvar #0 $infoName info
    set info(htaccessp,limit) $args       ;# List of operations, GET, POST, ...
}

proc Ht-/limit {infoName args} {
    upvar #0 $infoName info
    set info(htaccessp,limit) {}
}

proc Ht-require {infoName key list} {
    upvar #0 $infoName info
    if {![info exists info(htaccessp,limit)]} {
	set info(htaccessp,limit) {}
    }
    foreach op $info(htaccessp,limit) {
	if {![info exists info(htaccessp,require,$op,$key)]} {
		set info(htaccessp,require,$op,$key) {}
	    }
	    foreach a $list {
		lappend info(htaccessp,require,$op,$key) $a
	    }
     }
}

proc Ht-order {infoName value} {
    upvar #0 $infoName info
    if {![info exists info(htaccessp,limit)]} {
	set info(htaccessp,limit) {}
    }
    foreach op $info(htaccessp,limit) {
	if {[info exists info(htaccessp,order,$op)]} {
		 unset info(htaccessp,order,$op)
	}
	set info(htaccessp,order,$op) $value
    }
}

proc Ht-deny {infoName args} {
    HtByNet $infoName deny $args
}
proc Ht-allow {infoName args} {
    HtByNet $infoName allow $args
}
proc HtByNet {infoName how list} {
    upvar #0 $infoName info
    if {![info exists info(htaccessp,limit)]} {
	set info(htaccessp,limit) {}
    }
    if {[string compare [lindex $list 0] "from"] == 0} {
	set list [lrange $list 1 end]
    }
    foreach op $info(htaccessp,limit) {
	if {![info exists info(htaccessp,network,$how,$op)]} {
	    set info(htaccessp,network,$how,$op) {}
	}
	foreach a $list {
	    lappend info(htaccessp,network,$how,$op) [string tolower $a]
	}
    }
}

Added modules/httpd/cgi.tcl.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
# cgi.tcl
# CGI support
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: cgi.tcl,v 1.31 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::cgi 1.1

package require httpd	;# Httpd_Date Httpd_Error Httpd_Port Httpd_SelfUrl Httpd_SockClose
package require httpd::counter	;# Count
package require httpd::doc	;# DocAccessHook Doc_RegisterRoot Doc_Root Doc_Virtual
package require httpd::doc_error	;# Doc_NotFound
package require httpd::log	;# Log
package require httpd::threadmgr	;# Thread_Id Thread_Send Thread_SendAsync
package require httpd::url	;# Url_Dispatch Url_Handle Url_PathCheck Url_PrefixInstall
#package require httpd::utils	;# file

# Cgi parameters
# timeout	Seconds before pipe to CGI program is closed
# maxcgi	Number of concurrent requests allowed
# cgi		Running total of cgi requests
# ident		If true, try to use the ident protocol
# env-pass	List of environment variables to preserve when setting
#		up the environment.  The rest are deleted and then recreated
#		from information in the CGI request.
# tclsh		Pathname to a Tcl interpreter.  If you preserve the env(PATH)
#		by listing PATH in env-pass, this can be "tclsh80.exe"
#		or "protclsh80.exe".  Otherwise it has to be an absolute path.

array set Cgi {
    timeout	300000
    maxcgi	100
    cgi		0
    ident	0
    env-pass	{PATH LD_LIBRARY_PATH TZ}
}
if {"$tcl_platform(platform)" == "windows"} {

    # On windows we hard-code the interpreters for various script types

    regsub -nocase wish [info nameofexecutable] tclsh Cgi(tclsh) ;# For .tcl
    set Cgi(perl) "perl.exe"			;# For .pl
    set Cgi(cgiexe) $Cgi(tclsh)			;# For .cgi

    # More environment variables need to be passed through.
    # Windows NT Need Lib and SystemRoot so DLLs loaded by tcl are found.
    # Windows 95 needs more... so we just pass everything

    lappend Cgi(env-pass) * 
}

# Register a cgi-bin directory.
# This causes the server to pay attention to the extra path information
# after the program name.

proc Cgi_Directory {virtual {directory {}}} {

    # Set up the URL-directory mapping so that DocAccessHook works right.

    if {[string length $directory] == 0} {
	set directory [Doc_Virtual {} {} $virtual]
    }
    Doc_RegisterRoot $virtual $directory

    # Register the domain - not in a thread becaused we'll use another process anyway.
    # The CGI module will also read the post data itself so TclHttpd doesn't buffer
    # it all in memory before passing it to the CGI process.

    Url_PrefixInstall $virtual [list Cgi_Domain $virtual $directory] \
	-thread 0 -readpost 0
}

# Cgi_Domain is called from Url_Dispatch for URLs inside cgi-bin directories.

proc Cgi_Domain {virtual directory sock suffix} {
    global Cgi env

    # Check the path and then find the part beyond the program name.
    # The trimleft avoids a buildup of extra / after the domain prefix.

    if {[catch {Url_PathCheck [string trimleft $suffix /]} pathlist]} {
	Doc_NotFound $sock
	return
    }

    # url is the logical name as viewed by a browser
    # path is a physical file system name as viewd by the server

    set url [string trimright $virtual /]
    set path $directory
    set i 0
    foreach component $pathlist {
	incr i
	set path [file join $path $component]
	append url /$component
	if {[file isfile $path]} {
#	    if {[file executable $path]} {
		# Don't bother testing execute permission here,
		# because it doens't test right on windows anyway.
		set extra [lrange $pathlist $i end]
#	    }
	    break
	} elseif {![file exists $path]} { 
	    Doc_NotFound $sock
	    return
	}
    }
    if {![info exists extra]} {
	# Didn't find an executable file
	Httpd_Error $sock 403
	return
    } elseif {[llength $extra]} {
	set extra /[join $extra /]
    }

    # The CGI needs the server-relative url of the script,
    # the extra part after the program name,
    # and the translated version of the whole pathname.

    Url_Handle [list CgiHandle $url $extra $path] $sock
}

proc CgiHandle {url extra path sock} {
    global Doc env
    Cgi_SetEnvAll $sock $path $extra $url env
    CgiSpawn $sock $path
}

# This gets called if there is no extra pathname after
# the name of a cgi script, and the Doc module finds a .cgi file

proc Doc_application/x-cgi {path suffix sock} {
    upvar #0 Httpd$sock data
    Url_Handle [list CgiHandle $data(url) {} $path] $sock
}

# Set the environment for the cgi scripts.  This is passed implicitly to
# the cgi script during the "open" call.

proc Cgi_SetEnv {sock path {var env}} {
    upvar 1 $var env
    upvar #0 Httpd$sock data
    Cgi_SetEnvAll $sock $path {} $data(url) env
}

proc Cgi_SetEnvInterp {sock path interp} {
    upvar #0 Httpd$sock data
    Cgi_SetEnvAll $sock $path {} $data(url) env
    interp eval $interp [list uplevel #0 \
	[list array set env [array get env]]]
}

proc Cgi_SetEnvAll {sock path extra url var} {
    upvar #0 Httpd$sock data
    upvar 1 $var env
    global Httpd Httpd_EnvMap Cgi

    # we can't "unset env" or it won't get passed to the CGI script
    foreach i [array names env] {
	set clear 1
	foreach x $Cgi(env-pass) {
	    if {[string match $x $i]} {
		# Preserve some path settings
		set clear 0
		break
	    }
	}
	if {$clear} {
	    unset env($i)
	}
    }
    foreach name [array names Httpd_EnvMap] {
	set env($name) ""
	catch {
	    set env($name) $data($Httpd_EnvMap($name))
	}
    }
    set env(REQUEST_URI) [Httpd_SelfUrl $data(uri) $sock]
    set env(GATEWAY_INTERFACE) "CGI/1.1"
    set env(SERVER_PORT) [Httpd_Port $sock]
    if {[info exist Httpd(https_port)]} {
	set env(SERVER_HTTPS_PORT) $Httpd(https_port)
    }
    set env(SERVER_NAME) $Httpd(name)
    set env(SERVER_SOFTWARE) $Httpd(server)
    set env(SERVER_PROTOCOL) HTTP/1.0
    set env(REMOTE_ADDR) $data(ipaddr)
    set env(SCRIPT_NAME) $url
    set env(PATH_INFO) $extra
    set env(PATH_TRANSLATED) [string trimright [Doc_Root] /]/[string trimleft $data(url) /]
    set env(DOCUMENT_ROOT) [Doc_Root]
    set env(HOME) [Doc_Root]

    if {$Cgi(ident)} {
	catch {
	    set ident [::ident::get $sock]
	    set env(REMOTE_IDENT) [lindex $ident 0]
	}
    }

    if {$data(proto) == "POST"} {
	set env(QUERY_STRING) ""
    }
}

# Enable/disable IDENT lookup.  Disabled by default.

proc Cgi_Ident state {
    global Cgi

    regsub {^(1|yes|true|on)$} $state 1 state
    regsub {^(0|no|false|off)$} $state 0 state

    if {$state} {
	package require ident
    }

    set Cgi(ident) $state
}

# Run a cgi script:
# Our caller needs to set up the environment with Cgi_SetEnv.
# Run the script, and copy the
# output to the socket. 
# Set a timer to deal with invalid scripts.

proc CgiSpawn {sock script} {
    upvar #0 Httpd$sock data
    global env Cgi

    if {$Cgi(cgi) >= $Cgi(maxcgi)} {
	Httpd_Error $sock 504  "Too many CGI's"
	return
    }
    incr Cgi(cgi)

    # for GET queries, pass the query as an argument to the cgi script
    if {$data(proto) == "POST"} {
	set arglist ""
    } else {
	set arglist $data(query)
    }
    set pwd [pwd]
    cd [file dirname $script]
    if {[catch {CgiExec $script $arglist} fd]} {
	cd $pwd
	Httpd_Error $sock 400 $fd
	incr Cgi(cgi) -1
	return
    }
    cd $pwd
    Count cgihits
    set data(infile) $fd	;# So close happens in Httpd_SockClose
    set data(header) 0		;# Have not read header yet
    set data(headerlist) {}	;# list of read headers
    set data(headercode) "200 data follows"	;# normal return
    fconfigure $fd -blocking 0

    # Set up a timer in case it hangs

    catch {after cancel $data(cancel)}
    set data(cancel) [after $Cgi(timeout) CgiCancel $fd $sock]

    if {$data(proto) == "POST"} {

        # Read the pipe in auto mode to properly detect the end of
        # headers in Unix and Windows.  Pump the POST data in
        # binary mode.

	fconfigure $fd -translation {auto binary}

	if {$data(count) == 0} {

	    # Either there was no POST data, or we are inside a domain
	    # that automatically read the POST data into data(query) already
	    # Errors appear here because of the non-blocking writes.

	    catch {
		puts -nonewline $fd $data(query)
		flush $fd
	    }
	} else {

	    # Pump the query data to the CGI process in the background
	    # We set up fileevents after this finishes, so return now

	    # fcopy bug in Tcl 8.3.2 and Tcl 8.4a2 and all previous versions 
	    # prevents this from working reliably on large amounts of POST data
	    # fcopy $sock $fd -command [list CgiCopyDone $sock $fd] -size $data(count)
	    fileevent $sock readable [list CgiCopyPost $sock $fd]
	    return
	}
    }

    CgiCopyDone $sock $fd $data(count) ""
}

# CgiCopyPost --
#
#	Called to copy POST data down the pipe - need to avoid fcopy bug

proc CgiCopyPost {sock fd} {
    upvar #0 Httpd$sock data
    global tcl_version

    set buf [read $sock $data(count)]
    puts -nonewline $fd $buf
    if {$tcl_version <= 8.0} {
	set len [string length $buf]
    } else {
	# Ensure we get byte count, not I18N character count
	set len [string bytelength $buf]
    }
    set data(count) [expr {$data(count) - $len}]
    if {$data(count) <= 0} {
	flush $fd
	CgiCopyDone $sock $fd dummy ""
    }
}

# CgiCopyDone --
#
#	Called when we have finished copying POST data to the CGI process

proc CgiCopyDone {sock fd bytes {errmsg {}}} {
    upvar #0 Httpd$sock data

    # Reset this otherwise the Httpd module tries to read the
    # extra data

    set data(count) 0

    if {[string length $errmsg]} {
	CgiCancel
    } else {
	# Wait for output from the CGI process (CgiRead)
	# Watch the socket (CgiCleanup)
	# In a worker thread, this is not really a socket, hence the catch.

	catch {fileevent $sock readable [list CgiCleanup $fd $sock]}
	fileevent $fd readable [list CgiRead $fd $sock]
    }
}

# Execute the CGI process.

proc CgiExec {script arglist} {
    global tcl_platform
    global Cgi
    switch -- $tcl_platform(platform) {
	unix {
	    if {[file exists /dev/stdout]} {

		# This trick "2> /dev/stdout" fails if you start the process in
		# the background under an xterm, then quit the xterm.  In that case
		# the open raises an error.

		if { ! [catch {open "|[list $script] $arglist 2> /dev/stdout" r+} pipe]} {
		    return $pipe
		}
	    }

	    # We use cat to merge the stderr and stdout

	    return [open "|[list $script] $arglist |& cat" r+]
	}
	windows {
	    switch -- [file extension $script] {
		.pl {
		    return [open "|[list $Cgi(perl) $script] $arglist" r+]
		}
		.cgi {
		    return [open "|[list $Cgi(cgiexe) $script] $arglist" r+]
		}
		.tcl {
		    return [open "|[list $Cgi(tclsh) $script] $arglist" r+]
		}
		.exe {
		    return [open "|[list $script] $arglist" r+]
		}
		default {
		    error "Don't know how to execute CGI $script"
		}
	    }
	}
	macintosh {
	    error "CGI not supported on Macintosh"
	}
    }
}

# Read data from the CGI script, write to client.

proc CgiRead {fd sock} {
    upvar #0 Httpd$sock data
    global Cgi Httpd

    if {[eof $fd]} {
	CgiClose $fd $sock
    } elseif {[catch {
	if {!$data(header)} {

	    # Read and accumulate headers until we know what kind
	    # of response to make

	    set n [gets $fd line]
	    if {$n < 0} {
		# Blocked or EOF - do nothing.
		# EOF will be caught on next fileevent.
		# Blocked means we have a partial line, just wait.
	    } elseif {$n == 0} {
		set data(header) 1
		append header "HTTP/1.0 $data(headercode)\n"
		append header "Server: $Httpd(server)\n"
		append header "Date: [Httpd_Date [clock seconds]]\n"
		append header "Connection: Close\n"
		foreach line $data(headerlist) {
		    append header $line\n
		}
		append header "\n"
		CgiPutHeader $sock $header
	    } else {
		lappend data(headerlist) $line
		if {[regexp -nocase ^(location|uri): $line]} {
		    set data(headercode) "302 found"
		}
	    }
	} else {

	    CgiCopy $fd $sock
	}
    } oops]} {
	# Socket may have gone away
	CgiCancel $fd $sock
    }
}

# Emit the header, handling the case where we are in a worker thread.

proc CgiPutHeader {sock header} {
    upvar #0 Httpd$sock data
    if {[info exist data(master_thread)] &&
            $data(master_thread) != [Thread_Id]} {

        Thread_Send $data(master_thread) \
            [list CgiCopyDirect $sock $header]
        Thread_Send $data(master_thread) \
            [list fconfigure $sock -translation binary]
    } else {
        puts -nonewline $sock $header
    }

}

# Copy data from the pipe to the socket

proc CgiCopy {fd sock} {
    upvar #0 Httpd$sock data
    global Httpd

    fconfigure $fd -translation binary
    if {[info exist data(master_thread)] &&
            $data(master_thread) != [Thread_Id]} {
        # Read the data and copy it to the main thread for return.
        # Quick and dirty until we can transfer file descriptors.
        # The pipe is already non-blocking - read what we can

        Thread_SendAsync $data(master_thread) \
                    [list CgiCopyDirect $sock [read $fd]]

        return
    }

    # Normal one-thread case - set up to copy data from pipe to socket

    fconfigure $sock -translation binary
    fileevent $sock readable {}
    fileevent $fd readable {}
    fcopy $fd $sock -command [list CgiClose $fd $sock]
}

proc CgiCopyDirect {sock block} {
    puts -nonewline $sock $block
    flush $sock
}

# This is installed after running the sub-process to
# check for eof on the socket before the processing is complete.

proc CgiCleanup {fd sock} {
    fconfigure $sock -blocking 0 -translation auto
    set n [gets $sock line]
    if {[eof $sock]} {
	CgiCancel $fd $sock
    }
}

# Cancel a cgi script if it is taking too long.

proc CgiCancel {fd sock} {
    upvar #0 Httpd$sock data

    if {[info exist data(url)]} {
	Log $sock CgiCancel $data(url)
    }
    catch {exec kill [pid $fd]}
    CgiClose $fd $sock
}

# Close down the CGI connection

proc CgiClose {fd sock {bytes {}} {error {}}} {
    global Cgi
    upvar #0 Httpd$sock data

    catch {after cancel $data(cancel)}
    incr Cgi(cgi) -1
    if {![info exists data(header)]} {
	Httpd_Error $sock 204
    } else {
	Httpd_SockClose $sock 1
    }
    if {[string length $error] > 0} {
	Log $sock CgiClose $error
    }
}

Added modules/httpd/config.tcl.



































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# config.tcl
#
# This provides a simple module to manage configuration variables
#
# Brent Welch (c) 2000 Scriptics Corporation
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: config.tcl,v 1.4 2004/09/05 05:10:13 coldstore Exp $

package provide httpd::config 1.0

namespace eval config {
    
    # The main array holding the configuration information

    variable Config

    # The file containing the configuration information

    variable ConfigFile

    namespace export cget
}

# config::init --
#
#	Get the list of resources from disk.
#
# Arguments:
#	config		The name of the configuration file (optional)
#	aname		Name of array containing default configuration
#			values on input, and the new values after
#			processing the config file.
#
# Side Effects:
#	Defines the Config parameter array and records the name of
#	the configuration file in ConfigFile

proc config::init {config aname} {
    upvar 1 $aname TheirConfig
    variable Config
    variable ConfigFile

    if {[catch {open $config} in]} {
	return -code error "Cannot read configuration file \"$config\"\nError: $in"
    }
    set X [read $in]
    close $in

    # Load the file into a safe interpreter that just creates Config array

    set i [interp create -safe]
    if {$::tcl_version >= 8.5} {
      namespace ensemble create -command ::SafeFile -map {
        isdirectory {::file isdirectory}
        exists      {::file exists}
        join        {::file join}
        dirname     {::file dirname}
      }
      $i alias file SafeFile
    } else {
      interp expose $i file
    }
    $i alias fileutil::tempdir ::fileutil::tempdir 

    # Create the slave's Config array, then source the config script

    interp eval $i [list array set Config [array get TheirConfig]]

    interp eval $i {
	proc Config {name {value {}}} {
	    global Config
	    if {![info exist Config($name)] || [string length $value]} {
		set Config($name) $value
	    } else {
		set Config($name)
	    }
	}
    }
    if {[catch {interp eval $i $X} err]} {
	return -code error "Error in configuration file \"$config\"\n:Error: $err"
    }
    array set Config [interp eval $i {array get Config}]
    interp delete $i

    set ConfigFile $config
}

# config::cget --
#
#	Get the value for an index in the Config array.
#
# Arguments:
#	index	index in Config array to get.
#
# Results:
#	Returns the value of Config for the given index, or "" if
#	there is no such index.

proc config::cget {index} {
    variable Config

    if {![info exists Config($index)]} {
	return ""
    }
    return $Config($index)
}

# config::setValue --
#
#	Set one or more values for an index(es) in the Config array, and store
#	the array's new contents in the configuration file.
#
# Arguments:
#	args	A list of index, value pairs
#
# Results:
#	None.

proc config::setValue {args} {
    variable Config
    variable ConfigFile

    if {![info exist ConfigFile]} {
	return -code error "config is not initialized"
    }
    set in "(original lost)"
    if {![file exists $ConfigFile] || [catch {open $ConfigFile} in]} {
	set note "# Emergency copy: $in\n"
	unset in
    }
    append note "# Last modified: [clock format [clock seconds]]\n"

    # Re-write config file

    if {![info exist in]} {

	# We've lost the original, just dump out the array

	if {[catch {open $ConfigFile w} out]} {
	    return -code error "Cannot create configuration file: $out"
	}
	puts $out "# Server Configuration File\n$note\n"
	foreach name [lsort [array names Config]] {
	    puts $out [list Config $name $Config($name)]\n
	}
	close $out
    } else {
	
	# Re-write the original, inserting the new values.
	# This code only supports values that fit on one line

	set X [read $in]
	close $in
	if {[catch {open $ConfigFile w} out]} {
	    return -code error "Cannot re-write configuration file: $out"
	}

	regsub "^# Last modified:.*?\n" $X $note X

	foreach {name value} $args {
	    if {[regsub -all "\n\\s*?Config\\s*?[list $name](\\s*?).*?\n" $X \
			    "\nConfig [list $name]\\1 [list $value]\n" X] == 0} {
		append X "\n[list Config $name $value]\n"
	    }
	}
	puts -nonewline $out $X
	close $out
    }
    
    # Update in-memory information

    array set Config $args

    return
}

Added modules/httpd/cookie.tcl.

































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# cookie.tcl
#@c Cookie support
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: cookie.tcl,v 1.11 2005/01/02 03:36:38 coldstore Exp $

package provide httpd::cookie 1.0

package require httpd	;# Httpd_CurrentSocket Httpd_RemoveCookies Httpd_SetCookie
package require httpd::utils	;# K file lassign

# Cookie_Save
#
#@c	instruct httpd to return cookies, if any, to the browser
#
# Arguments:
#@a	interp  The interpreter in which to subst.

proc Cookie_Save {sock {interp {}}} {
    global Cookie
    if {![catch {
	interp eval $interp {uplevel #0 {set Cookie(set-cookie)}}
    } cookie]} {
	foreach c $cookie {
	    Httpd_SetCookie $sock $c
	}
	interp eval $interp {uplevel #0 {unset Cookie(set-cookie)}}
    }
}

# Cookie_Get
#
#@c	Return a *list* of cookie values, if present, else ""
#@c	It is possible for multiple cookies with the same key
#@c	to be present, so we return a list.
#@c     WARNING: This uses the environment HTTP_COOKIE, which can
#@c     get stomped on if a request reenters the event loop
#@c	See also Cookie_GetSock that doesn't have this problem
#
# Arguments:
#@a	cookie	The name of the cookie (the key)
# Returns:
#@r	a list of cookie values matching argument

proc Cookie_Get {cookie} {
    global env
    set result ""
    if {[info exist env(HTTP_COOKIE)]} {
	set rawcookie $env(HTTP_COOKIE)
    } else {
	# Try to find the connection
	if {[info exists env(HTTP_CHANNEL)]} {
	    upvar #0 Httpd$env(HTTP_CHANNEL) data
	    if {[info exist data(mime,cookie)]} {
		set rawcookie $data(mime,cookie)
	    }
	}
    }
    if {[info exist rawcookie]} {
	foreach pair [split $rawcookie \;] {
	    lassign [split [string trim $pair] =] key value
	    if {[string compare $cookie $key] == 0} {
		lappend result $value
	    }
	}
    }
    return $result
}

# Cookie_GetSock
#
#@c	Return a *list* of cookie values, if present, else ""
#@c	It is possible for multiple cookies with the same key
#@c	to be present, so we return a list.
#@c     This always gets the cookie state associated with the specified
#@c     socket, unlike Cookie_Get that looks at the environment.
#
# Arguments:
#@a	cookie	The name of the cookie (the key)
#@a	sock	A handle on the socket connection
# Returns:
#@r	a list of cookie values matching argument

proc Cookie_GetSock {sock cookie} {
    upvar #0 Httpd$sock data
    set result ""
    set rawcookie ""
    if {[info exist data(mime,cookie)]} {
        set rawcookie $data(mime,cookie)
    }
    foreach pair [split $rawcookie \;] {
        lassign [split [string trim $pair] =] key value
        if {[string compare $cookie $key] == 0} {
            lappend result $value
        }
    }
    return $result
}

# Cookie_Make
#
#$c	make a cookie from name value pairs
#
# Arguments:
#	args	Name value pairs, where the names are:
#@a		-name	Cookie name
#@a		-value	Cookie value
#@a		-path	Path restriction
#@a		-domain	domain restriction
#@a		-expires	Time restriction
#@a		-secure Append "secure" to cookie attributes
#@r	a formatted cookie

proc Cookie_Make {args} {
    array set opt $args
    set line "$opt(-name)=$opt(-value) ;"
    foreach extra {path domain} {
	if {[info exist opt(-$extra)]} {
	    append line " $extra=$opt(-$extra) ;"
	}
    }
    if {[info exist opt(-expires)]} {
	switch -glob -- $opt(-expires) {
	    *GMT {
		set expires $opt(-expires)
	    }
	    default {
		set expires [clock format [clock scan $opt(-expires)] \
			-format "%A, %d-%b-%Y %H:%M:%S GMT" -gmt 1]
	    }
	}
	append line " expires=$expires ;"
    }
    if {[info exist opt(-secure)]} {
	append line " secure "
    }
    return $line
}


# Cookie_Set
#
#$c	Set a return cookie
#
# Arguments:
#	args	Name value pairs, where the names are:
#@a		-name	Cookie name
#@a		-value	Cookie value
#@a		-path	Path restriction
#@a		-domain	domain restriction
#@a		-expires	Time restriction

proc Cookie_Set {args} {
    global Cookie
    lappend Cookie(set-cookie) [Cookie_Make {*}$args]
}


# Cookie_UnSet
#
#$c	Unset a return cookie
#
# Arguments:
#	args	Name value pairs, where the names are:
#@a		-name	Cookie name
#@a		-path	Path restriction
#@a		-domain	domain restriction
proc Cookie_Unset {name args} {
  Httpd_RemoveCookies [Httpd_CurrentSocket] $name
  Cookie_Set -name $name -value "" -expires [clock format [clock scan "last year"] -format "%A, %d-%b-%Y %H:%M:%S GMT" -gmt 1] {*}$args
}

Added modules/httpd/counter.tcl.





























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# counter.tcl
#
# Global counters and histograms
#
# This module was generalized and moved into the Standard Tcl Library.
# This code is now a thin layer over that more general package.
#
# We pre-declare any non-simple counters (e.g., the time-based
# histogram for urlhits, and the interval-histogram for service times)
# and everything else defaults to a basic counter.  Once things
# are declared, the counter::count function counts things for us.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: counter.tcl,v 1.20 2004/09/05 05:10:13 coldstore Exp $

# Layer ourselves on top of the Standard Tcl Library counter package.

package require counter 2.0
package provide httpd::counter 2.0

package require httpd	;# Httpd_RegisterShutdown
package require httpd::log	;# Log
package require httpd::utils	;# file parray

proc Counter_Init {{secsPerMinute 60}} {
    global counter
    if {[info exists counter]} {
	unset counter
    }
    set counter(starttime) [clock seconds]
    
    # The Count procedure will be self-initializing because
    # the counter::count module is not.  The knownTags list is
    # searched to determine if we need to initialize the counter.
    # Predefine well known counters here.

    # urlhits is the number of requests serviced.

    counter::init urlhits -timehist $secsPerMinute

    # This start/stop timer is used for connection service times.
    # The linear histogram has buckets of 5 msec.

    counter::init serviceTime -hist 0.005

    # This log-scale histogram multiplies the seconds time by
    # 1000 to get milliseconds, and then plots the log of that.
    # The log-base histgram isn't useful
    #counter::init serviceTime -histlog 10

    # These group counters are used for per-page hit, notfound, and error
    # statistics.  If you auto-gen unique URLS, these are a memory leak
    # that you can plug by doing
    #
    #	status::countInit hit -simple

    foreach g {domainHit hit notfound errors} {
	counter::init $g -group $g
    }

    # These are simple counters about each kind of connection event

    foreach c {accepts sockets connections urlreply keepalive connclose 
		http1.0 http1.1 cgihits} {
	counter::init $c
    }
    Httpd_RegisterShutdown Counter_CheckPoint
}

proc Counter_CheckPoint {} {
    global Log
    if {[info exists Log(log)]} {
	set path $Log(log)counter
	catch {file rename -force $path $path.old}
	if {![catch {open $path w} out]} {
	    puts $out \n[parray counter]
	    puts $out \n[parray [counter::get urlhits -histVar]]
	    puts $out \n[parray [counter::get urlhits -histHourVar]]
	    puts $out \n[parray [counter::get urlhits -histDayVar]]
	    close $out
	}
    }
}

proc Count {what {delta 1}} {
    if {![counter::exists $what]} {
	counter::init $what
    }
    counter::count $what $delta
}

proc CountName {instance tag} {
    if {![counter::exists $tag]} {
	counter::init $tag
    }
    counter::count $tag 1 $instance
}

proc Counter_Reset {what args} {
  counter::reset $what {*}$args
}

proc CountHist {what {delta 1}} {
  counter::count $what $delta
}

proc CountStart {what instance} {
  counter::start $what $instance
}
proc CountStop {what instance} {
  counter::stop $what $instance
#    counter::stop $what $instance CountMsec
}
proc CountMsec {x} {
    return [expr {$x * 1000}]
}
proc CountVarName {what} {
    return [counter::get $what -totalVar]
}
proc Counter_StartTime {} {
    return $counter::startTime
}

Added modules/httpd/debug.tcl.











































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
# debug.tcl --
#
#	Application-direct URLs to help debug the server.
# 	Tcl procedures of the form Debug/hello implement URLS
#	of the form /debug/hello
#
# Copyright (c) 1998-2000 by Ajuba Solutions.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: debug.tcl,v 1.21 2004/09/05 05:10:13 coldstore Exp $

package provide httpd::debug 1.0

package require httpd	;# Httpd_Webmaster
package require httpd::config	;# Config
package require httpd::direct	;# Direct_Url Direct_UrlRemove
package require httpd::status	;# Version
package require httpd::threadmgr	;# Thread_List Thread_Send
package require httpd::utils	;# Stderr file parray

# Debug_Url
#
#       Use this to register the URL prefix that corresponds to
#       the debug URLs implemented by this module
#
# Arguments:
#	dir	The URL prefix

proc Debug_Url {dir} {
    Direct_Url $dir Debug
    DebugSetRandomPassword $dir
}

# DebugSetRandomPassword
#
#       Choose and save a random password used to secure the /debug domain

proc DebugSetRandomPassword {dir} {
  set alphabet {a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 . + - =}
  for {set i 0} {$i < 12} {incr i} {
    set c [lindex $alphabet [expr int(rand() * [llength $alphabet])]]
    append passwd $c
  }
  set ::DebugPassword $passwd
  # This lets the admin see this important password during startup.
  # It is also displayed by the Tk srvui interface.
  Stderr "$dir user \"debug\" password \"$passwd\""
}

# DebugPasswordChecker
#
#	This is called to verify the username and password
#
# Arguments:
#	sock	Handle on the client connection
#	realm	Should be the realm we define above
#	user	The user name
#	pass	The password
#
# Results:
#	1	if access is allowed
#	0	if access is denied

proc DebugPasswordChecker {sock realm user pass} {
    # Any user will do, really, if you know the random password
    switch $user {
        tclhttpd -
        debug -
        default {
          return [DebugCheckRandomPassword $pass]
        }
    }
    return 0
}

# DebugCheckRandomPassword
#
#       Check that the input matches the random password

proc DebugCheckRandomPassword {input} {
  if {![info exist ::DebugPassword]} {
    return 0
  }
  return [expr {[string compare $::DebugPassword $input] == 0}]
}

# Debug/source --
#
#	Source the file into a server thread.  First look for the file to
#	source in the dir specified by Httpd(library).  If not found, use the
#	dir in Doc(templateLibrary) or Config(lib).
#
# Arguments:
#	source	the file to source
#
# Results:
#	Returns HTML code that displays result of loading the file.

proc Debug/source {source {thread main}} {
    global Httpd Doc Config
    set source [file tail $source]
    set dirlist $Httpd(library)
    if {[info exists Doc(templateLibrary)]} {
	lappend dirlist $Doc(templateLibrary)
    }
    if {[info exists Config(library)]} {
	lappend dirlist $Config(library)
    }
    if {[info exists Config(lib)]} {
	lappend dirlist $Config(lib)
    }
    foreach dir $dirlist {
	set file [file join $dir $source]
	if {[file exists $file]} {
	    break
	}
    }
    if {![file exists $file]} {
      set html "<h1>Error sourcing $source</h1>"
      append html "Cannot find it in <br>[join $dirlist <br>]"
      return $html
    }
      
    set error [catch {
	switch -- $thread {
	    main {
		uplevel #0 [list source $file]
	    }
	    all {
		foreach id [Thread_List] {
		    Thread_Send $id [list source $file]
		}
	    }
	    default {
                Thread_Send $thread [list source $file]
	    }
	}
    } result]
    set html "<title>Source $source</title>\n"
    if {$error} {
	global errorInfo
	append html "<H1>Error in $source</H1>\n"
	append html "<pre>$result<p>$errorInfo</pre>"
    } else {
	append html "<H1>Reloaded $source</H1>\n"
	append html "<pre>$result</pre>"
    }
    return $html
}

# Debug/package --
#
#	Forget, delete, and the reload a package into the server.
#
# Arguments:
#	name	the package to reload.
#
# Results:
#	Returns HTML code that displays the result of reloading the package.

proc Debug/package {name} {
    if {[catch {
	package forget $name
	catch {namespace delete $name}
	package require $name
    } result]} {
	set html "<title>Error</title>
<H1>Error Reloading Package $name</H1>

Unable to reload package \"$name\" due to:
<PRE>
$result
</PRE>
"
    } else {
	set html "<title>Package reloaded</title>
<H1>Reloaded Package $name</H1>
 
Version $result of package \"$name\" has been (re)loaded.
"
    }
 
    return $html
}
 
# Debug/pvalue --
#
#	Generate HTML code that displays the contents of all existing arrays
#	and variables that match the glob pattern.
#
# Arguments:
#	aname	the (fully qualified) glob pattern to match against existing
#		arrays and variables.
#
# Results:
#	Returns HTML code that displays the contents of the arrays and
#	variables that match the glob pattern.

proc Debug/pvalue {aname} {
    set html "<title>$aname</title>\n"
    append html [DebugValue $aname]
    return $html
}
proc DebugValue {aname} {
    upvar #0 $aname var
    append html "<p><b><font size=+=>$aname</font></b><br>\n"
    if {[array exists var]} {
	global $aname
	append html "<pre>[parray $aname]</pre>"
    } elseif {[info exists var]} {
	append html "<pre>[list set $aname $var]</pre>"
    } else {
	# Undefined variable - see if it is a pattern.
	# Be careful about declared but undefined procedures
	# that used to blow the recursion stack here...

	set list [lsort [uplevel #0 [list info vars $aname]]]
	if {[llength $list] == 1 &&
		[string compare [lindex $list 0] $aname] == 0} {
	    append html "<pre># $aname undefined</pre>"
	} else {
	    append html "<ul>"
	    foreach n $list {
		append html [DebugValue $n]
	    }
	    append html "</ul>"
	}
    }
    return $html
}

# Debug/parray --
#
#	Generate HTML code that displays 
#
# Arguments:
#	aname	the name of the array whose contents will appear.
#
# Results:
#	Returns HTML code that displays 

proc Debug/parray {aname} {
    global $aname
    set html "<title>Array $aname</title>\n"
    append html "<H1>Array $aname</H1>\n"
    append html "<pre>[parray $aname]</pre>"
    return $html
}

# Debug/raise --
#
#	Generate HTML code that causes the Tcl error specified by args to be thrown.
#
# Arguments:
#	args	(optional) the error string to throw.
#
# Side Effects:
#	An error is thrown.
#
# Results:
#	none.

proc Debug/raise {args} {
    error $args
}

# Debug/goof --
#
#	Generate HTML code that causes the Tcl error: "can't read "goof": no
#	such variable".
#
# Arguments:
#	none.
#
# Side Effects:
#	An error is thrown.
#
# Results:
#	None.

proc Debug/goof {} {
    set goof
    return
}

# Debug/after --
#
#	Generate HTML code that displays info regarding after events existing
#	on the server.
#
# Arguments:
#	none.
#
# Results:
#	Returns HTML.

proc Debug/after {} {
    global tcl_version
    set html "<title>After Queue</title>\n"
    append html "<H1>After Queue</H1>\n"
    append html "<pre>"
    if {[catch {after info} afterlist]} {
	append html "\"after info\" not supported in Tcl $tcl_version"
    } else {
	foreach a $afterlist {
	    append html "$a [after info $a]\n"
	}
    }
    append html </pre>
    return $html
}

# Debug/echo --
#
#	Generate HTML code that displays the attributes and values posted to
#	the URL.
#
# Arguments:
#	title	(optional) title to display
#	args	an even number of attrbutes and values to be displayed.
#
# Results:
#	Returns HTML.

proc Debug/echo {title args} {
    set html "<title>$title</title>\n"
    append html "<H1>$title</H1>\n"
    append html "<table border=1>\n"
    foreach {name value} $args {
	append html "<tr><td>$name</td><td>$value</td></tr>\n"
    }
    append html </table>
    return $html
}

# Debug/errorInfo --
#
#	Generate HTML code that displays a title, some errorInfo, and the
#	contents of (the env) array.
#
# Arguments:
#	title		(optional) page title to display
#	errorInfo	(optional) error data to display
#	env		(optional) the name of an array to display
#
# Results:
#	Returns HTML.

proc Debug/errorInfo {title errorInfo {env {no environment}}} {
    set html "<title>$title</title>\n"
    append html "<H1>$title</H1>\n"
    append html "<p>[Version]"
    append html "<br>Webmaster: [Httpd_Webmaster]"
    append html <pre>$errorInfo</pre>
    append html "<p>Environment:</p>"
    append html "<table>"
    catch {
    array set X $env
    foreach n [lsort [array names X]] {
	append html "<tr><td>$n</td><td>$X($n)</td></tr>\n"
    }
    }
    append html "</table>"
    return $html
}

# Debug/dbg --
#
#	Initiate a connection with the tcldebugger.
#
# Arguments:
#	host	the host where the debugger is running
#	port	the port on which the debugger is listening
#
# Results:
#	Returns the result of initiating the connection in HTML.

proc Debug/dbg {host port} {
    global debug_init Httpd

    # In case application-direct parameter bindings are broken,
    # use the local host and default prodebug port.
    if {$host == ""} {
	set host [info hostname]
    }
    if {$port == ""} {
	set port 2576
    }

    if {![info exist debug_init]} {
	if {[info command debugger_init] == ""} {
	    source [file join $Httpd(library) prodebug.tcl]
	}
	debugger_init $host $port
	set debug_init "$host $port"
	return "Contacted TclPro debugger at $host:$port"
    }
    return "Already connected to tclPro at $debug_init"
}

# Debug/showproc --
#
#	Generate HTML code that displays the args and body of a proc.
#
# Arguments:
#	proc	the name of the procedure
#
# Results:
#	Returns HTML.

proc Debug/showproc {proc} {
    global Debug/showproc
    set Debug/showproc text/plain

    set alist ""
    foreach arg [info args $proc] {
        if {[info default $proc $arg default]} {
            set arg [list $arg $default]
        }
        lappend alist $arg
    }
    return [list proc $proc $alist [info body $proc]]
}

# Debug/disable --
#
#	Disable debugging in tclhttpd.
#
# Side Effects:
#       Removes the /debug URL

proc Debug/disable {} {
    Direct_UrlRemove Debug
    return "<title>Debugging disabled</title>\n
                    <h1> Debugging disabled</h1>"
}  

Added modules/httpd/digest.tcl.













































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# digest.tcl
#
# Provides Digest Authentication, per http://www.ietf.org/rfc/rfc2617.txt
# Works in conjunction with auth.tcl, requires tcllib.
# Digest authentication is selectable in .htaccess.
# No provision for dual Basic/Digest authentication.
#
# Supports only algorithm=MD5 and qop=auth
# (which is more than most browsers support :)
#
# Copyright 2004 Colin McCormack.  [email protected]
# Licensed on terms identical to tclhttpd's license.

package require base64

package provide httpd::digest 1.0
package require httpd::md5hex
package require httpd::auth

# generate private key
if {[catch {package require Random}]} {
    # use the built in tcl random
    proc DigestRand {} {
	return [expr {rand() * 65536}]
    }
} else {
    # use http://mini.net/tcl/random
    # cvs -d:pserver:[email protected]:/cvsroot/tclsoap co Random
    # generate a random seed
    if {[catch {
	# try for hardware support
	set r [open /dev/random]
	binary scan [read $r 4] I seed
	close $r
    }]} {
	set seed [clock clicks]
    }
    ::isaac::isaac seed $seed	;# seed random

    # get an integer secret
    proc DigestRand {} {
	return [::isaac::isaac integer]
    }
}
set DigestSecret [DigestRand]

proc Digest_Passwd {username realm passwd} {
    return [string tolower [md5hex "$username:$realm:$passwd"]]
}

# calculate a digest key for a given session
proc DigestA1 {sock} {
    upvar #0 Httpd$sock data
    upvar #0 Digest$data(digest,nonce) digest

    # create a digest for this socket
    set userstuff "$data(digest,username):$data(digest,realm):$digest(passwd)"
    #Stderr "DigestA1: $userstuff"
    switch -- [string tolower $data(digest,algorithm)] {
	md5 {
	    set digest(A1) [md5hex $userstuff]
	}
	md5-sess {
	    set digest(A1) [md5hex "[string tolower [md5hex $userstuff]]:$data(digest,nonce):$data(digest,cnonce)"]
	}
	default {
	    error "unknown algorithm: $data(digest,algorithm)"
	}
    }
    set digest(A1) [string tolower $digest(A1)]
    return $digest(A1)
}

# per operation hash
proc DigestA2 {sock} {
    upvar #0 Httpd$sock data
    set uri $data(digest,uri)
    regexp {[^?]+} $uri uri
    if {[info exists data(proto)]} {
	#Stderr "A2: op:$data(proto) uri:$data(digest,uri)"
	set result [string tolower [md5hex "[string toupper $data(proto)]:$data(digest,uri)"]]
	# nb: we don't offer auth-int
    } else {
	#Stderr "A2: uri:$data(digest,uri)"
	set result [string tolower [md5hex "GET:$data(digest,uri)"]]
    }
    return [string tolower $result]
}

# generate a nonce
proc DigestNonce {} {
    #return "dcd98b7102dd2f0e8b11d0f600bfb0c093"	;# test

    global DigestSecret
    set time [clock clicks]
    return [string tolower [md5hex ${time}:${DigestSecret}]]
}

# calculate the digest value for a given operation and session
proc DigestDigest {sock} {
    upvar #0 Httpd$sock data
    upvar #0 Digest$data(digest,nonce) digest
    if {![info exists digest(A1)]} {
	set digest(A1) [DigestA1 $sock]
    }
    set digest(A2) [DigestA2 $sock]

    #Stderr "DigestDigest A1:$digest(A1) A2:$digest(A2) nc:[format %08x $data(digest,nc)] cnonce:$data(digest,cnonce) qop:$data(digest,qop)"

    if {[info exists data(digest,qop)]} {
	set result [md5hex "$digest(A1):$data(digest,nonce):[format %08x $data(digest,nc)]:$data(digest,cnonce):$data(digest,qop):$digest(A2)"]
    } else {
	set result [md5hex "$digest(A1):$data(digest,nonce):$digest(A2)"]
    }
    return [string tolower $result]
}

# handle the client's Digest
proc Digest_Request {sock realm file} {
    upvar #0 Httpd$sock data
    upvar #0 Digest$data(digest,nonce) digest
    set digest(last) [clock clicks]	;# remember the last use

    if {![info exists digest(A1)]} {
	set A1 [AuthGetPass $sock $file $data(digest,username)@$data(digest,realm)]
	if {$A1 != "*"} {
	    set digest(A1) $A1
	} else {
	    # no digest password on record - use plaintext password
	    if {![info exists digest(passwd)]} {
		set digest(passwd) [AuthGetPass $sock $file $data(digest,username)]
	    }
	    set digest(A1) [DigestA1 $sock]
	    #Stderr "Plaintext password $digest(passwd)"
	}
	#Stderr "A1 Calc: $digest(A1)"
    }

    # check that realms match
    if {$realm != $data(digest,realm)} {
	#Stderr "realm"
	return 0
    }

    #Stderr "Digest_Request: [array get digest] - [array get data digest,*]"

    if {[info exists digest(opaque)]} {
	if {$digest(opaque) != $data(digest,opaque)} {
	    #Stderr "Digest Opaque $digest(opaque) ne $data(digest,opaque)"
	    return 0
	}
    }

    # check the nonce count
    set data(digest,nc) [scan $data(digest,nc) %08x]
    if {[info exists digest(nc)]} {
	if { $data(digest,nc) <= $digest(nc)} {
	    set digest(stale) 1
	    #Stderr "Digest Stale $digest(nc) ne $data(digest,nc)"
	    #return 0	;# Mozilla doesn't implement nc
	}
	#Stderr "Digest nc $digest(nc) - $data(digest,nc)"
    } else {
	#Stderr "Digest New Nonce $data(digest,nc)"
	return 0	;# this is new to us
    }
    set digest(nc) $data(digest,nc)

    # check the password
    set calc_digest [DigestDigest $sock]
    if {$calc_digest != $data(digest,response)} {
	#Stderr "Digest Response: $calc_digest ne $data(digest,response)"
	return 0
    }

    # successful authentication
    # construct authentication args
    set a_args "qop=auth"
    if {[info exists data(digest,cnonce)]} {
	append a_args ", cnonce=\"$data(digest,cnonce)\""
	append a_args ", rspauth=\"${calc_digest}\""
    }
    if {[info exists data(digest,nc)]} {
	append auth_info [format ", nc=%08x" [expr 1 + $data(digest,nc)]]
    }

    # remember some data
    set digest(realm) $data(digest,realm)
    set digest(cnonce) $data(digest,cnonce)
    set digest(username) $data(digest,username)

    # associate nonce with realm,user
    global DigestByRealmName
    set DigestByRealmName($digest(realm),$digest(username)) $digest(nonce)

    Httpd_AddHeaders $sock Authentication-Info $auth_info

    #Stderr "Digest Request OK"
    return 1
}

# decode an Authentication request
# "parts" comes from the Authorization HTTP header.

proc Digest_Get {sock parts} {
    upvar #0 Httpd$sock data
    #Stderr "Digest_Get $parts"
    # get the digest request args
    foreach el [lrange $parts 1 end] {
	set el [string trimright $el ,]
	#foreach {n v} [split $el =] break
	regexp {^[ ]*([^=]+)[ ]*=[ ]*(.*)$} $el junk n v
	#Stderr "Getting: '$el' -> $n $v"
	set data(digest,[string trim $n " "]) [string trim $v " \""]
    }
    #Stderr "Digest Got: [array get data digest,*]"
    # perform some desultory checks on credentials
}

# create and issue a Digest challenge to the client
proc Digest_Challenge {sock realm user} {
    upvar #0 Httpd$sock data

    global DigestByRealmName
    if {[info exists DigestByRealmName($realm,$user)]} {
	# find an existing nonce for this realm,user pair
	set nonce $DigestByRealmName($realm,$user)

	upvar #0 Digest$nonce digest
	set digest(last) [clock clicks]	;# remember the last use
    } else {
	# get a new unique nonce
	# (redundant, really MD5 doesn't collide)
	set nonce [DigestNonce]
	while {[info exists ::Digest$nonce]} {
	    set nonce [DigestNonce]
	}
	upvar #0 Digest$nonce digest
	set digest(last) [clock clicks]	;# remember the last use

	# initialise the digest state
	global DigestSecret
	set digest(nonce) $nonce
	set digest(opaque) [string tolower [md5hex "[clock clicks]${DigestSecret}"]]
	#set digest(opaque) 5ccc069c403ebaf9f0171e9517f40e41	;# test
	set digest(nc) 0
	#set digest(stale) 0
    }

    # construct authentication args
    # minimally nonce, opaque, qop and algorithm
    set challenge [list nonce \"$digest(nonce)\" \
		       domain \"/" \
		       opaque \"$digest(opaque)\" \
		       qop \"auth\" \
		       algorithm MD5]
    #		   algorithm \"MD5,MD5-sess\"
    #if {$digest(stale)} {
    #lappend challenge stale true
    #}

    #Stderr "Digest Challenge: [array get digest] - $challenge"
    # issue Digest authentication challenge
    eval Httpd_RequestAuth $sock Digest $realm $challenge
}

if {0} {
    # test
    array set Httpd999 {
	digest,username Mufasa
	digest,realm [email protected]
	digest,nonce dcd98b7102dd2f0e8b11d0f600bfb0c093
	uri /dir/index.html
	digest,uri /dir/index.html
	op GET
	digest,qop auth
	digest,nc 00000001
	digest,cnonce 0a4f113b
	digest,response 6629fae49393a05397450978507c4ef1
	digest,opaque 5ccc069c403ebaf9f0171e9517f40e41
	digest,algorithm MD5
    }
    array set Digest$Httpd999(digest,nonce) [list last [clock clicks] nc [format %08d 1] opaque $Httpd999(digest,opaque) nonce $Httpd999(digest,nonce) realm [email protected] qop auth,auth-int passwd "Circle Of Life"]

    AuthParseHtaccess 999 /usr/lib/tclhttpd4.0.0/testdigest
    if {[catch {Digest_Request 999 [email protected] /usr/lib/tclhttpd4.0.0/testdigest}  DTest]} {
	error "Digest test error"
    }
    if {$DTest != 1} {
	error "Failed digest test"
    }
}

# nb: mozilla converts UCS2 to UTF8 for username and password

Added modules/httpd/direct.tcl.







































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# direct.tcl
#
# Support for application-direct URLs that result in Tcl procedures
# being invoked inside the server.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: direct.tcl,v 1.21 2004/11/20 07:10:04 coldstore Exp $

package provide httpd::direct 1.1

package require httpd	;# Httpd_Redirect Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::cookie	;# Cookie_Save
package require httpd::doc_error	;# Doc_NotFound
package require httpd::url	;# Url_PrefixInstall Url_PrefixRemove Url_QuerySetup
package require httpd::utils	;# file iscommand

# Direct_Url
#	Define a subtree of the URL hierarchy that is implemented by
#	direct Tcl calls.
#
# Arguments
#	virtual The name of the subtree of the hierarchy, e.g., /device
#	prefix	The Tcl command prefix to use when constructing calls,
#		e.g. Device
#	inThread	True if this should be dispatched to a thread.
#
# Side Effects
#	Register a prefix

proc Direct_Url {virtual {prefix {}} {inThread 0}} {
    global Direct
    if {[string length $prefix] == 0} {
	set prefix $virtual
    }
    set Direct($prefix) $virtual	;# So we can reconstruct URLs
    Url_PrefixInstall $virtual [list DirectDomain $prefix] $inThread
}

# Direct_UrlRemove
#       Remove a subtree of the URL hierarchy that is implemented by
#       direct Tcl calls.
#
# Arguments
#       prefix  The Tcl command prefix used when constructing calls,
#
# Side Effects
#
       
proc Direct_UrlRemove {prefix} {
    global Direct
    catch { Url_PrefixRemove $Direct($prefix) }
    catch { unset Direct($prefix) }
}
        
# Main handler for Direct domains (i.e. tcl commands)
# prefix: the Tcl command prefix of the domain registered with Direct_Url 
# sock: the socket back to the client
# suffix: the part of the url after the domain prefix.
#
# This calls out to the Tcl procedure named "$prefix$suffix",
# with arguments taken from the form parameters.
# Example:
# Direct_Url /device Device
# if the URL is /device/a/b/c, then the Tcl command to handle it
# should be
# proc Device/a/b/c
# You can define the content type for the results of your procedure by
# defining a global variable with the same name as the procedure:
# set Device/a/b/c text/plain
#  The default type is text/html

proc DirectDomain {prefix sock suffix} {
    global Direct
    global env
    upvar #0 Httpd$sock data

    # Set up the environment a-la CGI.

    Cgi_SetEnv $sock $prefix$suffix

    # Prepare an argument data from the query data.

    Url_QuerySetup $sock
    set cmd [Direct_MarshallArguments $prefix $suffix]
    if {$cmd == ""} {
	Doc_NotFound $sock
	return
    }

    # Eval the command.  Errors can be used to trigger redirects.

    set code [catch $cmd result]

    set type text/html
    upvar #0 $prefix$suffix aType
    if {[info exist aType]} {
	set type $aType
    }

    Direct_Respond $sock $code $result $type
}

# Direct_MarshallArguments --
#
#	Use the url prefix, suffix, and cgi values (set with the
#	ncgi package) to create a Tcl command line to invoke.
#
# Arguments:
# 	prefix		The Tcl command prefix of the domain registered 
#			with Direct_Url.
#	suffix		The part of the url after the domain prefix.
#
# Results:
#	Returns a Tcl command line.
#
# Side effects:
#	If the prefix and suffix do not map to a Tcl procedure,
#	returns empty string.

proc Direct_MarshallArguments {prefix suffix} {
    global Direct

    set cmd $prefix$suffix
    if {![iscommand $cmd]} {
	return
    }

    # Compare built-in command's parameters with the form data.
    # Form fields with names that match arguments have that value
    # passed for the corresponding argument.
    # Form fields with no corresponding parameter are collected into args.

    set cmdOrig $cmd
    set params [info args $cmdOrig]
    foreach arg $params {
	if {[ncgi::empty $arg]} {
	    if {[info default $cmdOrig $arg value]} {
		lappend cmd $value
	    } elseif {[string compare $arg "args"] == 0} {
		set needargs yes
	    } else {
		lappend cmd {}
	    }
	} else {
	    
	    # The original semantics for Direct URLS is that if there
	    # is only a single value for a parameter, then no list
	    # structure is added.  Otherwise the parameter gets a list
	    # of all values.

	    set vlist [ncgi::valueList $arg]
	    if {[llength $vlist] == 1} {
		lappend cmd [ncgi::value $arg]
	    } else {
		lappend cmd $vlist
	    }
	}
    }
    if {[info exists needargs]} {
	foreach {name value} [ncgi::nvlist] {
	    if {[lsearch $params $name] < 0} {
		lappend cmd $name $value
	    }
	}
    }
    return $cmd
}

# Direct_Respond --
#
#	This function returns the result of evaluating the direct
#	url.  Usually, this involves returning a page, but a redirect
#	could also occur.
#
# Arguments:
# 	sock	The socket back to the client.
#	code	The return code from evaluating the direct url.
#	result	The return string from evaluating the direct url.
#	type	The mime type to use for the result.  (Defaults to text/html).
#	
#
# Results:
#	None.
#
# Side effects:
#	If code 302 (redirect) is passed, calls Httpd_Redirect to 
#	redirect the current request to the url in result.
#	If code 0 is passed, the result is returned to the client.
#	If any other code is passed, an exception is raised, which
#	will cause a stack trace to be returned to the client.
#

proc Direct_Respond {sock code result {type text/html}} {
    switch $code {
	0 {
	    # Fall through to Httpd_ReturnData.
	}
	302	{
	    # Redirect.

	    Httpd_Redirect $result $sock
	    return ""
	}
	default {
	    # Exception will cause error page to be returned.

	    global errorInfo errorCode
	    return -code $code -errorinfo $errorInfo -errorcode $errorCode \
		    $result
	}
    }

    # See if a content type has been registered for the URL.

    # Save any return cookies which have been set.
    # This works with the Doc_SetCookie procedure that populates
    # the global cookie array.
    Cookie_Save $sock

    Httpd_ReturnData $sock $type $result
    return ""
}

Added modules/httpd/dirlist.tcl.





















































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# dirlist.tcl --
#
# Create a HTML-formatted directory listing
#
# Steve Ball (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: dirlist.tcl,v 1.13 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::dirlist 1.1

package require httpd	;# Httpd_ReturnData
package require httpd::doc	;# Doc_Handle
package require httpd::doc_error	;# Doc_NotFound
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_Encode
package require httpd::utils	;# file file_latest setmax

# DirList_IndexFile --
#
#	Define the index file for a directory
#
# Arguments:
#	pat	A glob pattern for index files in a directory.
#
# Results:
#	None
#
# Side Effects:
#	Sets the index file glob pattern.

proc DirList_IndexFile {pat} {
    global dirlist
    set dirlist(indexpat) $pat
}

# DirList_Directory --
#
#	Handle a directory.  Look for the index file, falling back to
#	the Directory Listing module, if necessary.  If the Directory
#	Listing is hidden, then give the not-found page.
#
# Arguments:
#	prefix	The URL domain prefix.
#	path	The file system pathname of the directory.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Dispatches to the appropriate page handler.

proc DirList_Directory {prefix path suffix sock} {
    upvar #0 Httpd$sock data
    global dirlist tcl_platform

    # Special case because glob doesn't work in wrapped files
    # Just set indexpat to "index.tml" or "index.html"

    set npath [file join $path $dirlist(indexpat)]
    if {[info exist tcl_platform(isWrapped)] && $tcl_platform(isWrapped)} {
	set newest $npath
    } else {
	set newest [file_latest [glob -directory $path -nocomplain -- $dirlist(indexpat)]]
    }
    if {[string length $newest]} {

	# Template hack.  Ask for the corresponding .html file in
	# case that file should be cached when running the template.
	# If we ask for the .tml directly then its result is never cached.
	global Template
	if {[string compare $Template(tmlExt) [file extension $newest]] == 0} {
	    set newest [file root $newest]$Template(htmlExt)
	}
	return [Doc_Handle $prefix $newest $suffix $sock]
    }
    if {[Dir_ListingIsHidden]} {
        # Directory listings are hidden, so give the not-found page.
        return [Doc_NotFound $sock]
    }
    # Listings are not hidden, so show it.
    Httpd_ReturnData $sock text/html [DirList $sock $path $data(url)]
}

# Dir_HideListings --
#
#	If a directory is viewed, hide the directory listing.
#
# Arguments:
#	None
#
# Results:
#	None
#
# Side Effects:
#	From now on, directory listings are hidden.

proc Dir_HideListings {} {
    global Doc
    set Doc(HideDirListing) 1
    return
}

# Dir_ShowListings --
#
#	If a directory is viewed, show the directory listing.
#
# Arguments:
#	None
#
# Results:
#	None
#
# Side Effects:
#	From now on, directory listings can be shown.

proc Dir_ShowListings {} {
    global Doc
    set Doc(HideDirListing) 0
    return
}

# Dir_ListingIsHidden --
#
#	Tell whether directory listings are currently hidden.
#
# Arguments:
#	None
#
# Results:
#	Returns 1 if listings are hidden, otherwise 0.
#
# Side Effects:
#	None

proc Dir_ListingIsHidden {} {
    global Doc
    return $Doc(HideDirListing)
}

# By default, directory listings are shown.
Dir_ShowListings

proc DirListForm {dir urlpath {sort name} {pattern *}} {
    set what [DirListTerm]
    set namecheck ""
    set sizecheck ""
    set numcheck ""
    switch -- $sort {
        number {
	    set numcheck checked
	}
	size {
	    set sizecheck checked
	}
	default {
	    set namecheck checked
	}
    }
    set listing "
<H1>Listing of $what $urlpath</H1>

<form action=$urlpath>
Pattern <input type=text name=pattern value=$pattern><br>
Sort by Modify Date <input type=radio name=sort value=number $numcheck>
or Name <input type=radio name=sort value=name $namecheck>
or Size <input type=radio name=sort value=size $sizecheck><br>
<input type=submit name=submit value='Again'><p>
"
    append listing [DirListInner $dir $urlpath $sort $pattern]
    append listing "</form>\n"
    return $listing
}

proc DirListInner {dir urlpath sort pattern} {
    set listing "<PRE>\n"
    set path [file split $dir]

    # Filter pattern to avoid leaking path information
    regsub -all {\.+/} $pattern {} pattern
    set pattern [string trimleft $pattern /]

    set list [glob -directory $dir -nocomplain -- $pattern]
    if {[llength $path] > 1} {
	append listing \
	    "<A HREF=\"..\">Up to parent [string tolower [DirListTerm]]</A>\n"
    }

    set timeformat "%b %e, %Y %X"
    if {[llength $list] > 0} {
	set max 0
	foreach entry $list {
	    setmax max [string length [file tail $entry]]
	}
	incr max [string length </a>]

	# Resort the list into list2

	switch -- $sort {
	    number {
		set mlist {}
		foreach entry $list {
		    lappend mlist [list $entry [file mtime $entry]]
		}
		if {[catch {lsort -decreasing -integer -index 1 $mlist} list2]} {
		    set list2 [lsort -command DateCompare $mlist]
		}
		set extra 1
	    }
	    size {
		set slist {}
		foreach entry $list {
		    lappend slist [list $entry [file size $entry]]
		}
		if {[catch {lsort -decreasing -integer -index 1 $slist} list2]} {
		    set list2 [lsort -command SizeCompare $slist]
		}
		set extra 1
	    }
	    default {
		if {[catch {lsort -dict $list} list2]} {
		    set list2 [lsort -command DirlistCompare $list]
		}
		set extra 0
	    }
	}

	# Loop through list2, which may have an extra sorting field we ignore

	foreach entry $list2 {
	    if {$extra} {
		set entry [lindex $entry 0]
	    }
	    file lstat $entry lst
	    switch $lst(type) {
		file {
		    # Should determine dingbat from file type
		    append listing "<A HREF=\"[DirHref $entry]\">[format %-*s $max [file tail $entry]</a>] [format %8d $lst(size)] [format %-5s bytes]  [clock format $lst(mtime) -format $timeformat]\n"
		}
		directory {
		    append listing "<A HREF=\"[DirHref $entry]/\">[format %-*s $max [file tail $entry]/</a>] [format %8s {}] [format %-5s dir]  [clock format $lst(mtime) -format $timeformat]\n"
		}
		link {
		    append listing "<A HREF=\"[DirHref $entry]\">[format %-*s $max [file tail $entry]</a>] [format %8s {}] [format %-5s link]  [clock format $lst(mtime) -format $timeformat] -> [file readlink $entry]\n"
		}
		characterSpecial -
		blockSpecial -
		fifo -
		socket {
		    append listing "<A HREF=\"${urlpath}[file tail $entry]\">[format %-20s [file tail $entry]</a>] $lst(type)\n"
		}
	    }
	}
    } else {
	append listing "[DirListTerm] is empty\n"
    }

    append listing "
</PRE>
"
    return $listing
}

proc DirHref {entry} {
    set entry [Url_Encode [file tail $entry]]
    # Decode ".",
    regsub -all -nocase {%2e} $entry . entry
    regsub -all -nocase {%5f} $entry _ entry
    return $entry
}

proc DirList {sock dir urlpath} {
    upvar #0 Httpd$sock data

    set sort name
    set pattern *
    if {[info exists data(query)]} {
	foreach {name value} [Url_DecodeQuery $data(query)] {
	    switch $name {
		sort {set sort $value}
		pattern {set pattern $value}
	    }
	}
    }

    return "
<HTML>
<HEAD>
    <TITLE>Listing of [DirListTerm] $urlpath</TITLE>
</HEAD>
<BODY>
    [DirListForm $dir $urlpath $sort $pattern]
</BODY>
</HTML>"
}

# DirlistCompare --
#
# Utility procedure for case-insensitive filename comparison.
# Suitable for use with lsort

proc DirlistCompare {a b} {
    string compare [string tolower $a] [string tolower $b]
}


proc DateCompare {a b} {
    set a [lindex $a 1]
    set b [lindex $b 1]
    if {$a > $b} {
	return -1
    } elseif {$a < $b} {
	return 1
    } else {
	return 0
    }
}

proc SizeCompare {a b} {
    set aa [lindex $a 1]
    set bb [lindex $b 1]
    set res [string compare $aa $bb]
    if { $res != 0 } {
	return $res
    } else {
	return [string compare $a $b]
    }
}

# DirListTerm --
#
# Return "Folder" or "Directory" as appropriate

proc DirListTerm {} {
    global tcl_platform

    if {[string compare macintosh $tcl_platform(platform)]} {
	set what Directory
    } else {
	set what Folder
    }
    return $what
}

Added modules/httpd/doc.tcl.































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
# doc.tcl
#
# File system based URL support.
# This calls out to the Auth module to check for access files.
# Once a file is found, it checks for content-type handlers defined
# by Tcl procs of the form Doc_$contentType.  If those are present
# then they are responsible for processing the file and returning it.
# Otherwise the file is returned by Doc_Handle.
#
# If a file is not found then a limited form of content negotiation is
# done based on the browser's Accept header.  For example, this makes
# it easy to transition between foo.shtml and foo.html.  Just rename
# the file and content negotiation will find it from old links.
#
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: doc.tcl,v 1.59 2004/12/11 13:22:40 coldstore Exp $

package require uri

package provide httpd::doc 1.1

package require httpd	;# Httpd_ReturnFile
package require httpd::auth	;# Auth_Check Auth_Verify
package require httpd::cgi	;# Cgi_Domain
package require httpd::counter	;# Count CountName
package require httpd::dirlist	;# DirList DirList_Directory
package require httpd::doc_error ;# Doc_NotFound
package require httpd::fallback	;# Fallback_Try
package require httpd::mtype	;# Mtype
package require httpd::redirect	;# Redirect_Dir Redirect_Self Redirect_To
package require httpd::template	;# Template_Dynamic Template_Try
package require httpd::url	;# Url_AccessInstall Url_PathCheck Url_PrefixInstall Url_PrefixMatch
package require httpd::utils	;# file iscommand

# Doc_Root --
#
# Query or set the physical pathname of the document root
#
# Arguments:
#	real 	Optional.  The name of the file system directory
#		containing the root of the URL tree.  If this is empty,
#		then the current document root is returned instead.
#	args	"real" followed by "args" for Url_PrefixInstall.
#		"real" is the name of the file system directory
#		containing the root of the URL tree.  If no args are given,
#		then the current document root is returned instead.
#
# Results:
#	If querying, returns the name of the directory of the document root.
#	Otherwise returns nothing.
#
# Side Effects:
#	Sets the document root.

proc Doc_Root {args} {
    global Doc
    if {[llength $args] > 0} {
        set real [lindex $args 0]
	set Doc(root) $real
	Doc_AddRoot / $real {*}[lrange $args 1 end]
        return
    }
    return $Doc(root)
}

# Doc_AddRoot
#	Add a file system to the virtual document hierarchy
#
# Arguments:
#	virtual		The URL prefix of the document tree to add.
#	directory	The file system directory containing the doc tree.
#	args		Same as args for Url_PrefixInstall
#
# Results:
#	None
#
# Side Effects:
#	Sets up a document URL domain and the document-based access hook.

proc Doc_AddRoot {virtual directory args} {
    Doc_RegisterRoot $virtual $directory
    Url_PrefixInstall $virtual [list DocDomain $virtual $directory] {*}$args
    Url_AccessInstall DocAccessHook
    return
}

# Doc_RegisterRoot
#	Add a file system managed by any Domain Handler (e.g. CGI)
#	This is necessary for Doc_AccessControl to search directories right.
#
# Arguments:
#	virtual		The prefix of the URL
#	directory	The directory that corresponds to $virtual
#
# Results:
#	None
#
# Side Effects:
#	Registers the URL to directory mapping

proc Doc_RegisterRoot {virtual directory} {
    global Doc
    if {[info exist Doc(root,$virtual)] &&
	    [string compare $Doc(root,$virtual) $directory] != 0} {
	return -code error \
		"Doc_RegisterRoot will not change an existing url to directory mapping"
    }
    set Doc(root,$virtual) [file normalize $directory]
}

# Doc_Include
#
#	Read the contents of the file and substitute them at the stack level
#	at which this procedure was called.  Relative paths will be joined
#	with the directory at the top of the include stack in global variable
#	page(includeStack).
#
# Arguments:
#	filename	The relative path of the file to read.
#
# Results:
#	Returns the substituted contents of the file.
#
# Side Effects:
#	None.

proc Doc_Include {filename} {
    global page

    # Use the path at the top of the include stack.
    set oldIncludeStack $page(includeStack)
    set path [file join [lindex $oldIncludeStack 0] $filename]

    # Read the data from the file.
    ::set f [open $path]
    ::set data [read -nonewline $f]
    close $f

    # Call subst on the data in the stack frame above this one.

    # To support nested includes, we use a uniquely named
    # variable to store incremental results.
    ::set resultVar "__result_[expr rand()]"

    # Create the script to eval in the stack frame above this one.
    ::set script "append $resultVar \[subst \{$data\}\]"

    # Create a temporary variable in the stack frame above this one,
    # and use it to store the incremental resutls of the multiple loop
    # iterations.  Remove the temporary variable when we're done so there's
    # no trace of this loop left in that stack frame.
    upvar $resultVar tmp
    ::set tmp ""

    # Including of doc templates can be nested.
    # Push the directory of the file we are subst'ing onto the include stack.
    # Perform the substitution, and the pop that dir from the stack.
    set page(includeStack) [linsert $oldIncludeStack 0 [file dirname $path]]
    uplevel $script
    set page(includeStack) $oldIncludeStack

    ::set result $tmp
    unset tmp
    return $result
}

# Doc_PublicHtml --
#
# Enable URLS of the form ~user/a/b/c and map those to
# a subdirectory of that users account.
#
# Arguments:
#	homedir The directory under a user's home that is their
#		personal URL root.  Defaults to public_html.
#		If this is empty, then user home directories
#		are disabled.
#
# Results:
#	None
#
# Side Effects:
#	Sets the per-user public_html directory name.

proc Doc_PublicHtml {{homedir public_html}} {
    global Doc
    if {[string length $homedir] == 0} {
	catch {unset Doc(homedir)}
    } else {
	set Doc(homedir) [string trim $homedir /]
    }
}

# Doc_Virtual - return a real pathname corresponding to a 
# "virtual" path in an include
#
# Arguments:
#	sock	The client connection.
#	curfile	The pathname of the file that contains the
#		"virtual" URL spec.  This is used to resolve
#		relative URLs.
#	virtual	The URL we need the file name of.
#
# Results:
#	The file name corresponding to the URL.
#	If "" is returned, then the URL is invalid.
#
# Side Effects:
#	None

proc Doc_Virtual {sock curfile virtual} {
    global Doc
    if {[regexp ^~ $virtual]} {
	# This is UNIX-specific, so we don't need file joins
	if {![info exists Doc(homedir)]} {
	    return {}	;# Not allowed
	}
	set list [split $virtual /]
	set user [lindex $list 0]
	if {[catch {glob $user} homedir]} {
	    return {}	;# No such user
	}
	return $homedir/$Doc(homedir)/[join [lrange $list 1 end] /]
    }

    # Try to hook up the pathname under the appropriate document root

    if {[regexp ^/ $virtual]} {
	Url_PrefixMatch $virtual prefix suffix
	if {[info exist Doc(root,$prefix)]} {
	    return [file join $Doc(root,$prefix) [string trimleft $suffix /]]
	} else {
	    # Not a document domain, so there cannot be a file behind this url.

	    return {}
	}
    }

    # Non-absolute URL

    return [file join [file dirname $curfile] $virtual]
}

# DocAccessHook
#
#	Access handle for Doc domains.
#	This looks for special files in the file system that
#	determine access control.  This is registered via
#	Url_AccessInstall
#
# Arguments:
#	sock	Client connection
#	url	The full URL. We realy need the prefix/suffix, which
#		is stored for us in the connection state
#
# Results:
#	"denied", in which case an authorization challenge or
#	not found error has been returned.  Otherwise "skip"
#	which means other access checkers could be run, but
# 	most likely access will be granted.

proc DocAccessHook {sock url} {
    global Doc
    upvar #0 Httpd$sock data

    # Make sure the path doesn't sneak out via ..
    # This turns the URL suffix into a list of pathname components

    if {[catch {Url_PathCheck $data(suffix)} data(pathlist)]} {
	Doc_NotFound $sock
	return denied
    }

    # Figure out the directory corresponding to the domain, taking
    # into account other document roots.

    if {[info exist Doc(root,$data(prefix))]} {
	set directory $Doc(root,$data(prefix))
    } else {
	set directory [file join $Doc(root,/) [string trimleft $data(prefix) /]]
    }

    # Look for .htaccess and .tclaccess files along the path
    # If you wanted to have a time-limited cache of these
    # cookies you could save the cost of probing the file system
    # for these files on each URL.

    set cookie [Auth_Check $sock $directory $data(pathlist)]

    # Finally, check access

    if {![Auth_Verify $sock $cookie]} {
	return denied
    } else {
	return skip
    }
}

# DocDomain --
#
# Main handler for Doc domains (i.e. file systems)
# This looks around for a file and, if found, uses Doc_Handle
# to return the contents.
#
# Arguments:
#	prefix		The URL prefix of the domain.
#	directory	The directory containing teh domain.
#	sock		The socket connection.
#	suffix		The URL after the prefix.
#
# Results:
#	None
#
# Side Effects:
#	Dispatch to the document handler that is in charge
#	of generating an HTTP response.

proc DocDomain {prefix directory sock suffix} {
    global Doc
    upvar #0 Httpd$sock data

    # The pathlist has been checked and URL decoded by
    # DocAccess, so we ignore the suffix and recompute it.

    if {![info exists data(pathlist)]} {
	set data(pathlist) [Url_PathCheck $data(suffix)]
    }
    set pathlist $data(pathlist)
    set suffix [join $pathlist /]

    # Check for personal home pages

    if {[regexp ^~ $pathlist] && [info exists Doc(homedir)]} {

	set user [lindex $pathlist 0]
	if {[catch {glob $user} homedir]} {
	    Doc_NotFound $sock
	    return	;# No such user
	}

	set directory [file join $homedir $Doc(homedir)]
	if {![file isdirectory $directory]} {
	    Doc_NotFound $sock
	    return	;# No User's Public Directory
	}

	if {![file readable $directory]} {
	    Doc_NotFound $sock
	    return	;# No access to User's Public Directory
	}

	set pathlist [lrange $pathlist 1 end]
	set suffix [join $pathlist /]
    }

    # The file join here is subject to attacks that create absolute
    # pathnames outside the URL tree.  We trim left the / and ~
    # to prevent those attacks.

    set path [file join $directory [string trimleft $suffix /~]]
    set path [DocPathNormalize $path]
    set data(path) $path	;# record this path for not found handling
    set data(directory) $directory

    # Handle existing files
    return [Doc_Handle $prefix $path $suffix $sock]
}

# Doc_Return --
#
# Return a document from a URL.  Dispatch to the mime type handler, if defined.
#
# Arguments:
#	prefix	The URL prefix of the domain.
#	path	The file system pathname of the file.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Dispatch to the correct document handler.

proc Doc_Return {prefix path suffix sock} {
    upvar #0 Httpd$sock data

    # precise match - return file or dispatch to mime type handler
    CountName $data(url) hit

    switch [file type $path] {
	directory {
	    if {[string length $data(url)] && ![regexp /$ $data(url)]} {
		# Insist on the trailing slash
		Redirect_Dir $sock
		return
	    }

	    return [DirList_Directory $prefix $path $suffix $sock]
	}
 
	link {
	    set link [file readlink $path]
	    if {[file pathtype $link] == "relative"} {
		set link [file join [file dirname $path] $link]
	    }
	    return [Doc_Return $prefix $link $suffix $sock] 
	}

	default {
	    # Look for a Tcl procedure whose
	    # name matches the MIME Content-Type
	    if {[info exists data(contentType)]} {
		set ctype $data(contentType) ;# set by a template
	    } else {
		set ctype [Mtype $path]
	    }
	    
	    set cmd Doc_$ctype
	    if {[iscommand $cmd]} {
		# call the Mime type handler
		return [$cmd $path $suffix $sock]
	    } else {
		return [Httpd_ReturnFile $sock $ctype $path]
	    }
	}
    }
}

# Doc_Handle --
#
# Handle a document URL.  Dispatch to the mime type handler, if defined.
#
# Arguments:
#	prefix	The URL prefix of the domain.
#	path	The file system pathname of the file.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Dispatch to the correct document handler.

proc Doc_Handle {prefix path suffix sock} {
    upvar #0 Httpd$sock data

    # first we check if there's a template file to run, and run it
    # if there's a precise file match, we return it
    # otherwise we generate alternatives from the client's Accept
    # otherwise we leave it Cgi to try to satisfy the request

    # Look for a fresh template which generates the desired path
    if {[Template_Try $sock $path $suffix]} {
	# template has handled the request
	return 1
    }

    # Template_Try hasn't satisfied the request,
    # Look for an exact match.
    if {[file exists $path] && [file readable $path]} {
	# we have a file precisely matching the request
	Doc_Return $prefix $path $suffix $sock
	return 1
    }

    # Negotiate an Acceptable available alternative file
    # if one is found, a redirect is provoked
    # (FIXME: is this according to the spec?)
    if {[Fallback_Try $prefix $path $suffix $sock]} {
	# we have found an Accept-able alternative
	# Fallback_Try generates a redirect
	return 1
    }

    # Couldn't find any matches
    # check for cgi script in the middle of the path
    # will generate Doc_Notfound if necessary
    Cgi_Domain $prefix $data(directory) $sock $suffix

    return 1
}

# Doc_GetPath --
#	
#	Return a list of unique directories from domain root to a given path
#	Adjusts for Document roots and user directories
#
# Arguments:
#	sock		The client connection
#	file		The file endpoint of the path
# Results:
#	A list of directories from root to directory of $data(path)
#
# Side Effects:
#	None.

proc Doc_GetPath {sock {file ""}} {
    global Doc
    upvar #0 Httpd$sock data

    if {$file == ""} {
	set file $data(path)
    }

    # Start at the Doc_AddRoot point
    if {[info exist Doc(root,$data(prefix))]} {
	set root [file normalize $Doc(root,$data(prefix))]

	# always start in the rootdir
	set dirs $Doc(root)
    } else {
	set root $Doc(root,/)
	set dirs {}
    }

    set dirsplit [file split [file dirname $file]]
    if {[string match ${root}* $file]} {

	# Normal case of pathname under domain prefix

	set path $root
	set extra [lrange $dirsplit [llength [file split $root]] end]

    } elseif {[set hindex [lsearch -exact $dirsplit $Doc(homedir)]] >= 0} {
	
	# "public_html" is in the path, so we have been warped
	# to a user's URL tree.

	set path [eval file join [lrange $dirsplit 0 $hindex]]
	incr hindex
	set extra [lrange $dirsplit $hindex end]
    } else {
	# Don't know where we are - just use the current directory

	set path [file dirname $file] 
	set extra {}
    }

    foreach dir [concat [list {}] $extra] {
	set path [file join $path $dir]
	# Don't add duplicates to the list.
	if {[lsearch $dirs $path] == -1} {
	    lappend dirs $path
	}
    }

    return $dirs
}

# Helper routine for cleaning up file names
# Part of the context here is that "file exists" on Windows
# ignores trailing . in a pathname, leading to cute attacks

if {[catch {file normalize /a/b/../c/foo.tml.}]} {
  # No file normalize command
  if {$tcl_platform(platform) == "windows"} {
    proc DocPathNormalize {path} {
      return [string trimright $path .]
    }
  } else {
    proc DocPathNormalize {path} {
      return $path
    }
  }
} else {
  proc DocPathNormalize {path} {
    return [file normalize $path]
  }
}

Added modules/httpd/doc_error.tcl.

















































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# doc_error.tcl
#@c handlers for server errors and doc-not-found cases.
#
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: doc_error.tcl,v 1.7 2004/09/05 05:10:13 coldstore Exp $

package provide httpd::doc_error 1.0

package require httpd	;# Httpd_Error
package require httpd::counter	;# Count CountName
package require httpd::doc	;# Doc_Virtual
package require httpd::log	;# Log
package require httpd::subst	;# Subst_ReturnFile
package require httpd::utils	;# file lappendOnce protect_text

# Doc_NotFoundPage --
#
#@c Register a file not found error page.
#@c This page always gets "subst'ed, but without the fancy
#@c context of the ".tml" pages.
#@c
# Arguments:
#@a	virtual	The URL of the not-found page, e.g., /notfound.html
#
# Results:
#@r	None
#
# Side Effects:
#@e	Sets the not-found page.

proc Doc_NotFoundPage { virtual } {
    global Doc
    set Doc(page,notfound) [Doc_Virtual {} {} $virtual]
}

# Doc_ErrorPage --
#
#@c Register a server error page.
#@c This page always gets "subst'ed"
#
# Arguments:
#@a	virtual	The URL of the error page, e.g., /error.html
#
# Results:
#@r	None
#
# Side Effects:
#@e	Sets the error page.

proc Doc_ErrorPage { virtual } {
    global Doc
    set Doc(page,error) [Doc_Virtual {} {} $virtual]
}

# Doc_NotFound --
#
#@c	Called when a page is missing.  This looks for a handler page
#@c	and sets up a small amount of context for it.
#
# Arguments:
#@a	sock	The socket connection.
#
# Results:
#@r	None
#
# Side Effects:
#@e	Returns a page.

proc Doc_NotFound { sock } {
    global Doc Referer
    upvar #0 Httpd$sock data
    CountName $data(url) notfound
    set Doc(url,notfound) $data(url)	;# For subst
    if {[info exists data(mime,referer)]} {

	# Record the referring URL so we can track down
	# bad links

	lappendOnce Referer($data(url)) $data(mime,referer)
    }
    DocSubstSystemFile $sock notfound 404 [protect_text $Doc(url,notfound)]
}

# Doc_Error --
#
#@c	Called when an error has occurred processing the page.
#
# Arguments:
#@a	sock	The socket connection.
#	ei	errorInfo
#
# Results:
#@r	None
#
# Side Effects:
#@e	Returns a page.

proc Doc_Error { sock ei } {
    global Doc
    upvar #0 Httpd$sock data
    # Could have been reset!!!
    catch {
	set Doc(errorUrl) $data(url)
	set Doc(errorInfo) $ei	;# For subst
	CountName $Doc(errorUrl) errors
    }
    if {![info exists data(error_hook)] || [catch {$data(error_hook) $sock}]} {
	DocSubstSystemFile $sock error 500 [protect_text $ei]
    }
}

# DocSubstSystemFile --
#
#	Simple template processor for notfound and error pages.
#
# Arguments:
#	sock	The socket connection
#	key	Either "notfound" or "error"
#	code	HTTP code
#	extra 	Optional string to include in return page.
#	interp  Interp to use for Subst.
#
# Results:
#	None
#
# Side Effects:
#	Returns a page.

proc DocSubstSystemFile {sock key code {extra {}} {interp {}}} {
    global Doc env
    if {![info exists Doc(page,$key)]} {
	set path [Doc_Virtual {} {} /$key.html]
	if {[file exists $path]} {
	    set Doc(page,$key) $path
	}
    }
    if {![info exists Doc(page,$key)] || 
	[catch {Subst_ReturnFile $sock $Doc(page,$key) $interp} err]} {
	if {[info exists err]} {
	    Log $sock DocSubstSystemFile $err
	}
	Httpd_Error $sock $code $extra
    }
}

# Doc_ErrorInfo --
#
#@c Return the error information raised by this page
#
# Arguments:
#
# Results:
#@r	$Doc(errorInfo)
#
# Side Effects:
#@e	None

proc Doc_ErrorInfo {} {
    global Doc
    return $Doc(errorInfo)
}

# Doc_UrlNotFound --
#
#@c Return the url which was not found (in notfound handler)
#
# Arguments:
#
# Results:
#@r	$Doc(url,notfound)
#
# Side Effects:
#@e	None

proc Doc_UrlNotFound {} {
    global Doc
    return $Doc(url,notfound)
}

Added modules/httpd/doctools.tcl.



















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# doctools.tcl
#
# tclllib doctools support

package provide httpd::doctools 1.0

if {[catch {package require doctools}]} {
    # tcllib's doctools package must be available
    return
}

package require httpd	;# Httpd_PostDataSize Httpd_ReturnData Httpd_ReturnFile
package require httpd::mtype	;# Mtype Mtype_Add
package require httpd::url	;# Url_ReadPost
#package require httpd::utils	;# file

# register the man suffix as a doctool application
set Doctools(suffix) .man
Mtype_Add $Doctools(suffix) application/x-doctool

# Doc_application/x-doctool --
#
# use doctools to format up and return an html document
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Sets up the interpreter context and runs doctools over the page
#	if necessary, to generate a cached version which is returned to the client.

proc Doc_application/x-doctool {path suffix sock} {

    # allow selection of doctool output types
    DoctoolsQuery $sock
    set format [ncgi::value format]
    if {$format == ""} {
	set format html
    }

    # check if a cached version exists and is newer
    if {[file exists ${path}.$format]} {
	set mtime [file mtime ${path}.$format]
	if {$mtime > [file mtime $path]} {
	    return [Httpd_ReturnFile $sock text/$format ${path}.$format]
	}
    }

    # generate the requested format
    set fd [open $path]
    ::doctools::new doctool -format $format
    if {[catch {doctool format [read $fd]} result]} {
    }
    doctool destroy
    close $fd

    # write the cached version
    if {![catch {set fd [open ${path}.$format w]}]} {
	puts $fd $result
	close $fd
	# return the file
	return [Httpd_ReturnFile $sock text/$format ${path}.$format]
    } else {
	# can't cache - return as data
	Httpd_ReturnData $sock text/$format $result
    }
}

# this should be a global facility somewhere
proc DoctoolsQuery {sock} {
    upvar #0 Httpd$sock data

    if {[Httpd_PostDataSize $sock] > 0 && ![info exists data(query)]} {
	set data(query) {}
    }
    if {[info exist data(query)]} {
	if {![info exist data(mime,content-type)] || $data(proto) == "GET"} {
	    
	    # The check against GET is because IE 5 has the following bug.
	    # If it does a POST with content-type multipart/form-data and
	    # keep-alive reuses the connection for a subsequent GET request,
	    # then the GET request erroneously has a content-type header
	    # that is a copy of the one from the previous POST!

	    set type application/x-www-urlencoded
	} else {
	    set type $data(mime,content-type)
	}

	# Read and append the pending post data to data(query).

	Url_ReadPost $sock data(query)

	# Initialize the Standard Tcl Library ncgi package so its
	# ncgi::value can be used to get the data.
	ncgi::reset $data(query) $type
	ncgi::parse
	ncgi::urlStub $data(url)
    }
}

Added modules/httpd/fallback.tcl.























































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# fallback.tcl
#@c Fallback does "content negotation" if a file isn't found
#@c look around for files with different suffixes but the same root.
#
# NOTE: This feature is probably more trouble than it is worth.
# It was originally used to be able to choose between different
# iamge types (e.g., .gif and .jpg), but is now also used to
# find templates (.tml files) that correspond to .html files.
#
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: fallback.tcl,v 1.8 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::fallback 1.0

package require httpd::mtype	;# Mtype Mtype_Accept
package require httpd::redirect	;# Redirect_QuerySelf
package require httpd::template	;# Template_Choose
#package require httpd::utils	;# file

# Fallback_ExcludePat --
#
# Define a pattern of files names to exclude in Fallback
#
# Arguments:
#	patlist	A glob pattern of files to avoid when playing
#		games in FallBack to find an alternative file.
#
# Results:
#	None
#
# Side Effects:
#	Sets the exclude pattern.

proc Fallback_ExcludePat {patlist} {
    global Fallback
    set Fallback(excludePat) $patlist
}
if {![info exists Fallback(excludePat)]} {
    set Fallback(excludePat) {*.bak *.swp *~}
}

# Fallback_Try
#
# Try to find an file which matches the HTTP Accept alternatives
# given by the client.
#
# Arguments:
#	prefix	The URL prefix of the domain.
#	path	The pathname we were trying to find.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	This either triggers an HTTP redirect to switch the user
#	to the correct file name, or it calls out to the template-aware
#	text/html processor.

proc Fallback_Try {virtual path suffix sock} {
    set root [file root $path]
    if {[string match */ $root]} {
	# Input is something like /a/b/.xyz
	return 0
    }

    # Look for files indicated by any Accept headers.
    # Most browsers say */*, but they may provide some ordering info, too.

    # First generate a list of candidate files by ignoring extension
    global Template	;# we need the template extension here
    set ok {}
    foreach choice [glob -nocomplain $root.*] {
	# don't let "foo.html.old" match for "foo.html"
	# but let foo.*.tml match for foo.*
	if {[string equal $root [file root $choice]]
	    || [string equal [file extension $choice] $Template(tmlExt)]} {

	    # Filter on the exclude patterns
	    if {![FallbackExclude $choice]} {
		lappend ok $choice
	    }
	}
    }

    # Now we pick the best file from the files and templates that matched
    # Template_Choose will return us the best possible match
    # the best match might not yet exist, but may be able to be generated 
    # from a template, which will be handled after the redirection we provoke
    set npath [Template_Choose [Mtype_Accept $sock] $ok]
    if {[string length $npath] == 0} {
	# there was no viable alternative
	return 0
    } elseif {[string compare $path $npath] == 0} {
	# the best alternative was the original path requested
	# FIXME: this is bogus - we shouldn't even be called if there's a match
	return 0
    } else {
	# A file matched with a different extension to that requested
	# (if the match was a template, we offer the untemplated name.)

	# Redirect_to/offer our best match.
	# Redirect so we don't mask spelling errors like john.osterhoot

	set new [file extension $npath]	;# candidate extension
	set old [file extension $suffix]	;# requested extension
	if {[string length $old] == 0} {
	    append suffix $new	;# client request was without extension
	} else {
	    # client requested foo.$old, we're offering foo.$new
	    # Watch out for specials in $old, like .html)
	    # FIXME: the following seems bogus and heavyweight
	    # if there's an element in the path which happens to match the ext,
	    # we will subst it too, which can't be a good thing.
	    # we should really decompose the path and reconstruct it.
	    regsub -all {[][$^|().*+?\\]} $old {\\&} old ;# quote special chars
	    regsub $old\$ $suffix $new suffix	;# substitute $new for $old
	}

	# Offer alternative to the client by redirection, preserving query data
	Redirect_QuerySelf $sock "$virtual[string trimleft $suffix /~]"
	return 1	;# we have completely handled the request.
    }
}

# FallbackExclude --
#
# This is used to filter out files like "foo.bak"  and foo~
# from the Fallback failover code
#
# Arguments:
#	name	The filename to filter.
#
# Results:
#	1	If the file should be excluded, 0 otherwise.
#
# Side Effects:
#	None

proc FallbackExclude {name} {
    global Fallback
    foreach pat $Fallback(excludePat) {
	if {[string match $pat $name]} {
	    return 1
	}
    }
    return 0
}

Added modules/httpd/fastcgi.tcl.















>
>
>
>
>
>
>
1
2
3
4
5
6
7
###
# This package adds fastCGI support for tclhttpd
# While it's cool that tclhttpd *can* do a lot of things dynamically
# it often needs to access external components
###

package provide httpd::fastcgi 0.1

Added modules/httpd/fossil.tcl.













>
>
>
>
>
>
1
2
3
4
5
6
###
# This package adds fastCGI support for fossil repositories
###

package provide httpd::fossil 0.1

Added modules/httpd/httpd.tcl.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
# httpd.tcl --
#
# HTTP 1.0 protocol stack, plus connection keep-alive and 1.1 subset.
# This accepts connections and calls out to Url_Dispatch once a request
# has been recieved.  There are several utilities for returning
# different errors, redirects, challenges, files, and data.
#
# For binary data transfer this uses unsupported0 or fcopy.
# Tcl8.0a2 was the last release with unsupported0.
# Note that Tcl8.0b1 has a bug in fcopy where if an error occurs then
# bgerror is called instead of the command callback to fcopy.  This
# causes file descriptor leaks, so don't use 8.0b1 for real servers.
#
# For async operation, such as long-lasting server-side operations use
# Httpd_Suspend.
#
# Copyright
# Matt Newman (c) 1999 Novadigm Inc.
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# Brent Welch (c) 2001-2004 Panasas Inc
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: httpd.tcl,v 1.90 2005/02/26 02:33:31 coldstore Exp $

package provide httpd 1.7

package require httpd::config	;# Config config::cget config::init
package require httpd::counter	;# Count CountHist CountStart CountStop
package require httpd::log	;# Log Log_Flush Log_FlushMinutes Log_SetFile
package require httpd::logstd	;# LogValue
package require httpd::redirect	;# Redirect_Dir
package require httpd::threadmgr	;# Thread_Enabled Thread_Init Thread_Respond
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_Dispatch Url_PostHook
package require httpd::utils	;# K Stderr file protect_text
package require httpd::version	;# Httpd_Version

# initialize all the global data

# Location of this package
set Httpd(library) [file dirname [info script]]

# HTTP/1.0 error codes (the ones we use)
array set Httpd_Errors {
    200 {Data follows}
    204 {No Content}
    302 {Found}
    304 {Not Modified}
    400 {Bad Request}
    401 {Authorization Required}
    403 {Permission denied}
    404 {Not Found}
    408 {Request Timeout}
    411 {Length Required}
    419 {Expectation Failed}
    500 {Server Internal Error}
    501 {Server Busy}
    503 {Service Unavailable}
    504 {Service Temporarily Unavailable}
}
# Environment variables that are extracted from the mime header
# by Cgi_SetEnv.  The values are keys into the
# per-connection state array (i.e. "data")

array set Httpd_EnvMap {
    CONTENT_LENGTH	mime,content-length
    CONTENT_TYPE	mime,content-type
    HTTP_ACCEPT		mime,accept
    HTTP_AUTHORIZATION	mime,authorization
    HTTP_FROM		mime,from
    HTTP_REFERER	mime,referer
    HTTP_USER_AGENT	mime,user-agent
    QUERY_STRING	query
    REQUEST_METHOD	proto
    HTTP_COOKIE         mime,cookie
    HTTP_FORWARDED      mime,forwarded
    HTTP_HOST           mime,host
    HTTP_PROXY_CONNECTION mime,proxy-connection
    REMOTE_USER		remote_user
    AUTH_TYPE		auth_type
}

# The per-connection state is kept in the "data" array, which is
# really an array named Httpd$sock - (note the upvar #0 trick throughout)
# The elements of this array are documented here.  URL implementations
# are free to hang additional state off the data array so long as they
# do not clobber the elements documented here:

# These fields are semi-public, or "well known".  There are a few
# API's to access them, but URL implementations can rely on these:
#
# self		A list of protocol (http or https), name, and port that
#		capture the server-side of the socket address
#		Available with  Httpd_Protocol, Httpd_Name, and Httpd_Port API.
# uri		The complete URL, including proto, servername, and query
# proto		http or https
# url		The URL after the server name and before the ?
# query		The URL after the ?
# ipaddr	The remote client's IP address
# cert		Client certificate (The result of tls::status)
# host		The host specified in the URL, if any (proxy case)
# port		The port specified in the URL, if any
# mime,*	HTTP header request lines (e.g., mime,content-type)
# count		Content-Length
# set-cookie	List of Set-Cookie headers to stick into the response
#		Use Httpd_SetCookie to append to this.
# headers		List of http headers to stick into the response
#		Use Httpd_AddHeaders to append to this.

# prefix	(Set by Url_Dispatch to be the URL domain prefix)
# suffix	(Set by Url_Dispatch to be the URL domain suffix)

# auth_type	(Set by the auth.tcl module to "Basic", etc.)
# remote_user	(Set by the auth.tcl to username from Basic authentication)
# session	(Set by the auth.tcl to "realm,$username" from Basic auth)
#		You can overwrite this session ID with something more useful

# Internal fields used by this module.
# left		The number of keep-alive connections allowed
# cancel	AfterID of event that will terminate the connection on timeout
# state		State of request processing
# version	1.0 or 1.1
# line		The current line of the HTTP request
# mimeorder	List indicating order of MIME header lines
# key		Current header key
# checkNewLine	State bit for Netscape SSL newline bug hack
# callback	Command to invoke when request has completed
# file_size	Size of file returned by ReturnFile
# infile	Open file used by fcopy to return a file, or CGI pipe
# filter	List of http post-generation filter procs to apply to content
# path	normalized path to Doc file (set by doc.tcl)

# Httpd_Init
#	Initialize the httpd module.  Call this early, before Httpd_Server.
#
# Arguments:
#	none
#
# Side Effects:
#	Initialize the global Httpd array.
# bufsize:	Chunk size for copies
# initialized:	True after server started.
# ipaddr:	Non-default ipaddr for the server (for multiple interfaces)
# library:	a directory containing the tcl scripts.
# port:		The port this server is serving
# listen:	the main listening socket id
# server:	The server ID for the HTTP protocol.
# shutdown:	A list of Tcl callbacks made when the server shuts down
# sockblock:	blocking mode value for sockets (normally this should be 0)
# timeout1:	Time before the server closes a kept-alive socket (msecs)
# timeout2:	Time before the server kills an in-progress transaction.  (msecs)
# timeout3:	Time allowed to drain extra post data
# version:	The version number.
# maxused:	Max number of transactions per socket (keep alive)

proc Httpd_Init {} {
    global Httpd
    array set Httpd {
	timeout1	120000
	timeout2	120000
	timeout3	2000
	server		"Tcl-Webserver/"
	initialized 	1
	shutdown	""
	sockblock	0
	bufsize		16384
	maxused		25
    }
    if {![info exist Httpd(maxthreads)]} {
	set Httpd(maxthreads) 0
    }
    Httpd_Version
    append Httpd(server) $Httpd(version)
}

# Httpd_Server --
#	Start the server by listening for connections on the desired port.
#	This may be re-run to re-start the server.  Call this late,
# 	fter Httpd_Init and the init calls for the other modules.
#
# Arguments:
#	port	The TCP listening port number
#	name	The qualified host name returned in the Host field.  Defaults
#		to [info hostname]
#	ipaddr	Non-default interface address.  Otherwise IP_ADDR_ANY is used
#		so the server can accept connections from any interface.
#
# Results:
#	none
#
# Side Effects:
#	This sets up a callback to HttpdAccept for new connections.

proc Httpd_Server {{port 80} {name {}} {ipaddr {}}} {
    global Httpd

    if {![info exists Httpd(initialized)]} {
	Httpd_Init
    }
    catch {close $Httpd(listen)}
    set Httpd(name) $name
    set Httpd(ipaddr) $ipaddr
    set Httpd(port) $port
    if {[string length $name] == 0} {
	set Httpd(name) [info hostname]
    }
    set cmd [list socket -server [list HttpdAccept \
	    [list http $name $port]]]
    if {[string length $ipaddr] != 0} {
        lappend cmd -myaddr $ipaddr
    }
    lappend cmd $port
    if {[catch $cmd Httpd(listen)]} {
        return -code error "$Httpd(name):$port $Httpd(listen)\ncmd=$cmd"
    }
}

# Httpd_ServerShutdown --
#
#	Close the server's HTTP socket.
#
# Arguments:
#	none
#
# Results:
#	Returns "" if the socket was successfully closed, otherwise an error string.
#
# Side Effects:
#	Close the server's HTTP listening socket.

proc Httpd_ServerShutdown {} {
    global Httpd
    Log {} ShutdownSocket
    catch {close $Httpd(listen)} err
    return $err
}

proc Httpd_VirtualHost {host file} {
    return [Httpd_VirtualHosts [list $host] $file]
}

proc Httpd_VirtualHosts {hostNames file} {
    variable virtual

    foreach host $hostNames {
        set host [string tolower $host]
        if {[info exists virtual($host)]} {
	    error "Virtual host $host already exists"
        }
    }
    set slave [interp create]

    # Transfer the scalar global variables
    foreach var {::v ::auto_path} {
	$slave eval [list set $var [set $var]]
    }
    # Transfer the array global variables
    foreach arr {::Config ::Httpd} {
	$slave eval [list array set $arr [array get $arr]]
    }
    $slave eval [list array set ::Httpd [list name $host]]
    # Load the packages
    $slave eval package require httpd [package provide httpd]
    foreach pkg {version utils counter config} {
	$slave eval \
		package require httpd::$pkg [package provide httpd::$pkg]
    }
    $slave eval [list array set Config [list config $file host $host]]
    $slave eval {
	config::init $Config(config) Config
	namespace import config::cget

	# This replaces the command line processing
	array set Config [array get config::Config]

	if {[string length $Config(library)] &&
		[lsearch -exact $auto_path $Config(library)] == -1} {
	    lappend auto_path $Config(library)
	}
	Httpd_Init

	if {$Config(threads) > 0} {
	    package require Thread		;# C extension
	    package require httpd::threadmgr	;# Tcl layer on top
	    Thread_Init $Config(threads)
	} else {
	    # Stub out Thread_Respond so threadmgr isn't required
	    proc Thread_Respond {args} {return 0}
	    proc Thread_Enabled {} {return 0}
	}
	source $Config(main)
	Log_SetFile		[cget LogFile]$Config(port)_
	Log_FlushMinutes	[cget LogFlushMinutes]
	Log_Flush
    }

    foreach host $hostNames {
        set host [string tolower $host]
	set virtual($host) $slave
    }

}

# Httpd_SecureServer --
#
#	Like Httpd_Server, but with additional setup for SSL.
#	This requires the TLS extension.
#
# Arguments:
#	port	The TCP listening port number
#	name	The qualified host name returned in the Host field.  Defaults
#		to [info hostname]
#	ipaddr	Non-default interface address.  Otherwise IP_ADDR_ANY is used
#		so the server can accept connections from any interface.
#
# Results:
#	none
#
# Side Effects:
#	This sets up a callback to HttpdAccept for new connections.

proc Httpd_SecureServer {{port 443} {name {}} {ipaddr {}}} {
    global Httpd

    if {![info exists Httpd(initialized)]} {
	Httpd_Init
    }
    catch {close $Httpd(https_listen)}
    set Httpd(name) $name
    set Httpd(https_ipaddr) $ipaddr
    set Httpd(https_port) $port
    if {[string length $name] == 0} {
	set Httpd(name) [info hostname]
    }
    package require tls

    # This now depends on a call to tls::init being made elsewhere, typically
    # in the main startup script.  That call sets all the various SSL parameters
    # based on the server's configuration file.

    set cmd [list tls::socket -server [list HttpdAccept \
	    [list https $name $port]]]
    if {[string length $ipaddr] != 0} {
        lappend cmd -myaddr $ipaddr
    }
    lappend cmd $port
    if {[catch $cmd Httpd(https_listen)]} {
        return -code error "$Httpd(name):$port $Httpd(https_listen)\ncmd=$cmd"
    }
}

# Httpd_SecureServerShutdown --
#
#	Close the server's secure socket.
#
# Arguments:
#	none
#
# Results:
#	Returns "" if the socket was successfully closed, otherwise an error string.
#
# Side Effects:
#	Close the server's HTTPS listening socket.

proc Httpd_SecureServerShutdown {} {
    global Httpd
    Log {} ShutdownSecureSocket
    catch {close $Httpd(https_listen)} err
    return $err
}

# Httpd_Shutdown --
#
#	Kill the server gracefully
#
# Arguments:
#	none
#
# Results:
#	none
#
# Side Effects:
#	Close the server listening socket(s)
#	Invoke any registered shutdown procedures.

proc Httpd_Shutdown {} {
    global Httpd
    variable virtual
    set ok 1
    foreach host [array names virtual] {
	$virtual($host) eval Httpd_Shutdown
    }
    foreach handler $Httpd(shutdown) {
	if {[catch {eval $handler} err]} {
	    Log "" "Shutdown: $handler" $err
	    set ok 0
	}
    }
    Log {} Shutdown
    Httpd_ServerShutdown
    Httpd_SecureServerShutdown
    return $ok
}

# Httpd_RegisterShutdown --
#
#	Register a Tcl command to be called by Httpd_Shutdown
#
# Arguments:
#	cmd	The command to eval from Httpd_Shutdown
#
# Results:
#	none
#
# Side Effects:
#	Save the callback.

proc Httpd_RegisterShutdown {cmd} {
    global Httpd
    if {[lsearch $Httpd(shutdown) $cmd] < 0} {
	lappend Httpd(shutdown) $cmd
    }
}

# HttpdAccept --
#
#	This is the socket accept callback invoked by Tcl when
#	clients connect to the server.
#
# Arguments:
#	self	A list of {protocol name port} that identifies the server
#	sock	The new socket connection
#	ipaddr	The client's IP address
#	port	The client's port
#
# Results:
#	none
#
# Side Effects:
#	Set up a handler, HttpdRead, to read the request from the client.
#	The per-connection state is kept in Httpd$sock, (e.g., Httpdsock6),
#	and upvar is used to create a local "data" alias for this global array.

proc HttpdAccept {self sock ipaddr port} {
    global Httpd
    upvar #0 Httpd$sock data

    Count accepts
    Count sockets
    set data(self) $self
    set data(ipaddr) $ipaddr
    if {[Httpd_Protocol $sock] == "https"} {
	
	# There is still a lengthy handshake that must occur.
	# We do that by calling tls::handshake in a fileevent
	# until it is complete, or an error occurs.

	Count accept_https
	fconfigure $sock -blocking 0
	fileevent $sock readable [list HttpdHandshake $sock]
    } else {
	HttpdReset $sock $Httpd(maxused)
    }
}

# HttpdHandshake --
#
#	Complete the SSL handshake. This is called from a fileevent
#	on a new https connection.  It calls tls::handshake until done.
#
# Arguments:
#	sock	The socket connection
#
# Results:
#	none
#
# Side Effects:
#	If the handshake fails, close the connection.
#	Otherwise, call HttpdReset to set up the normal HTTP protocol.

proc HttpdHandshake {sock} {
    upvar #0 Httpd$sock data
    global Httpd errorCode
	
    if {[catch {tls::handshake $sock} complete]} {
	if {[lindex $errorCode 1] == "EAGAIN"} {
	    # This seems to occur normally on UNIX systems
	    return
	}
	Log $sock "HttpdHandshake" "\{$data(self)\} $sock \
	    $data(ipaddr) $complete"
	Httpd_SockClose $sock 1 "$complete"
    } elseif {$complete} {
	set data(cert) [tls::status $sock]
	HttpdReset $sock $Httpd(maxused)
    }
}

# HttpdReset --
#
#	Initialize or reset the socket state.
#	We allow multiple transactions per socket (keep alive).
#
# Arguments:
#	sock	The socket connection
#	left	(optional) The keepalive connection count.
#
# Results:
#	none
#
# Side Effects:
#	Resets the "data" array.
#	Cancels any after events.
#	Closes the socket upon error or if the reuse counter goes to 0.
#	Sets up the fileevent for HttpdRead

proc HttpdReset {sock {left {}}} {
    global Httpd
    upvar #0 Httpd$sock data

    if {[catch {
	flush $sock
    } err]} {
	Httpd_SockClose $sock 1 $err
	return
    }
    Count connections

    # Count down transactions.

    if {[string length $left]} {
	set data(left) $left
    } else {
	set left [incr data(left) -1]
    }
    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
    }

    # Clear out (most of) the data array.

    set ipaddr $data(ipaddr)
    set self $data(self)
    if {[info exist data(cert)]} {
	set cert $data(cert)
    }
    unset data
    array set data [list state start version 0 \
	    left $left ipaddr $ipaddr self $self]
    if {[info exist cert]} {
	set data(cert) $cert
    }

    # Set up a timer to close the socket if the next request
    # is not completed soon enough.  The request has already
    # been started, but a bad URL domain might not finish.

    set data(cancel) [after $Httpd(timeout1) \
	[list Httpd_SockClose $sock 1 "timeout"]]
    fconfigure $sock -blocking 0 -buffersize $Httpd(bufsize) \
	-translation {auto crlf}
    fileevent $sock readable [list HttpdRead $sock]
    fileevent $sock writable {}
}

# Httpd_Peername --
#
# Really need to fix the core to support DNS lookups.
# This routine is not used anywhere.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	The clients dns name.
#
# Side Effects:
#	None

proc Httpd_Peername {sock} {
    # This is expensive!
    fconfigure $sock -peername
}

# HttpdRead --
#
# Read request from a client.  This is the main state machine
# for the protocol.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Reads the request from the socket and dispatches the
#	URL request when ready.

proc HttpdRead {sock} {
    global Httpd
    upvar #0 Httpd$sock data

    # Use line mode to read the request and the mime headers

    if {[catch {gets $sock line} readCount]} {
	Httpd_SockClose $sock 1 "read error: $readCount"
	return
    }

    # State machine is a function of our state variable:
    #	start: the connection is new
    #	mime: we are reading the protocol headers
    # and how much was read. Note that
    # [string compare $readCount 0] maps -1 to -1, 0 to 0, and > 0 to 1
    set state [string compare $readCount 0],$data(state)

    switch -glob -- $state {
	1,start	{
	    if {[regexp {^([^ ]+) +([^?]+)\??([^ ]*) +HTTP/(1.[01])} \
		    $line x data(proto) data(url) data(query) data(version)]} {
		
		# data(uri) is the complete URI

		set data(uri) $data(url)
		if {[string length $data(query)]} {
		    append data(uri) ?$data(query)
		}

		# Strip leading http://server and look for the proxy case.

		if {[regexp {^https?://([^/:]+)(:([0-9]+))?(.*)$} $data(url) \
			x xserv y xport urlstub]} {
		    set myname [Httpd_Name $sock]
		    set myport [Httpd_Port $sock]
		    if {([string compare \
			    [string tolower $xserv] \
			    [string tolower $myname]] != 0) ||
			    ($myport != $xport)} {
			set data(host) $xserv
			set data(port) $xport
		    }
		    # Strip it out if it is for us (i.e., redundant)
		    # This makes it easier for doc handlers to
		    # look at the "url"
		    set data(url) $urlstub
		}
		set data(state) mime
		set data(line) $line
		CountHist urlhits

		# Limit the time allowed to serve this request

		if {[info exists data(cancel)]} {
		    after cancel $data(cancel)
		}
		set data(cancel) [after $Httpd(timeout2) \
		    [list HttpdCancel $sock]]
	    } else {
		# Could check for FTP requests, here...
		Log $sock HttpError $line
		Httpd_SockClose $sock 1
	    }
	}
	0,start {
	    # This can happen in between requests.
	}
	1,mime	{
	    # This regexp picks up
	    # key: value
	    # MIME headers.  MIME headers may be continue with a line
	    # that starts with spaces.
	    if {[regexp {^([^ :]+):[ 	]*(.*)} $line dummy key value]} {

                # The following allows something to
                # recreate the headers exactly

                lappend data(headerlist) $key $value

                # The rest of this makes it easier to pick out
                # headers from the data(mime,headername) array

		set key [string tolower $key]
		if {[info exists data(mime,$key)]} {
		    append data(mime,$key) ,$value
		} else {
		    set data(mime,$key) $value
		    lappend data(mimeorder) $key
		}
		set data(key) $key

	    } elseif {[regexp {^[ 	]+(.*)}  $line dummy value]} {
		# Are there really continuation lines in the spec?
		if {[info exists data(key)]} {
		    append data(mime,$data(key)) " " $value
		} else {
		    Httpd_Error $sock 400 $line
		}
	    } else {
		Httpd_Error $sock 400 $line
	    }
	    # Check for virtual host
	    variable virtual
	    if {[string compare host $key]} {return}
	    set host [lindex [split [string tolower $value] :] 0]
	    if {[catch {set virtual($host)} i]} {return}

	    # Transfer $sock to interp $i
	    fileevent $sock readable {}
	    interp transfer {} $sock $i
	    set data(self) [list [Httpd_Protocol $sock] \
		    $host [Httpd_Port $sock]]
	    if {[info exists data(cancel)]} {
		after cancel $data(cancel)
		unset data(cancel)
	    }
	    $i eval [list array set Httpd$sock [array get data]]
	    unset data
	    $i eval [list fileevent $sock readable [list HttpdRead $sock]]
	    set tmp [$i eval [list \
		    after $Httpd(timeout2) [list HttpdCancel $sock]]]
	    $i eval [list array set Httpd$sock [list cancel $tmp]]
	}
	0,mime	{
	    if {$data(proto) == "POST"} {
		fconfigure $sock  -translation {binary crlf}
		if {![info exists data(mime,content-length)]} {
		    Httpd_Error $sock 411
		    return
		}
		set data(count) $data(mime,content-length)
		if {$data(version) >= 1.1 && [info exists data(mime,expect)]} {
		    if {$data(mime,expect) == "100-continue"} {
			puts $sock "100 Continue HTTP/1.1\n"
			flush $sock
		    } else {
			Httpd_Error $sock 419 $data(mime,expect)
			return
		    }
		}

		# Flag the need to check for an extra newline
		# in SSL connections by some browsers.

		set data(checkNewline) 1

		# Facilitate a backdoor hook between Url_DecodeQuery
		# where it will read the post data on behalf of the
		# domain handler in the case where the domain handler
		# doesn't use an Httpd call to read the post data itself.

		Url_PostHook $sock $data(count)
	    } else {
		Url_PostHook $sock 0    ;# Clear any left-over hook
		set data(count) 0
	    }

	    # Disabling this fileevent makes it possible to use
	    # http::geturl in domain handlers reliably

	    fileevent $sock readable {}

	    # The use of HTTP_CHANNEL is a disgusting hack.

	    set ::env(HTTP_CHANNEL) $sock

	    # Do a different dispatch for proxies.  By default, no proxy.

	    if {[info exist data(host)]} {
		if {[catch {
		    Proxy_Dispatch $sock
		} err]} {
		    Httpd_Error $sock 400 "No proxy support\n$err"
		}
	    } else {
		# Dispatch to the URL implementation.

		# As a service for domains that loose track of their
		# context (e.g., .tml pages) we save the socket in a global.
		# If a domain implementation would block and re-enter the
		# event loop, it must use Httpd_Suspend to clear this state,
		# and use Httpd_Resume later to restore it.

		set Httpd(currentSocket) $sock
		CountStart serviceTime $sock
		Url_Dispatch $sock
	    }
	}
	-1,* {
	    if {[fblocked $sock]} {
		# Blocked before getting a whole line
		return
	    }
	    if {[eof $sock]} {
		Httpd_SockClose $sock 1 ""
		return
	    }
	}
	default {
	    Httpd_Error $sock 404 "$state ?? [expr {[eof $sock] ? "EOF" : ""}]"
	}
    }
}

# Httpd_PostDataSize --
#
# Arguments:
#	sock	Client connection
#
# Results:
#	The amount of post data available.

proc Httpd_PostDataSize {sock} {
    upvar #0 Httpd$sock data

    return $data(count)
}

# Httpd_GetPostData --
#
# Arguments:
#	sock	Client connection
#	varName	Name of buffer variable to append post data to
#	size	Amount of data to read this call. -1 to read all available.
#
# Results:
#	The amount of data left to read.  When this goes to zero, you are done.

proc Httpd_GetPostData {sock varName {size -1}} {
    global Httpd
    upvar #0 Httpd$sock data
    upvar 1 $varName buffer

    if {$size < 0} {
	set size $Httpd(bufsize)
    }
    HttpdReadPost $sock buffer $size
    return $data(count)
}

# Httpd_ReadPostDataAsync --
#
#	Convenience layer on Http-GetPostDataAsync to
#	read the POST data into a the data(query) variable.
#
# Arguments:
#	(Same as HttpdReadPost)
#
# Side Effects:
#	(See Httpd_GetPostDataAsync)

proc Httpd_ReadPostDataAsync {sock cmd} {
    global Httpd
    upvar #0 Httpd$sock data
    if {[string length $data(query)]} {
	# This merges query data from the GET/POST URL
	append data(query) &
    }
    Httpd_Suspend $sock
    fileevent $sock readable [list HttpdReadPostGlobal $sock \
	    Httpd${sock}(query) $Httpd(bufsize) $cmd]
    return
}

# Httpd_GetPostDataAsync --
#
#	Read the POST data into a Tcl variable, but do it in the
#	background so the server doesn't block on the socket.
#
# Arguments:
#	(Same as HttpdReadPost)
#
# Side Effects:
#	This schedules a readable fileevent to read all the POST data
#	asynchronously.  The data is appened to the named variable.
#	The callback is made 

proc Httpd_GetPostDataAsync {sock varName blockSize cmd} {
    Httpd_Suspend $sock
    fileevent $sock readable \
	[list HttpdReadPostGlobal $sock $varName $blockSize $cmd]
    return
}

# HttpdReadPostGlobal --
#
# This fileevent callback can only access a global variable.
# But HttpdReadPost needs to affect a local variable in its
# caller so it can be shared with Httpd_GetPostData.
# So, the fileevent case has an extra procedure frame.
#
# Arguments:
#	(Same as HttpdReadPost)
#
# Results:
#	None
#
# Side Effects:
#	Accumulates POST data into the named variable

proc HttpdReadPostGlobal {sock varName blockSize {cmd {}}} {
    upvar #0 $varName buffer
    HttpdReadPost $sock buffer $blockSize $cmd
}

# HttpdReadPost --
#
#	The core procedure that reads post data and accumulates it
#	into a Tcl variable.
#
# Arguments:
#	sock	Client connection
#	varName	Name of buffer variable to append post data to.  This
#		must be a global or fully scoped namespace variable, or
#		this can be the empty string, in which case the data
#		is discarded.
#	blockSize	Default read block size.
#	cmd	Callback to make when the post data has been read.
#		It is called like this:
#		cmd $sock $varName $errorString
#		Where the errorString is only passed if an error occurred.
#
# Results:
#	None
#
# Side Effects:
#	Consumes post data and appends it to a variable.

proc HttpdReadPost {sock varName blockSize {cmd {}}} {
    global Httpd
    upvar #0 Httpd$sock data

    # Ensure that the variable, if specified, exists by appending "" to it

    if {[string length $varName]} {
	upvar 1 $varName buffer
	append buffer ""
    }

    if {[eof $sock]} {
	if {$data(count)} {
	    set doneMsg "Short read: got [string length $buffer] bytes,\
		expected $data(count) more bytes"
	    set data(count) 0
	} else {
	    set doneMsg ""
	}
    } else {
	if {[info exist data(checkNewline)]} {

	    # Gobble a single leading \n from the POST data
	    # This is generated by various versions of Netscape
	    # when using https/SSL.  This extra \n is not counted
	    # in the content-length (thanks!)

	    set nl [read $sock 1]
	    if {[string compare $nl \n] != 0} {

		# It was not an extra newline.

		incr data(count) -1
		if {[info exist buffer]} {
		    append buffer $nl
		}
	    }
	    unset data(checkNewline)
	}
	set toRead [expr {$data(count) > $blockSize ? \
		$blockSize : $data(count)}]
	if {[catch {read $sock $toRead} block]} {
	    set doneMsg $block
	    set data(count) 0
	} else {
	    if {[info exist buffer]} {
		append buffer $block
	    }

	    set data(count) [expr {$data(count) - [string length $block]}]
	    if {$data(count) == 0} {
		set doneMsg ""
	    }
	}
    }
    if {[info exist doneMsg]} {
	Url_PostHook $sock 0
	catch {fileevent $sock readable {}}
	Httpd_Resume $sock
	if {[string length $cmd]} {
	    eval $cmd [list $sock $varName $doneMsg]
	}
	return $doneMsg
    } else {
	return ""
    }
}

# Httpd_CopyPostData --
#
#	Copy the POST data to a channel and make a callback when that
#	has completed.
#
# Arguments:
#	sock	Client connection
#	channel	Channel, e.g., to a local file or to a proxy socket.
#	cmd	Callback to make when the post data has been read.
#		It is called like this:
#		    cmd $sock $channel $bytes $errorString
#		Bytes is the number of bytes transferred by fcopy.
#		errorString is only passed if an error occurred,
#		otherwise it is an empty string
#
# Side Effects:
#	This uses fcopy to transfer the data from the socket to the channel.

proc Httpd_CopyPostData {sock channel cmd} {
    upvar #0 Httpd$sock data
    fcopy $sock $channel -size $data(count) \
    	-command [concat $cmd $sock $channel]
    Url_PostHook $sock 0
    return
}

# Httpd_GetPostChannel --
#
# Arguments:
#	sock		Client connection
#	sizeName	Name of variable to get the amount of post
#			data expected to be read from the channel
#
# Results:
#	The socket, as long as there is POST data to read

proc Httpd_GetPostChannel {sock sizeName} {
    upvar #0 Httpd$sock data
    upvar 1 $sizeName size

    if {$data(count) == 0} {
	error "no post data"
    }
    set size $data(count)
    return $sock
}

# The following are several routines that return replies

# HttpdCloseP --
#	See if we should close the socket
#
# Arguments:
#	sock	the connection handle
#
# Results:
#	1 if the connection should be closed now, 0 if keep-alive

proc HttpdCloseP {sock} {
    upvar #0 Httpd$sock data

    if {[info exists data(mime,connection)]} {
	if {[string tolower $data(mime,connection)] == "keep-alive"} {
	    Count keepalive
	    set close 0
	} else {
	    Count connclose
	    set close 1
	}
    } elseif {[info exists data(mime,proxy-connection)]} {
	if {[string tolower $data(mime,proxy-connection)] == "keep-alive"} {
	    Count keepalive
	    set close 0
	} else {
	    Count connclose
	    set close 1
	}
    } elseif {$data(version) >= 1.1} {
	Count http1.1
    	set close 0
    } else {
	# HTTP/1.0
	Count http1.0
	set close 1
    }
    if {[expr {$data(left) == 0}]} {
	# Exceeded transactions per connection
	Count noneleft
    	set close 1
    }
    return $close
}

# Httpd_CompletionCallback --
#
#	Register a procedure to be called when an HTTP request is
#	completed, either normally or forcibly closed.  This gives a
#	URL implementation a guaranteed callback to clean up or log
#	requests.
#
# Arguments:
#	sock	The connection handle
#	cmd	The callback to make.  These arguments are added:
#		sock - the connection
#		errmsg - An empty string, or an error message.
#
# Side Effects:
# 	Registers the callback

proc Httpd_CompletionCallback {sock cmd} {
    upvar #0 Httpd$sock data
    set data(callback) $cmd
}

# HttpdDoCallback --
#
#	Invoke the completion callback.
#
# Arguments:
#	sock	The connection handle
#	errmsg	The empty string, or an error message.
#
# Side Effects:
# 	Invokes the callback

proc HttpdDoCallback {sock {errmsg {}}} {
    upvar #0 Httpd$sock data
    if {[info exists data(callback)]} {
	catch {eval $data(callback) {$sock $errmsg}}

	# Ensure it is only called once
	unset data(callback)
    }
    CountStop serviceTime $sock
}

# Httpd_AddHeaders
#	Add http headers to be used in a reply
#	Call this before using Httpd_ReturnFile or
#	Httpd_ReturnData
#
# Arguments:
#	sock	handle on the connection
#	args	a list of header value ...

proc Httpd_AddHeaders {sock args} {
  upvar #0 Httpd$sock data
  lappend data(headers) {*}$args
}

# Httpd_RemoveHeaders
#	Remove previously set headers from the reply.
#	Any headers that match the glob pattern are removed.
#
# Arguments:
#	sock	handle on the connection
#	pattern	glob pattern to match agains cookies.

proc Httpd_RemoveHeaders {sock {pattern *}} {
    upvar #0 Httpd$sock data
    if {[info exists data(headers)] && $data(headers) != {}} {
        set tmp {}
        foreach {header value} $data(headers) {
            if {![string match $pattern $header]} {
                lappend tmp $header $value
            }
        }
        set data(headers) $tmp
    }
    return
}

# Httpd_NoCache
#	Insert header into http header to indicate that this page
#	should not be cached
#
# Arguments:
#	sock	handle on the connection

proc Httpd_NoCache {sock} {
    Httpd_RemoveHeaders $sock Cache-Control
    Httpd_AddHeaders $sock Cache-Control no-cache
    Httpd_AddHeaders $sock Expires content '-1'
}

# Httpd_Refresh
#	Insert header into http header to cause browser to refresh
#	after a delay, optionally to a different URL
#
# Arguments:
#	sock	handle on the connection
#	time	time in seconds before refresh
#	url	optional: url to refresh to

proc Httpd_Refresh {sock time {url ""}} {
    Httpd_RemoveHeaders $sock Cache-Control
    if {$url == ""} {
	Httpd_AddHeaders $sock Refresh $time
    } else {
	Httpd_AddHeaders $sock Refresh ${time}\;url=${url}
    }
}

# HttpdRespondHeader --
#
#	Utility routine for outputting response headers for normal data Does
#	not output the end of header markers so additional header lines can be
#	added
#
# Arguments:
#	sock	The connection handle
#	type	The mime type of this response
#	close	If true, signal connection close headers.  See HttpdCloseP
#	size	The size "in bytes" of the response
#	code	The return code - defualts to 200
#
# Side Effects:
# 	Outputs header lines

proc HttpdRespondHeader {sock type close size {code 200}} {
    global Httpd
    upvar #0 Httpd$sock data

    set data(code) $code
    append reply "HTTP/$data(version) $code [HttpdErrorString $code]" \n
    append reply "Date: [Httpd_Date [clock seconds]]" \n
    append reply "Server: $Httpd(server)\n"

    if {$close} {
	append reply "Connection: Close" \n
    } elseif {$data(version) == 1.0 && !$close} {
	append reply "Connection: Keep-Alive" \n
    }
    append reply "Content-Type: $type" \n
    if {[string length $size]} {
	append reply "Content-Length: $size" \n
    }

    if {[info exists data(headers)]} {
	foreach {header value} $data(headers) {
	    catch {
		append reply "[string trimright $header :]: " $value \n
	    }
	}
    }

    puts -nonewline $sock $reply
}

# HttpdErrorString --
#
#	Map from an error code to a meaningful string.
#
# Arguments:
#	code	An HTTP error code, e.g., 200 or 404
#
# Results:
#	An error string, e.g. "Data follows" or "File Not Found"
#
# Side Effects:
# 	None

proc HttpdErrorString { code } {
    global Httpd_Errors
    if {[info exist Httpd_Errors($code)]} {
	return $Httpd_Errors($code)
    } else {
	return "Error $code"
    }
}

# Httpd_RemoveCookies
#	Remove previously set cookies from the reply.
#	Any cookies that match the glob pattern are removed.
#	This is useful for expiring a cookie that was previously set.
#
# Arguments:
#	sock	handle on the connection
#	pattern	glob pattern to match agains cookies.

proc Httpd_RemoveCookies {sock pattern} {
    upvar #0 Httpd$sock data
    if {[info exists data(set-cookie)] && $data(set-cookie) != {}} {
        set tmp {}
        foreach c $data(set-cookie) {
            if {![string match $pattern $c]} {
                lappend tmp $c
            }
        }
        set data(set-cookie) $tmp
    }
    return
}

# Httpd_SetCookie
#	Define a cookie to be used in a reply
#	Call this before using Httpd_ReturnFile or
#	Httpd_ReturnData
#
# Arguments:
#	sock	handle on the connection
#	cookie	Set-Cookie line
#	modify	(optional) If true, overwrite any preexisting
#		cookie that matches.  This way you can change
#		the expiration time.

proc Httpd_SetCookie {sock cookie {modify 0}} {
    upvar #0 Httpd$sock data
    lappend data(set-cookie) $cookie
}

# HttpdSetCookie
#	Generate the Set-Cookie headers in a reply
#	Use Httpd_SetCookie to register cookes eariler
#
# Arguments:
#	sock	handle on the connection

proc HttpdSetCookie {sock} {
    upvar #0 Httpd$sock data
    if {[info exist data(set-cookie)]} {
	foreach item $data(set-cookie) {
	    puts $sock "Set-Cookie: $item"
	}
	# HttpdCookieLog $sock HttpdSetCookie
	unset data(set-cookie)
    }
}

# Httpd_ReturnFile
#	Return a file.
#
# Arguments:
#	sock	handle on the connection
#	type	is a Content-Type
#	path	is the file pathname
#	offset	amount to skip at the start of file
#
# Side Effects:
#	Sends the file contents back as the reply.

proc Httpd_ReturnFile {sock type path {offset 0}} {
    global Httpd
    upvar #0 Httpd$sock data

    if {[Thread_Respond $sock \
	    [list Httpd_ReturnFile $sock $type $path $offset]]} {
	return
    }

    # Set file size early so it gets into all log records

    set data(file_size) [file size $path]
    set data(code) 200

    Count urlreply
    if {[info exists data(mime,if-modified-since)]} {
        # No need for complicated date comparison, if they're identical then 304.
	if {$data(mime,if-modified-since) == [Httpd_Date [file mtime $path]]} {
            Httpd_NotModified $sock
            return
        }
    } 

    # Some files have a duality, when the client sees X bytes but the
    # file is really X + n bytes (the first n bytes reserved for server
    # side accounting information.

    incr data(file_size) -$offset

    if {[catch {
	set close [HttpdCloseP $sock]
	HttpdRespondHeader $sock $type $close $data(file_size) 200
	HttpdSetCookie $sock
	puts $sock "Last-Modified: [Httpd_Date [file mtime $path]]"
	puts $sock ""
	if {$data(proto) != "HEAD"} {
	    set in [open $path]		;# checking should already be done
	    fconfigure $in -translation binary -blocking 1
	    if {$offset != 0} {
		seek $in $offset
	    }
	    fconfigure $sock -translation binary -blocking $Httpd(sockblock)
	    set data(infile) $in
	    Httpd_Suspend $sock 0
	    fcopy $in $sock -command [list HttpdCopyDone $in $sock $close]
	} else {
	    Httpd_SockClose $sock $close
	}
    } err]} {
	HttpdCloseFinal $sock $err
    }
}

# Httpd_ReturnData
#	Return data for a page.
#
# Arguments:
#	sock	handle on the connection
#	type	a Content-Type
#	content	the data to return
#	code	the HTTP reply code.
#
# Side Effects:
#	Send the data down the socket

proc Httpd_ReturnData {sock type content {code 200} {close 0}} {
    global Httpd
    upvar #0 Httpd$sock data

    # process any filters
    if {[info exists data(filter)]} {
	while {[llength $data(filter)]} {
	    set cmd [lindex $data(filter) end]
	    set data(filter) [lrange $data(filter) 0 end-1]
	    set content [eval $cmd $sock [list $content]]
	}
    }

    if {[Thread_Respond $sock \
	    [list Httpd_ReturnData $sock $type $content $code $close]]} {
	return
    }

    Count urlreply
    if {$close == 0} {
    	set close [HttpdCloseP $sock]
    }
    if {[catch {
	HttpdRespondHeader $sock $type $close [string length $content] $code
	HttpdSetCookie $sock
	puts $sock ""
	if {$data(proto) != "HEAD"} {
	    fconfigure $sock -translation binary -blocking $Httpd(sockblock)
	    puts -nonewline $sock $content
	}
	Httpd_SockClose $sock $close
    } err]} {
	HttpdCloseFinal $sock $err
    }
}

# Httpd_ReturnCacheableData
#	Return data with a Last-Modified time so
#	that proxy servers can cache it.  Or they seem to, anyway.
#
# Arguments:
#	sock	Client connection
#	type	a Content-Type
#	content	the data to return
#	date	Modify date of the date
#	code	the HTTP reply code.
#
# Side Effects:
#	Send the data down the socket

proc Httpd_ReturnCacheableData {sock type content date {code 200}} {
    global Httpd 
    upvar #0 Httpd$sock data

    # process any filters
    if {[info exists data(filter)]} {
	while {[llength $data(filter)]} {
	    set cmd [lindex $data(filter) end]
	    set data(filter) [lrange $data(filter) 0 end-1]
	    set content [eval $cmd $sock [list $content]]
	}
    }

    if {[Thread_Respond $sock \
	    [list Httpd_ReturnCacheableData $sock $type $content $date $code]]} {
	return
    }

    Count urlreply
    set close [HttpdCloseP $sock]
    if {[catch {
	HttpdRespondHeader $sock $type $close [string length $content] $code
	HttpdSetCookie $sock
	puts $sock "Last-Modified: [Httpd_Date $date]"
	puts $sock ""
	if {$data(proto) != "HEAD"} {
	    fconfigure $sock -translation binary -blocking $Httpd(sockblock)
	    puts -nonewline $sock $content
	}
	Httpd_SockClose $sock $close
    } err]} {
	HttpdCloseFinal $sock $err
    }
}

# Httpd_Filter
#	Add a post-generation filter to the socket
#
# Arguments:
#	sock	Client connection
#	args	filter proc or specs
#
# Side Effects:
#	Adds a filter to data(filter)
proc Httpd_Filter {sock args} {
    upvar #0 Httpd$sock data
    lappend data(filter) $args
}

# HttpdCopyDone -- this is used with fcopy when the copy completes.
#
# Arguments:
#	in	Input channel, typically a file
#	sock	Socket connection
#	close	If true, the socket is closed after the copy.
#	bytes	How many bytes were copied
#	error	Optional error string.
#
# Results:
#	None
#
# Side Effects:
#	See Httpd_SockClose

proc HttpdCopyDone {in sock close bytes {error {}}} {
    if {$error == ""} {
        # This special value signals a normal close,
        # and triggers a log record so static files are counted
        set error Close
    }
    Httpd_SockClose $sock $close $error
}

# HttpdCancel --
#
# Cancel a transaction if the client doesn't complete the request fast enough.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Terminates the connection by returning an error page.

proc HttpdCancel {sock} {
    upvar #0 Httpd$sock data
    Count cancel
    Httpd_Error $sock 408
}

# generic error response

set Httpd_ErrorFormat {
    <title>Httpd_Error: %1$s</title>
    Got the error <b>%2$s</b><br>
    while trying to obtain <b>%3$s</b>.
}

# Httpd_Error --
#
# send the error message, log it, and close the socket.
# Note that the Doc module tries to present a more palatable
# error display page, but falls back to this if necessary.
#
# Arguments:
#	sock	Socket connection
#	code	HTTP error code, e.g., 500
#	detail  Optional string to append to standard error message.
#
# Results:
#	None
#
# Side Effects:
#	Generates a HTTP response.

proc Httpd_Error {sock code {detail ""}} {

    if {[Thread_Respond $sock [list Httpd_Error $sock $code $detail]]} {
	# We've passed the error back to the main thread
	return
    }

    upvar #0 Httpd$sock data
    global Httpd Httpd_ErrorFormat

    Count errors
    append data(url) ""
    set message [format $Httpd_ErrorFormat $code [HttpdErrorString $code] $data(url)]
    append message <br>$detail
    if {$code == 500} {
	append message "<h2>Tcl Call Trace</h2>"
	for {set l [expr [info level]-1]} {$l > 0} {incr l -1} {
	    append message "$l: [protect_text [info level $l]]<br>"
	}
    }
    Log $sock Error $code $data(url) $detail

    # We know something is bad here, so we make the completion callback
    # and then unregister it so we don't get an extra call as a side
    # effect of trying to reply.

    HttpdDoCallback $sock $message

    if {[info exists data(infile)]} {
	# We've already started a reply, so just bail out
	Httpd_SockClose $sock 1
	return
    }
    if {[catch {
	HttpdRespondHeader $sock text/html 1 [expr {[string length $message] + 4}] $code
	puts $sock ""
	puts $sock $message
    } err]} {
	Log $sock LostSocket $data(url) $err
    }
    Httpd_SockClose $sock 1
}

set HttpdRedirectFormat {
    <html><head>
    <title>Found</title>
    </head><body>
    This document has moved to a new <a href="%s">location</a>.
    Please update your documents and hotlists accordingly.
    </body></html>
}

# Httpd_Redirect --
#
# Generate a redirect reply (code 302)
#
# Arguments:
#	newurl	New URL to redirect to.
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generates an HTTP reply

proc Httpd_Redirect {newurl sock} {
    upvar #0 Httpd$sock data
    global Httpd HttpdRedirectFormat

    if {[Thread_Respond $sock \
	    [list Httpd_Redirect $newurl $sock]]} {
	return
    }

    set message [format $HttpdRedirectFormat $newurl]
    set close [HttpdCloseP $sock]
    HttpdRespondHeader $sock text/html $close [string length $message] 302
    HttpdSetCookie $sock
    puts $sock "Location: $newurl"
    puts $sock "URI: $newurl"
    puts $sock ""

    # The -nonewline is important here to work properly with
    # keep-alive connections

    puts -nonewline $sock $message
    Httpd_SockClose $sock $close
}

# Httpd_NotModified --
#
# Generate a Not Modified reply (code 304)
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generates an HTTP reply

proc Httpd_NotModified {sock} {
    upvar #0 Httpd$sock data

    if {[Thread_Respond $sock \
	    [list Httpd_NotModified $sock]]} {
	return
    }

    HttpdRespondHeader $sock text/html 0 0 304
    HttpdSetCookie $sock
    puts $sock ""

    Httpd_SockClose $sock 0
}

# Httpd_RedirectSelf --
#
# Generate a redirect to another URL on this server.
#
# Arguments:
#	newurl	Server-relative URL to redirect to.
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generates an HTTP reply.

proc Httpd_RedirectSelf {newurl sock} {
    Httpd_Redirect [Httpd_SelfUrl $newurl $sock] $sock
}

# Httpd_SelfUrl --
#
# Create an absolute URL for this server
#
# Arguments:
#	url	A server-relative URL on this server.
#	sock	The current connection so we can tell if it
#		is the regular port or the secure port.
#
# Results:
#	An absolute URL.
#
# Side Effects:
#	None

proc Httpd_SelfUrl {url {sock ""}} {
    global Httpd
    if {$sock == ""} {
	set sock $Httpd(currentSocket)
    }
    upvar #0 Httpd$sock data

    set type [Httpd_Protocol $sock]
    set port [Httpd_Port $sock]
    if {[info exists data(mime,host)]} {

	# Use in preference to our "true" name because
	# the client might not have a DNS entry for use.

	set name $data(mime,host)
    } else {
	set name [Httpd_Name $sock]
    }
    set newurl $type://$name
    if {[string first : $name] == -1} {
	# Add in the port number, which may or may not be present in
	# the name already.  IE5 sticks the port into the Host: header,
	# while Tcl's own http package does not...

	if {$type == "http" && $port != 80} {
	    append newurl :$port
	}
	if {$type == "https" && $port != 443} {
	    append newurl :$port
	}
    }
    append newurl $url
}

# Httpd_Protocol --
#
# Return the protocol for the connection
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	Either "http" or "https"
#
# Side Effects:
#	None

proc Httpd_Protocol {sock} {
    upvar #0 Httpd$sock data
    return [lindex $data(self) 0]
}

# Httpd_Name --
#
# Return the server name for the connection
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	The name of the server, e.g., www.tcltk.org
#
# Side Effects:
#	None

proc Httpd_Name {sock} {
    upvar #0 Httpd$sock data
    return [lindex $data(self) 1]
}

# Httpd_Port --
#
# Return the port for the connection
#
# Arguments:
#	sock	The current connection. If empty, then the
#		regular (non-secure) port is returned.  Otherwise
#		the port of this connection is returned.
#
# Results:
#	The server's port.
#
# Side Effects:
#	None

proc Httpd_Port {{sock {}}} {
    if {[string length $sock]} {

	# Return the port for this connection

	upvar #0 Httpd$sock data
	return [lindex $data(self) 2]
    } else {

	# Return the non-secure listening port

	global Httpd
	if {[info exist Httpd(port)]} {
	    return $Httpd(port)
	} else {
	    return {}
	}
    }
}
# Httpd_SecurePort --
#
#	Return the secure port of this server
#
# Arguments:
#
# Results:
#	The server's secure port.
#
# Side Effects:
#	None

proc Httpd_SecurePort {} {

    # Return the secure listening port

    global Httpd
    if {[info exist Httpd(https_port)]} {
	return $Httpd(https_port)
    } else {
	return {}
    }
}

set HttpdAuthorizationFormat {
    <HTML><HEAD>
    <TITLE>401 Authorization Required</TITLE>
    </HEAD><BODY>
    <H1>Authorization Required</H1>
    This server could not verify that you
    are authorized to access the document you
    requested.  Either you supplied the wrong
    credentials (e.g., bad password), or your
    browser doesn't understand how to supply
    the credentials required.<P>
    </BODY></HTML>
}

# Httpd_RequestAuth --
#
# Generate the (401) Authorization required reply
#
# Arguments:
#	sock	Socket connection
#	type	usually "Basic"
#	realm	browsers use this to cache credentials
#	args	additional name value pairs for request
#
# Results:
#	None
#
# Side Effects:
#	Generate an authorization challenge response.

proc Httpd_RequestAuth {sock type realm args} {
    upvar #0 Httpd$sock data
    global Httpd HttpdAuthorizationFormat

    if {[Thread_Respond $sock \
	    [list Httpd_RequestAuth $sock $type $realm]]} {
	return
    }

    set additional ""
    foreach {name value} $args {
	append additional ", " ${name}=$value
    }

    set close [HttpdCloseP $sock]
    HttpdRespondHeader $sock text/html $close [string length $HttpdAuthorizationFormat] 401
    puts $sock "Www-Authenticate: $type realm=\"$realm\" $additional"
    puts $sock ""
    puts -nonewline $sock $HttpdAuthorizationFormat
    Httpd_SockClose $sock $close
}

# Httpd_Date --
#
# generate a date string in HTTP format
#
# Arguments:
#	seconds	Clock seconds value
#
# Results:
#	A date string.
#
# Side Effects:
#	None

proc Httpd_Date {seconds} {
    return [clock format $seconds -format {%a, %d %b %Y %T GMT} -gmt true]
}

# Httpd_SockClose --
#	"Close" a connection, although the socket might actually
#	remain open for a keep-alive connection.
#	This means the HTTP transaction is fully complete.
#
# Arguments:
#	sock	Identifies the client connection
#	closeit	1 if the socket should close no matter what
#	message	Logging message.  If this is "Close", which is the default,
#		then an entry is made to the standard log.  Otherwise
#		an entry is made to the debug log.
#
# Side Effects:
#	Cleans up all state associated with the connection, including
#	after events for timeouts, the data array, and fileevents.

proc Httpd_SockClose {sock closeit {message Close}} {
    global Httpd
    upvar #0 Httpd$sock data

    if {[string length $message]} {
	Log $sock $message
	if {$message == "Close"} {

	    # This is a normal close.  Any other message
	    # is some sort of error.

	    set message ""
	}
    }
    # Call back to the URL domain implementation so they are
    # sure to see the end of all their HTTP transactions.
    # There is a slight chance of an error reading any un-read
    # Post data, but if the URL domain didn't want to read it,
    # then they obviously don't care.

    HttpdDoCallback $sock $message

    Count connections -1
    if {[info exist data(infile)]} {

	# Close file or CGI pipe.  Still need catch because of CGI pipe.

	catch {close $data(infile)}
    }
    if {$closeit} {
	if {[info exists data(count)] && $data(count) > 0} {

	    # There is unread POST data.  To ensure that the client
	    # can read our reply properly, we must read this data.
	    # The empty variable name causes us to discard the POST data.

	    if {[info exists data(cancel)]} {
		after cancel $data(cancel)
	    }
	    set data(cancel) [after $Httpd(timeout3) \
		[list HttpdCloseFinal $sock "timeout reading extra POST data"]]

	    Httpd_GetPostDataAsync $sock "" $data(count) HttpdReadPostDone
	} else {
	    HttpdCloseFinal $sock
	}
    } else {
	HttpdReset $sock
    }
}

# HttpdReadPostDone --
#
#	Callback is made to this when we are done cleaning up any
#	unread post data.
#
# Arguments:
#	sock	Socket connection
#	varname	Name of variable with post data
#	errmsg	If not empty, an error occurred on the socket.
#
# Results:
#	None
#
# Side Effects:
#	None here, but see HttpdCloseFinal.

proc HttpdReadPostDone {sock var errmsg} {
    HttpdCloseFinal $sock $errmsg
}

# HttpdCloseFinal --
#
#	Central close procedure.  All close operations should funnel
#	through here so that the right cleanup occurs.
#
# Arguments:
#	sock	Socket connection
#	errmsg	If non-empty, then something went wrong on the socket.
#
# Results:
#	None
#
# Side Effects:
#	Cleans up any after event associated with the connection.
#	Closes the socket.
#	Makes the callback to the URL domain implementation.

proc HttpdCloseFinal {sock {errmsg {}}} {
    upvar #0 Httpd$sock data
    Count sockets -1
    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
    }
    if {[catch {close $sock} err]} {
	Log $sock CloseError $err
	if {[string length $errmsg] == 0} {
	    set errmsg $err
	}
    }
    HttpdDoCallback $sock $errmsg
    if {[info exist data]} {
	unset data
    }
}

# Httpd_RequestComplete --
#
#	Detect if a request has been sent.  The holder of a socket
#	might need to know of the URL request was completed with
#	one of the return-data commands, or is still lingering open.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	1 if the request was completed, 0 otherwise.
#
# Side Effects:
#	None.

proc Httpd_RequestComplete {sock} {
    upvar #0 Httpd$sock data
    if {![info exist data(state)] || $data(state) == "start"} {
	
	# The connection was closed or reset in a keep-alive situation.

	return 1
    } else {
	return 0
    }
}

# server specific version of bgerror - indent to hide from indexer

    proc bgerror {msg} {
	global errorInfo

	set msg "[clock format [clock seconds]]\n$errorInfo"
	if {[catch {Log nosock bgerror $msg}]} {
	    Stderr $msg
	}
    }

# HttpdCookieLog --
#
#	Special loggin procedure to debug cookie implementation.
#
# Arguments:
#	sock	Socket connection
#	what	What procedure is doing the logging.
#
# Results:
#	None
#
# Side Effects:
#	Writes to the debug log.

proc HttpdCookieLog {sock what} {
    global Log Httpd
    upvar #0 Httpd$sock data
    if {[info exist Log(log)] && ![info exist Httpd(cookie_log)]} {
	set Httpd(cookie_log) [open $Log(log)cookie a]
    }
    if {[info exist Httpd(cookie_log)]} {
	append result [LogValue data(ipaddr)]
	append result { } \[[clock format [clock seconds] -format %d/%h/%Y:%T] -0700\]

	append result { } $what
	switch $what {
	    Httpd_Dispatch {
		if {![info exist data(mime,cookie)]} {
		    return
		}
		append result { } \"$data(mime,cookie)\"
	    }
	    Httpd_SetCookie -
	    HttpdSetCookie {
		append result { } \"[LogValue data(set-cookie)]\"
	    }
	}
	catch { puts $Httpd(cookie_log) $result ; flush $Httpd(cookie_log)}
    }
}

# Httpd_Suspend --
#
#	Suspend Wire Callback - for async transactions
#	Use Httpd_Resume once you are back in business
#	Note: global page array is not preserved over suspend
#
# Arguments:
#	sock	Socket connection
#	timeout Timeout period.  After this the request is aborted.
#
# Results:
#	None
#
# Side Effects:
#	Disables fileevents and sets up a timer.

proc Httpd_Suspend {sock {timeout ""}} {
    global Httpd
    upvar #0 Httpd$sock data

    fileevent $sock readable {}
    fileevent $sock writable {}

    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
	unset data(cancel)
    }
    if {[info exists Httpd(currentSocket)]} {
	unset Httpd(currentSocket)
    }
    if {$timeout == ""} {
	set timeout $Httpd(timeout2)
    }
    if {$timeout != 0} {
	set data(cancel) [after $timeout [list HttpdCancel $sock]]
    }
}

# Httpd_Resume --
#
#	Resume processing of a request.  Sets up a bit of global state that
#	has been cleared by Httpd_Suspend.
#
# Arguments:
#	sock	Socket connection
#	timeout Timeout period.  After this the request is aborted.
#
# Results:
#	None
#
# Side Effects:
#	Restores the Httpd(currentSocket) setting.

proc Httpd_Resume {sock {timeout ""}} {
    upvar #0 Httpd$sock data
    global Httpd
    set Httpd(currentSocket) $sock
    if {[info exists data(cancel)]} {
	after cancel $data(cancel)
    }
    if {$timeout == ""} {
	set timeout $Httpd(timeout1)
    }
    set data(cancel) [after $timeout \
	[list Httpd_SockClose $sock 1 "timeout"]]
}

# Httpd_CurrentSocket --
#
#	Return (or set) the handle to the current socket.
#
# Arguments:
#	sock	Optional - if specified, set the current socket.
#
# Results:
#	A socket.
#
# Side Effects:
#	None.

proc Httpd_CurrentSocket {{sock {}}} {
    global Httpd
    if {[string length $sock]} {
	set Httpd(currentSocket) $sock
    }
    return $Httpd(currentSocket)
}

# Httpd_Pair --
#
#
# Pair two fd's - typically for tunnelling
# Close both if either one closes (or gets an error)
#
#
# Arguments:
#	sock	Socket connection
#	fd	Any other I/O connection
#
# Results:
#	None
#
# Side Effects:
#	Sets up fileevents for proxy'ing data.

proc Httpd_Pair {sock fd} {
    global Httpd
    upvar #0 Httpd$sock data

    syslog debug "HTTP: Pairing $sock and $fd"

    Httpd_Suspend $sock 0

    fconfigure $sock -translation binary -blocking 0
    fconfigure $fd -translation binary -blocking 0

    fileevent $sock readable [list HttpdReflect $sock $fd]
    fileevent $fd readable [list HttpdReflect $fd $sock]
}

# HttpdReflect --
#
#	This is logically fcopy in both directions, but the core
#	prevents us from doing that so we do it by hand.
#
# Arguments:
#	in	Input channel
#	out	Output channel
#
# Results:
#	None
#
# Side Effects:
#	Copy data between channels.

proc HttpdReflect {in out} {
    global Httpd
    if {[catch {
	set buf [read $in $Httpd(bufsize)]
	puts -nonewline $out $buf
	flush $out
	set buflen [string length $buf]
	if {$buflen > 0} {
	    syslog debug "Tunnel: $in -> $out ($buflen bytes)" 
	}
    } oops]} {
	Log $in Tunnel "Error: $oops"
    } elseif {![eof $in]} {
	return 1
    } else {
	syslog debug "Tunnel: $in EOF"
    }
    fileevent $in readable {}
    fileevent $out readable {}
    catch {flush $in}
    catch {flush $out}
    catch {close $in}
    catch {close $out}
    return 0
}

# Httpd_DumpHeaders --
#
#	Dump out the protocol headers so they can be saved for later.
#
# Arguments:
#	sock	Client connection
#
# Results:
#	A list structure that alternates between names and values.
#	The names are header names without the trailing colon and
#	mapped to lower case (e.g., content-type).  Two pseudo-headers
#	added: One that contains the original request URL; its name is "url"
#	Another that contains the request protocol; its name is "method"
#	There are no duplications in the header keys.  If any headers
#	were repeated, their values were combined by separating them
#	with commas.

proc Httpd_DumpHeaders {sock} {
    upvar #0 Httpd$sock data

    set result [list url $data(uri) method $data(proto) version $data(version)]
    if {[info exist data(mimeorder)]} {
	foreach key $data(mimeorder) {
	    lappend result $key $data(mime,$key)
	}
    }
    return $result
}

# Httpd_Webmaster --
#
# Define an email address for the webmaster
#
# Arguments:
#	email 	The email of the webmaster.  If empty, the
#		current value is returned, which is handy in
#		web pages.
#
# Results:
#	Returns the webmaster email.
#
# Side Effects:
#	Sets the webmaster email.

proc Httpd_Webmaster {{email {}}} {
    global Httpd
    if {[string length $email] == 0} {
	if {![info exists Httpd(webmaster)]} {
	    set Httpd(webmaster) webmaster
	}
	return $Httpd(webmaster)
    } else {
	set Httpd(webmaster) $email
    }
}


Added modules/httpd/imagemap.tcl.



























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# imagemap.tcl
# based on imagemap.c, version 1.8
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: imagemap.tcl,v 1.7 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::imagemap 1.0

package require httpd	;# Httpd_Redirect Httpd_ReturnData
package require httpd::counter	;# Count
package require httpd::utils	;# file parray

# Doc_application/x-imagemap --
#
# this is called by DocHandle to process .map files
#
# Arguments:
#	path	The file name of the .map file.
#	suffix	The URL suffix
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Redirect to the URL indicated by the map.

proc Doc_application/x-imagemap {path suffix sock} {
    upvar #0 Httpd$sock data
    if {![info exists data(query)]} {
	Httpd_ReturnData $sock text/plain "[parray Httpd$sock]"
	return
    }
    set url [Map_Lookup $path?$data(query)]
    Count maphits
    Httpd_Redirect $url $sock
}

proc MapPointInRect {X Y coordArray} {
	upvar $coordArray coords
        return [expr ($X >= $coords(0,X) && $X <= $coords(1,X)) && \
        ($Y >= $coords(0,Y) && $Y <= $coords(1,Y))]
}

proc MapPointInCircle {X Y coordArray} {
	upvar $coordArray coords

        set radius1 [expr (($coords(0,Y) - $coords(1,Y)) * ($coords(0,Y) - \
        $coords(1,Y))) + (($coords(0,X) - $coords(1,X)) * ($coords(0,X) - \
        $coords(1,X)))]
        set radius2 [expr (($coords(0,Y) - $Y) * ($coords(0,Y) - $Y)) + \
        (($coords(0,X) - $X) * ($coords(0,X) - $X))]
        return [expr $radius2 <= $radius1]
}

proc MapPointInPoly {tx ty pgonArray} {
	upvar $pgonArray pgon
	global MAXVERTS

	set numverts [expr [llength [array names pgon]] / 2]
	set lastvert [expr $numverts - 1]
        set crossings 0

        set y pgon($lastvert,Y)

        set p pgon(0,Y)
        if {($y >= $ty) != ($p >= $ty)} {
		set xflag0 [expr $pgon($lastvert,X) >= $tx]
                if {$xflag0 == ($pgon(0,X) >= $tx)} {
                        if $xflag0 {
                                incr crossings
			}
                } else {
                        incr crossings [expr {$pgon($lastvert,X) - ($y - $ty) *
			    ($pgon(0,X) - $pgon($lastvert,X)) /
			    ($p - $y) >= $tx}]
                }
        }

        for {set i 0} {$i < $numverts} {incr i} {
		set y $pgon($i,Y)
                if {$y >= $ty} {
			while {$i < $numverts && $pgon($i,Y) >= $ty} {
				incr i
			}
                } else {
			while {$i < $numverts && $pgon($i,Y) < $ty} {
				incr i
			}
		}
		if {$i >= $numverts} {
			break
		}
		set lasti [expr $i-1]
		set xflag0 [expr $pgon($lasti,X) >= $tx]
		if {$xflag0 == ($pgon($i,X) >= $tx)} {
			if $xflag0 {
				incr crossings
			}
		} else {
			incr crossings \
			    [expr ($pgon($lasti,X) - \
			    ($pgon($lasti,Y) - $ty) * \
			    ($pgon($i,X) - $pgon($lasti,X)) / \
			    ($pgon($i,Y) - $pgon($lasti,Y))) >= $tx]
		}
        }
        set inside_flag [expr $crossings & 0x01]
        return $inside_flag
}

proc MapTest {} {
    array set pgon {
	0,X 0.0   0,Y 0.0
	1,X 100.0 1,Y 0.0
	2,X 100.0 2,Y 100.0
	3,X 0.0   3,Y 100.0
    }
    foreach {X Y} {50. 50. 1. 1. 0. 0. 200. 200.} {
	puts "($X,$Y) In Poly [pointinpoly $X $Y pgon]"
    }
}

Added modules/httpd/include.tcl.















































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# include.tcl
#
# Stephen Uhler (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: include.tcl,v 1.7 2004/10/22 03:43:06 coldstore Exp $

# Process server side includes.
# Look for comments of the form:
#   <!--#keyword args  -->
# Where "keyword" is one of:
#  ECHO FLASTMOD FSIZE INCLUDE EXEC
# We do not implement
#  CONFIG
# The input string is passed on the command line to Httpd_include,
# and the result is returned.
# Note: the included file is treated as text, which possibly has
# other include files in it.  We are not doing a full URL dispatch
# on the included files, so they cannot be cgi scripts or other fancy
# objects.

package require html

package provide httpd::include 1.0

package require httpd	;# Httpd_Error Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::counter	;# Count
package require httpd::doc	;# Doc_Virtual
package require httpd::utils	;# file iscommand

# Global state for this module
# maxdepth controls recursively included files.

array set Include {
	maxdepth 10
}

# Process a file with server includes

proc Doc_application/x-server-include {path suffix sock} {
    Count includes
    if {[catch {open $path} in]} {
	Httpd_Error $sock 404 $in
    } else {
	global env
	Cgi_SetEnv $sock $path 
	set html [Include_Html $sock $path [read $in]]
	close $in
	Httpd_ReturnData $sock text/html $html
    }
}

# Process all the server includes.
# sock: a token passed through to the include procedures
# path: required to handle relative paths in recursive includes
# html:  The html to process
# depth: A counter to detect include loops

proc Include_Html {sock path html {depth 0}} {
    set token \x87	;# this character never appears in an html stream
    regsub -all {([][$\\])} $html {\\\1} html	;# protect TCL special characters
    regsub -all -- --> $html $token html	;# convert end of comment to token
    regsub -all "<!--# *(\[^ ]+) *(\[^$token]+)$token" $html \
	    "\[IncludeInner $sock {$path} {\\1} {\\2} [incr depth]\]" html	;# find all includes
    regsub -all $token $html --> html		;# recover end of comment tokens
    return  [subst $html]			;# process the includes
}

proc IncludeInner {sock path command params depth} {
    set command [string tolower $command]
    if {![iscommand include_$command]} {
	return "<!-- Server not configured to processes \"$command\" includes -->\n"
    } elseif {[catch {include_$command $sock $path $params $depth} result]} {
    	return "<!-- Server error in include command $command: $result -->\n"
    } else {
    	return $result
    }
}

# utility to extract the file name specified from the include parameters

proc IncludeFile {sock op path params} {
    if {[html::extractParam $params virtual orig]} {
	set key virtual
	set npath [Doc_Virtual $sock $path $orig]
    } elseif {[html::extractParam $params file orig]} {
	set key file
	set npath [file join [file dirname $path] $orig]
    } else {
	error "<!-- Invalid $op parameter list: $params. -->\n"
    }
    return [list $key $npath $orig]
}

# Each server function has its own procedure, that returns the substituted value
###############################################################################

# include another file
# Params:
#  virtual=path
#  file=path

proc include_include {sock path params depth} {
    global Include
    if {$depth > $Include(maxdepth)} {
    	return "<!-- Include recursion depth exceeded ($depth) -->\n"
    }
    if {[catch {IncludeFile $sock include $path $params} info]} {
	return $info
    }
    set key [lindex $info 0]
    set npath [lindex $info 1]
    set orig [lindex $info 2]

    # now open the file and re-do substitutions.

    if {[catch {open $npath r} fd]} {
	return "<!-- invalid include $key path $orig: $fd -->\n"
    }
    set data [Include_Html $sock $npath [read $fd] $depth]
    close $fd
    return $data
}

proc include_echo {sock path params args} {
    global env
    set var ""
    if {[html::extractParam $params var]} {
	if {[info exists env($var)]} {
	    return $env($var)
	} else {
	    return "<!-- No such variable: $var. -->\n"
	}
    }
    return "<!-- Echo: No var parameter. -->\n"
}

proc include_fsize {sock path params args} {
    if {[catch {IncludeFile $sock fsize $path $params} info]} {
	return $info
    }
    set key [lindex $info 0]
    set npath [lindex $info 1]
    set orig [lindex $info 2]
    if {[file exists $npath]} {
	return [file size $npath]
    } else {
	return "<!-- File not found $key: $npath. -->\n"
    }
}

proc include_exec {sock path params args} {
    set cmd ""
    if {[html::extractParam $params cmd]} {
	if {[catch {eval exec $cmd} result]} {
	    regsub -all -- --> $result {} result
	    return "<!-- $cmd error: $result  -->\n"
	} else {
	    return $result
	}
    }
}

proc include_config {sock path params args} {
    return "<!-- include config not implemented -->\n"
}

proc include_flastmod {sock path params args} {
    if {[catch {IncludeFile $sock flastmod $path $params} info]} {
	return $info
    }
    set key [lindex $info 0]
    set npath [lindex $info 1]
    set orig [lindex $info 2]
    if {[file exists $npath]} {
	return [clock format [file mtime $npath]]
    } else {
	return "<!-- File not found $key: $npath. -->\n"
    }
}

Added modules/httpd/log.tcl.



























































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# log.tcl
#
#	This is a file-based logging module for TclHttpd.
#
#	This starts a new log file each day with Log_SetFile
#	It also maintains an error log file that is always appeneded to
#	so it grows over time even when you restart the server.
#
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: log.tcl,v 1.14 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::log 1.1

package require httpd::config	;# Config
package require httpd::counter	;# Count Counter_CheckPoint
package require httpd::logstd	;# LogStandardData
package require httpd::utils	;# Stderr file

# log an Httpd transaction

# This program is used to compress log files
if {![info exists Log(compressProg)]} {
    set Log(compressProg) gzip
}

# Flush interval
if {![info exists Log(flushInterval)]} {
    set Log(flushInterval) [expr {60 * 1000}]
}

# This is used to turn on an alternate debug log file
if {![info exist Log(debug_log)]} {
    set Log(debug_log) 0
}


# Log --
#
#	Log information about the activity of TclHttpd.  There are two kinds of
#	log entries.  One "normal" entry that goes into its own log, one line
#	for each HTTP transaction.  All other log records are appended to an
#	error log file.
#
# Arguments:
#	sock	The client connection.
#	reason	If "Close", then this is the normal completion of a request.
#		Otherwise, this is some error tag and the record goes to
#		the error log.
#	args	Additional information to put into the logs.
#
# Results:
#	None
#
# Side Effects:
#	Writes data to the log files.

proc Log {sock reason args} {
    global Log
    upvar #0 Httpd$sock data

    # Log normal closes to the regular log.
    # Log everything else to the error log.

    switch -- $reason {
	"Close" {
	    set now [clock seconds]
	    set result [LogStandardData $sock $now]
	    if {[catch {puts $Log(log_fd) $result} err]} {
		set urk !
	    }
	    if {$Log(flushInterval) == 0} {
		catch {flush $Log(log_fd)}
	    }
	}
	"Debug" {
	    set now [clock seconds]
	    append result { } \[[clock format $now -format %d/%h/%Y:%T]\]
	    append result { } $sock { } $reason { } $args
	    if {[info exists data(url)]} {
		append result { } $data(url)
	    }
	    catch { puts $Log(debug_fd)  $result ; flush $Log(debug_fd) }
	}
	default {
	    set now [clock seconds]
	    append result { } \[[clock format $now -format %d/%h/%Y:%T]\]
	    append result { } $sock { } $reason { } $args
	    if {[info exists data(url)]} {
		append result { } $data(url)
	    }
	    catch { puts $Log(error_fd)  $result ; flush $Log(error_fd) }
	}
    }
}

# Log_Configure --
#
#	Query/modify configuration settings for logging.
#
# Arguments:
#	args	option/value pairs
#
# Results:
#	Configuration value(s) or empty string

proc Log_Configure args {
    global Log

    switch [llength $args] {
	0 {
	    foreach {key value} [array get Log] {
		lappend result [list -$key $value]
	    }
	    return $result
	}
	1 {
	    return $Log(-[lindex $args 0])
	}
	default {
	    if {[llength $args] % 2} {
		error "no value specified for option \"[lindex $args end]\""
	    } else {
		foreach {option value} $args {
		    switch -- $option {
			-lognames {
			    lappend newOptions lognames [boolean $value]
			}
			default {
			    # TODO: Other logging options, such as filenames, flush interval, etc
			    error "unknown option \"$option\""
			}
		    }
		}
		array set Log $newOptions
	    }
	}
    }
    return {}
}

# Log_FlushMinutes --
#
# Set the interval at which the logs are flushed.
#
# Arguments:
#	min	The minutes between flushes.  If 0,
#		then the log is flushed on each write.
#
# Results:
#	None
#
# Side Effects:
#	None

proc Log_FlushMinutes {min} {
    global Log
    set Log(flushInterval) [expr int($min*60*1000)]
    if {[info exist Log(flushID)]} {
	Log_Flush
    }
}

# Log_CompressProg --
#
# Set log compression program
#
# Arguments:
#	prog	the program used to compress logs
#
# Results:
#	None
#
# Side Effects:
#	None

proc Log_CompressProg {prog} {
    global Log
    set Log(compressProg) $prog
}

# Log_SetFile --
# automatically change log files every midnight
#
# Arguments:
#	basename 	The name of a base filename
#			including its directory,
#			e.g. /logs/www
#			This will create files like:
#			/logs/www80_00.09.23
#
# Results:
#	None
#
# Side Effects:
#	Closes and opens files, creating new files
#	each time through.

proc Log_SetFile {{basename {}}} {
    global Log
    if {[string length $basename]} {
	set Log(log) $basename
    }
    if {![info exists Log(log)]} {
	catch {close $Log(log_fd)}
	catch {close $Log(error_fd)}
	catch {close $Log(debug_fd)}
	return
    }
    catch {Counter_CheckPoint} 		;# Save counter data

    # set after event to switch files after midnight
    set now [clock seconds]
    set next [expr {([clock scan 23:59:59 -base $now] -$now + 1000) * 1000}]
    after cancel Log_SetFile
    after $next Log_SetFile

    # set the log file and error file.
    # Log files rotate, error files don't

    if {[info exists Log(log_file)] && [file exists $Log(log_file)]} {
	set lastlog $Log(log_file)
    }
    set Log(log_file) $Log(log)[clock format $now -format %y.%m.%d]
    catch {close $Log(log_fd)}

    # Create log directory, if neccesary, then open the log file

    catch {file mkdir [file dirname $Log(log_file)]}
    if {[catch {set Log(log_fd) [open $Log(log_file) a]} err]} {
	 Stderr $err
    }

    if {[info exists lastlog]} {
	# compress log files as we go
	if {[file executable $Log(compressProg)] &&
	    [catch {exec $Log(compressProg) $lastlog &} err]} {
	    Stderr $err
	}
    }

    catch {close $Log(error_fd)}
    if {[catch {set Log(error_fd) [open $Log(log)error a]} err]} {
	Stderr $err
    }

    # This debug log gets reset daily

    catch {close $Log(debug_fd)}
    if {[info exists Log(debug_file)] && [file exists $Log(debug_file)]} {
	catch {file rename -force $Log(debug_file) $Log(debug_file).old}
    }

    if {[info exist Log(debug_log)] && $Log(debug_log)} {
	set Log(debug_file) $Log(log)debug
	if {[catch {set Log(debug_fd) [open $Log(debug_file) w]} err]} {
	    Stderr $err
	}
    }
}

# Log_Flush --
# flush the output to the log file.  Do this periodically, rather than
# for every transaction, for better performance
#
# Arguments:
#
# Results:
#	None
#
# Side Effects:
#	Flushes the logs to disk.

proc Log_Flush {} {
    global Log
    catch {flush $Log(log_fd)}
    catch {flush $Log(error_fd)}
    catch {after cancel $Log(flushID)}
    if {$Log(flushInterval) > 0} {
	set Log(flushID) [after $Log(flushInterval) Log_Flush]
    }
}

Added modules/httpd/logstd.tcl.





















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# logstd.tcl
#
# Standard Web Log file format support.
#
# Stephen Uhler / Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: logstd.tcl,v 1.5 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::logstd 1.0

package require httpd	;# Httpd_Peername
package require httpd::log	;# Log
package require httpd::utils	;# file

# Use IP address, or domain name?
# Default is IP address, because looking up names is expensive
if {![info exists Log(lognames)]} {
    set Log(lognames) 0
}

# If true, we append cookie values to the log
if {![info exists Log(cookie)]} {
    set Log(cookie) 0
}

# LogStandardData --
#
#	Generate a standard web log file record for the current connection.
#	This records the client address, the URL, the time, the error
#	code, and so forth.
#
# Arguments:
#	sock	The client connection.
#	now	The timestamp for the connection, in seconds
#
# Results:
#	A string containing the log fie record.
#
# Side Effects:
#	None

proc LogStandardData {sock now} {
    return [LogStandardPrint [LogStandardList $sock $now]]
}

# LogStandardPrint --
#
#	Generate a standard web log file record for the current connection.
#	This records the client address, the URL, the time, the error
#	code, and so forth.
#
# Arguments:
#	sock	The client connection.
#	now	The timestamp for the connection, in seconds
#
# Results:
#	A string containing the log fie record.
#
# Side Effects:
#	None

proc LogStandardPrint {data} {
    set sep ""
    set result ""
    foreach {n v} $data {
	if {$v == "" || $v == "-"} {
	    append result ${sep}-
	    continue
	}
	switch -- $n {
	    time {
		 append result $sep\[[clock format $v -format "%d/%h/%Y:%T %Z"]\]
	    }
	    http -
	    referer -
	    useragent -
	    cookie {
		append result $sep"$v"
	    }
	    default {
		append result $sep$v
	    }
	}
	set sep " "
    }
    return $result
}

# LogStandardList --
#
#	Like LogStandardData, but return the data in a name, value list
#	suitable for use in foreach loops, array get, or long term
#	storage.
#
# Arguments:
#	sock	The client connection
#	now	The timestamp for the connection, in seconds
#
# Results:
#	A name, value list of the fields in a standard web log entry.
#
# Side Effects:
#	None

proc LogStandardList {sock now} {
    global Log
    upvar #0 Httpd$sock data
    if {$Log(lognames)} {
	if {[catch {lappend result ipaddr [Httpd_Peername $sock]}]} {
	    lappend result ipaddr [LogValue data(ipaddr)]
	}
    } else {
	lappend result	ipaddr [LogValue data(ipaddr)]
    }
    lappend result authuser [LogValue data(mime,auth-user)]
    lappend result username [LogValue data(mime,username)]
    lappend result time $now
    lappend result http [LogValue data(line)]
    lappend result status [LogValue data(code)]
    lappend result filesize [LogValue data(file_size)]
    lappend result referer [LogValue data(mime,referer)]
    lappend result useragent [LogValue data(mime,user-agent)]
    if {$Log(cookie)} {
      # This field is not always present in logs
      lappend result cookie [LogValue data(mime,cookie)]
    }
    return $result
}

# LogValue --
#
#	Generate a field or the default "null field" representation.
#
# Arguments:
#	var	The variable whose value to use, if any
#
# Results:
#	The value of the variable, or - as the default.
#
# Side Effects:
#	None

proc LogValue {var} {
    upvar $var data
    if {[info exists data]} {
	return $data
    } else {
       return -
    }
}

Added modules/httpd/mail.tcl.













































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# mail.tcl
# mail support using tcllib's smtp and mime packages
#
# The /mail URL is registered as a direct url that maps to procedures
# in this file that begin with Mail.
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: mail.tcl,v 1.16 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::mail 1.0

package require httpd	;# Httpd_Webmaster
package require httpd::config	;# Config
package require httpd::direct	;# Direct_Url
package require httpd::utils	;# file protect_text

# No useful default, but we define procedures so the vanilla server
# can start up.

# Config(mail) seems to be an old usage 
# MailServer is defined in tclhttpd.rc

if {[info exists Config(mail)] && ($Config(mail) != {})} {
    set Mail(server) $Config(mail)
} elseif {[config::cget MailServer] ne ""} {
    set Mail(server) [config::cget MailServer]
}

package require smtp
package require mime

# Mail_Send
#	Send email to recipients using tcllib's smtp client.
#
# Arguments:
#	recipients	list of email addresses to which to send the mail
#	subject	subject line for email
#	from	email address of email sender
#	type	mime type of body ("text/plain" for normal email)
#	body	the body of the email
#
# Results:
#	return the tcllib smtp client's return, {} if successful else:
#	A list indicating which recipients were unacceptable to the SMTP server.
#	Each element of the list is another list, containing the address,
#	an SMTP error code, and a textual diagnostic.
#	
# Side Effects:
#	Email is sent to each of the recipients

proc Mail_Send {recipients subject from type body} {
    global Mail

    set token [mime::initialize -canonical $type -string $body]
    mime::setheader $token Subject $subject

    set result [smtp::sendmessage $token \
		    -recipients $recipients \
		    -originator $from \
		    -servers $Mail(server)]
    mime::finalize $token
    return $result
}

# Mail_Result
#	convert tcllib smtp server result to a table suitable for display

proc Mail_Result {mail_err} {
    set html ""
    if {$result != {}} {
	set html <table>
	foreach el $result {
	    append html <tr>
	    foreach {addr errcode diagnostic} $el {
		append html <th> [protect_text $addr] </th>
		append html <td> [protect_text $errcode] </td>
		append html <td> [protect_text $diagnostic] </td>
	    }
	    append html </tr>
	}
	append html </table>
    }
    return $html
}

proc MailSend {recipients subject from type body} {
    set result [Mail_Send $recipients $subject $from $type $body]
    if {$result == ""} {
	set html "<b>Thank You!</b><br>Mailed report to <b>[protect_text $recipients]</b>"
    } else {
	return [Mail_Result $result]
    }
}

proc Mail_Url {dir} {
    Direct_Url $dir Mail
}

proc Mail/bugreport {email errorInfo args} {
    global Httpd
    set html "<pre>"
    foreach {name value} $args {
	if {([string compare $name "env"] == 0) && 
		([catch {array set X $value}] == 0)} {
	    # add this later
	    continue
	} else {
	    append html "$name: $value\n"
	}
    }
    append html  $Httpd(server)\n
    append html [protect_text $errorInfo]

    if {[info exist X]} {
	append html "\n\nEnvironment:\n"
	foreach n [lsort [array names X]] {
	    append html "  $n: $X($n)\n"
	}
    }
    append html "</pre>"
    if {$email == ""} {
	set email [Httpd_Webmaster]
    }
    MailSend $email "$Httpd(name):$Httpd(port) error" "" text/html $html
}

# If your form action is /mail/forminfo, then this procedure
# sends the results to the address specified by "sendto"
proc Mail/forminfo {sendto subject href label args} {
    set from ""
    foreach {name value} $args {
	# If the value has unbalanced braces, we will do base64
	# encoding to avoid a huge jumble of backslashes and
	# a long line that will not survive the email transport
	set blob [list $value]
	if {[regsub -all \\\\ $blob {} _] > 0} {
	    append message "[list Data64 $name] \\\n"
	    append message [list [base64::encode $value]]\n
	} else {
	    append message [list Data $name $value]\n
	}
	if {[string compare $name "email"] == 0} {
	    set from $value
	}
    }
    set html [MailSend $sendto $subject $from text/plain $message]
    if {[string length $href]} {
	if {[string length $label] == 0} {
	    set label Back
	}
	append html "<p><a href=\"$href\">$label</a>"
    }
    return $html
}

# This form is designed to be embedded into a page
# that handles form data.

proc Mail_FormInfo {} {
    global page
    set html {<!-- Mail_FormInfo -->}
    if {[info exist page(query)]} {
	array set q $page(query)
	if {[info exist q(sendto)] && [info exist q(subject)]} {
	    eval {Mail/forminfo $q(sendto) $q(subject) {} {}} $page(query)
	    set html {<!-- Mail_FormInfo sent email -->}
	}
    }
    return $html
}

# Older version of mail/forminfo
proc Mail/formdata {email subject args} {
    foreach {name value} $args {
	append message "$name: $value\n"
    }
    MailSend $email $subject {} text/plain $message
}

Added modules/httpd/maptcl.tcl.











































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# maptcl.tcl
# Pure Tcl imagemap handling.
#
# 	read in an image map file, and generate the appropriate canvas
# 	# sample image map
#	circle 	/sun-on-net/internet.sol/access.html  664,311 686,311
#	default	http://www.hal.com/
#	default 	/sunsoft/index.html
#	point /sunworldonline/common/swol-subscribe.html 45,134
#	poly / 182,11 184,88 301,77 365,86 393,57 393,10 
#	rect	/sunsoft/index.html 1,1 119,34
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: maptcl.tcl,v 1.7 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::ismaptcl 1.0
package require httpd::imagemap 1.0	;# MapPointInCircle MapPointInPoly MapPointInRect
package require httpd::log	;# Log
#package require httpd::utils	;# file

# translate an x/y coordinate into a url

proc Map_Lookup {request} {
    global ImageMaps
    if {[regexp {([^?]+)\?([0-9]+),([0-9]+)} $request {} map x y]} {
	if {[catch {file mtime $map} mtime]} {
	    return ""
	}
	if {![info exists ImageMaps($map)] ||
		($mtime > $ImageMaps(mtime,$map))} {
	    set ImageMaps($map) [MapRead $map]
	    set ImageMaps(mtime,$map) $mtime
	} 
	return [MapHit $ImageMaps($map) $x $y]
    } else {
	return ""
    }
}

# MapRead - this parses a map data file and converts it to
# a Tcl array that contains state about each region.
# This parser is another famous regsub-subst combo by Steve Uhler

proc MapRead {file} {
    if {[catch {open $file} fd]} {
	Log "" "file open" $fd
	return {}
    }
    regsub -all  {\.}  $file _ cookie
    set data [read $fd]
    close $fd
    regsub -all "(^|\n+)#\[^\n]*" $data {} data
    regsub -all {([][$\\])} $data {\\\1} data
    set types circle|default|point|poly|rect
    append exp {[ 	]*(} $types {)[ 	]+([^	}
    append exp \n { ]+)[ 	]*([^} \n\r {]*)} \[\n\r]+
    regsub -nocase -all $exp $data "\[MapInsert [list $cookie] \\1 {\\2} {\\3}]" cmd
    upvar #0 $cookie map
    catch {unset map}
    subst $cmd
    return $cookie
}

# helper proc for generating the data structure

proc MapInsert {cookie type href coords} {
    upvar #0 $cookie map
    if {![info exists map]} {
	set map(N) 0
    } else {
	incr map(N)
    }
    regsub -all , $coords { } coords
    set c {}
    set i 0
    foreach {X Y} $coords {
	lappend c $i,X $X $i,Y $Y
	incr i
    }
    set map($map(N),type) $type
    set map($map(N),coords) $c
    set map($map(N),href) $href
    if {$type == "default"} {
	set map(default) $href
    }
}

# MapHit looks up coordinates in a map

proc MapHit {cookie x y} {
    upvar #0 $cookie map
    set sawpoint 0
    for {set i 0} {$i < $map(N)} {incr i} {
	array set pgon $map($i,coords)
	switch $map($i,type) {
	    poly {
		if {[MapPointInPoly $x $y pgon]} {
		    return $map($i,href)
		}
	    }
	    circle {
		if {[MapPointInCircle $x $y pgon]} {
		    return $map($i,href)
		}
	    }
	    rect {
		if {[MapPointInRect $x $y pgon]} {
		    return $map($i,href)
		}
	    }
	    point {
		set dist [expr ($x - $pgon(0,X)) * ($x - $pgon(0,X)) + \
				($y - $pgon(0,Y)) * ($y - $pgon(0,Y))]
		if {!$sawpoint || ($dist < $mindist)} {
		    set mindist $dist
		    set default $map($i,href)
		}
	    }
	}
    }
    if {[info exists default]} {
	return $default
    }
    if {[info exists map(default)]} {
	return $map(default)
    }
    return {}
}

Added modules/httpd/maptk.tcl.



















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# maptk.tcl
# simple sample image map resolver
# uses Netscape map files
#
# This version uses a Tk canvas to do hit detection.
#
# Stephen Uhler (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: maptk.tcl,v 1.6 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::ismaptk 1.0

package require httpd::log	;# Log
#package require httpd::utils	;# file

# 	read in an image map file, and generate the appropriate canvas
# 	# sample image map
#	circle 	/sun-on-net/internet.sol/access.html  664,311 686,311
#	default	http://www.hal.com/
#	default 	/sunsoft/index.html
#	point /sunworldonline/common/swol-subscribe.html 45,134
#	poly / 182,11 184,88 301,77 365,86 393,57 393,10 
#	rect	/sunsoft/index.html 1,1 119,34

# translate an x/y coordinate into a url

proc Map_Lookup {request} {
    if {[regexp {([^?]+)\?([0-9]+),([0-9]+)} $request {} map x y]} {
	if {[catch {file mtime $map} mtime]} {
	    return ""
	}
	if {![info exists ImageMaps($map)] ||
		($mtime > $ImageMaps(mtime,$map))} {
	    set ImageMaps($map) [MapRead $map]
	    set ImageMaps(mtime,$map) $mtime
	} 
	return [MapHit $ImageMaps($map) $x $y]
    } else {
	return ""
    }
}

# Resolve hits by building a canvas (which is never mapped),
# with the map objects.  Use the file name as the canvas tag.

proc MapRead {file} {
    if {[catch {open $file} fd]} {
	Log "" "file open" $fd
	return {}
    }
    regsub -all  {\.}  $file _ cookie
    set data [read $fd]
    close $fd
    catch {destroy .image$cookie}
    set can [canvas .image$cookie]
    regsub -all "(^|\n+)#\[^\n]*" $data {} data
    regsub -all {([][$\\])} $data {\\\1} data
    set types circle|default|point|poly|rect
    append exp {[ 	]*(} $types {)[ 	]+([^	}
    append exp \n { ]+)[ 	]*([^} \n\r {]*)} \[\n\r]+
    regsub -nocase -all $exp $data "\[MapInsert [list $can] \\1 {\\2} {\\3}]" cmd
    $can lower default
    set tags [$can itemconfigure default -tags]
    $can itemconfigure default -tags [lindex $tags 0]
    subst $cmd
    return $can
}

# helper proc for generating the canvas

proc MapInsert {can type href coords} {
    regsub -all , $coords { } coords
    if {[catch {
    switch -- $type {
	default {
	    upvar #0 $can default
	    set default $href
#	    $can create rectangle  0 0 1000 1000 -fill white -tags [list $href default]
	}
	circle {
	    # The coords are the center and one point on the edge.
	    # Tk ovals are defined by two corner points.
	    foreach {x1 y1 x2 y2} $coords {break}
	    set r [expr int(sqrt(($y2 - $y1) * ($y2 - $y1) + \
				    ($x2 - $x1) * ($x2 - $x1)))]
	    set x1 [expr $x1 - $r]
	    set x2 [expr $x1 + 2*$r]
	    set y1 [expr $y1 - $r]
	    set y2 [expr $y1 + 2 * $r]
	    $can create oval $x1 $y1 $x2 $y2 -fill black -tags $href
	}
	rect {
	    eval {$can create rectangle} $coords -fill black -tags {$href}
	}
	poly {
	    eval {$can create polygon} $coords -fill black -tags {$href}
	}
	point {
	    eval {$can create oval} $coords $coords -width 2 -fill black \
		    -tags {$href}
	}
    }} err]} {
	Log $can $href $err
    }
}

proc MapHit {map x y} {
    if {[catch {
	$map gettags [lindex [$map find overlapping $x $y $x $y] 0]
    } result]} {
	set result {}
    }
    if {[string length $result] == 0} {
	upvar #0 $map default
	catch {set result $default}
    }
    return $result
}

Added modules/httpd/md5hex.tcl.





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This is a shim layer to deal with the inconsistencies
# between md5 1 and md5 2 (grr)

package provide httpd::md5hex 1.0
catch {
    # for some reason pkg_mkIndex barfs on this ... hide it.
    package require md5 2

    # md5hex always returns a hex version of the md5 hash

    if {[package vcompare [package present md5] 2.0] > -1} {
	# we have md5 v2 - it needs to be told to return hex
	interp alias {} md5hex {} ::md5::md5 -hex --
    } else {
	# we have md5 v1 - it returns hex anyway
	interp alias {} md5hex {} ::md5::md5
    }
}

Added modules/httpd/mime.types.

































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#
# Thanks to [email protected]
# This is the mime.types shipped with the NCSA http server

application/activemessage
application/andrew-inset                       
application/applefile
application/atomicmail                         
application/dca-rft                            
application/dec-dx                             
application/mac-binhex40	hqx
application/macwriteii
application/msword		doc dot
application/ms-excel		xls xlw xla xlc xlm xlt
application/ms-powerpoint	ppt pps pot
application/ms-project		mpp
application/x-msaccess		mdb
application/x-msmetafile	wmf
application/x-mswrite		wri
application/x-msschedule	scd
application/news-message-id                    
application/news-transmission      
application/octet-stream       bin core exe tgz gz Z zip          
application/octet-stream       sun4 i86pc
application/oda                oda
application/pdf                pdf
application/postscript         ai eps ps       
application/remote-printing                    
application/rtf                rtf             
application/slate                              
application/x-mif      mif
application/x-javascript	js
application/wita                               
application/wordperfect5.1
application/x-cgi		cgi
application/x-csh              csh             
application/x-dvi              dvi             
application/x-hdf              hdf             
application/x-latex            latex           
application/x-netcdf           nc cdf          
application/x-ns-proxy-autoconfig pac
application/x-safetcl		thtml
application/x-server-include	shtml
application/x-sh               sh              
application/x-tcl              tcl             
application/x-tcl-subst		subst
application/x-tcl-template	tml
application/x-tcl-auth		auth
application/x-tcl-snmp		snmp
application/x-tcl-connect	xtcl
application/x-tex              tex             
application/x-texinfo          texinfo texi   
application/x-troff            t tr roff       
application/x-troff-man        man             
application/x-troff-me         me              
application/x-troff-ms         ms              
application/x-wais-source      src             
application/x-imagemap		map
application/zip                zip             
application/x-bcpio            bcpio           
application/x-cpio             cpio            
application/x-gtar             gtar            
application/x-shar             shar            
application/x-sv4cpio          sv4cpio         
application/x-sv4crc           sv4crc          
application/x-tar              tar             
application/x-ustar            ustar           
application/x-patch		patch
application/x-shockwave-flash swf
audio/basic                    au snd          
audio/x-aiff                   aif aiff aifc
audio/x-wav                    wav             
image/gif                      gif GIF        
image/ief                      ief             
image/jpeg                     jpeg jpg jpe
image/tiff                     tiff tif        
image/x-cmu-raster             ras
image/x-portable-anymap        pnm             
image/x-portable-bitmap        pbm             
image/x-portable-graymap       pgm             
image/x-portable-pixmap        ppm             
image/x-rgb                    rgb
image/x-xbitmap                xbm             
image/x-xpixmap                xpm             
image/x-xwindowdump            xwd             
message/external-body
message/news
message/partial
message/rfc822
multipart/alternative
multipart/appledouble
multipart/digest
multipart/mixed
multipart/parallel
text/html                      html htm
text/plain                     txt
text/richtext                  rtx             
text/tab-separated-values      tsv             
text/x-setext                  etx             
text/xml		       xml
application/xhtml+xml    xhtml
text/css                       css
video/mpeg                     mpeg mpg mpe    
video/quicktime                qt mov          
video/x-msvideo                avi             
video/x-sgi-movie              movie           
text/vnd.wap.wml                wml
text/vnd.wap.wmlscript          wmls
application/vnd.wap.wmlc        wmlc
application/vnd.wap.wmscriptc   wmlsc
image/vnd.wap.wbmp              wbmp
audio/mpeg	mp3

Added modules/httpd/mtype.tcl.

















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# mimetype.tcl --
# Code to deal with mime types
#
# Brent Welch (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: mtype.tcl,v 1.9 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::mtype 1.1

#package require httpd::utils	;# file

# Convert the file suffix into a mime type

# global MimeType is a mapping from file extension to mime-type

proc Mtype {path} {
    global MimeType

    set ext [string tolower [file extension $path]]
    if {[info exist MimeType($ext)]} {
	return $MimeType($ext)
    } else {
	return text/plain
    }
}

# Read a mime types file into the mimeType array.
# Set up some minimal defaults if no file is available.

proc Mtype_ReadTypes {file} {
    global MimeType

    array set MimeType {
	{}	text/plain
	.txt	text/plain
	.htm	text/html
	.html	text/html
	.tml	application/x-tcl-template
	.gif	image/gif
	.thtml	application/x-safetcl
	.shtml	application/x-server-include
	.cgi	application/x-cgi
	.map	application/x-imagemap
	.subst	application/x-tcl-subst
    }
    if {[catch {open $file} in]} {
	return
    }

    while {[gets $in line] >= 0} {
	if {[regexp {^( 	)*$} $line]} {
	    continue
	}
	if {[regexp {^( 	)*#} $line]} {
	    continue
	}
	if {[regexp {([^ 	]+)[ 	]+(.+)$} $line match type rest]} {
	    foreach item [split $rest] {
		if {[string length $item]} {
		    set MimeType([string tolower .$item]) $type
		}
	    }
	}
    }
    close $in
}

# Mtype_Accept --
#
#	This returns the Accept specification from the HTTP headers.
#	These are a list of MIME types that the browser favors.
#
# Arguments:
#	sock	The socket connection
#
# Results:
#	The Accept header, or a default.
#
# Side Effects:
#	None

proc Mtype_Accept {sock} {
    upvar #0 Httpd$sock data
    if {![info exist data(mime,accept)]} {
	return */*
    } else {
	return $data(mime,accept)
    }
}

# Mtype_Match --
#
# 	This compares a document type with the Accept values.
#
# Arguments:
#	accept	The results of Mtype_Accept
#	type	A MIME Content-Type.
#
# Results:
#	1	If the content-type matches the accept spec, 0 otherwise.
#
# Side Effects:
#	None

proc Mtype_Match {accept type} {
    foreach t [split $accept ,] {
	regsub {;.*} $t {} t	;# Nuke quality parameters
	set t [string trim [string tolower $t]]
	if {[string match $t $type]} {
	    return 1
	}
    }
    return 0
}

# Mtype_Add --
#
# 	Add a MIME type mapping
#
# Arguments:
#	suffix	A file suffix
#	type	The corresponding MIME Content-Type.
#
# Results:
#       None

proc Mtype_Add {suffix type} {
    global MimeType

    set suffix [string trimleft $suffix .]
    set MimeType([string tolower .$suffix]) $type
}

# Mtype_Reset --
#
# 	Clear all MIME type mappings
#
# Arguments:
#	None
#
# Side Effects:
#       Unsets the MimeType array

proc Mtype_Reset {} {
    global MimeType
    if {[info exist MimeType]} {
        unset MimeType
    }
}

Added modules/httpd/objects.tcl.









































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# objects.tcl
#
# Provides a hook for objects to process URLs
# Object that are connected are expected to expose the method:
#
# httpdMarshallArguments [suffix] [cgiList]
#
# Returns a command that is immediately evaluated, usually in the
# form of [object] [method] [key/value list]
#
# For an example of this system in action, see custom/objects.tcl
# in the distribution
#
# Copyright
# Sean Woods (c) 2008
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: objects.tcl,v 1.1 2008/05/06 00:17:47 eviltwinskippy Exp $


package provide httpd::objects 1.0


# Object_Url
#	Define a subtree of the URL hierarchy that is implemented by
#	direct Tcl calls to a Tao Object.
#
# Arguments
#	virtual The name of the subtree of the hierarchy, e.g., /device
#	object	The Tcl object to use when constructing calls,
#		e.g. Device
#	inThread	True if this should be dispatched to a thread.
#
# Side Effects
#	Register an object

proc ::Object_Url {virtual object {inThread 0}} {
    global Direct
    set Direct($object) $virtual    ;# So we can reconstruct URLs
    Url_PrefixInstall $virtual [list ObjectDomain $object] $inThread
}

# Object_UrlRemove
#       Remove a subtree of the URL hierarchy that is implemented by
#       direct Tcl calls.
#
# Arguments
#       object  The Tcl object used when constructing calls,
#
# Side Effects
#
       
proc ::Object_UrlRemove {object} {
    global Direct
    catch { Url_PrefixRemove $Direct($object) }
    catch { unset Direct($object) }
}
        
# Main handler for Object domains (i.e. tcl commands)
# object: the object registered with Object_Url 
# sock: the socket back to the client
# suffix: the part of the url after the object.
#
# This calls out to the Object with the suffix being either
# a direct method to this object, a reference to an object
# and a method to call to the referered object.
#
# All parameters from the form are fed into a Dict
# All object method called must be prefixed with "httpd"
#
# Example:
# Object_Url /device Device
# if the URL is /device/a/display, then the Tcl command to handle it
# should be
# proc [Device /node a] httpdDisplay
#
# You can define the content type for the results of your procedure by
# modifying the global ::page(content-type) field
#
# ::page(content-type) is reset to text/html every pageview

proc ::ObjectDomain {object sock suffix} {
    global Direct
    global env
    upvar #0 Httpd$sock data
    global page
    set page(content-type) text/html

    # Set up the environment a-la CGI.

    Cgi_SetEnv $sock $object
    #$suffix

    # Prepare an argument data from the query data.

    Url_QuerySetup $sock
    set cmd [$object httpdMarshallArguments $suffix [::ncgi::nvlist]]
    
    if {$cmd == ""} {
	Doc_NotFound $sock
	return
    }
    set code [catch $cmd result]
    
    ::Object_Respond $sock $code $result $page(content-type)
}

# Object_Respond --
#
#	This function returns the result of evaluating the object
#	url.  Usually, this involves returning a page, but a redirect
#	could also occur.
#
# Arguments:
# 	sock	The socket back to the client.
#	code	The return code from evaluating the direct url.
#	result	The return string from evaluating the direct url.
#	type	The mime type to use for the result.  (Defaults to text/html).
#
# Notes: Cargo Culted from Direct_Url Code. May start to differ later.
#
# Results:
#	None.
#
# Side effects:
#	If code 302 (redirect) is passed, calls Httpd_Redirect to 
#	redirect the current request to the url in result.
#	If code 0 is passed, the result is returned to the client.
#	If any other code is passed, an exception is raised, which
#	will cause a stack trace to be returned to the client.
#

proc ::Object_Respond {sock code result {type text/html}} {
    switch $code {
	0 {
	    # Fall through to Httpd_ReturnData.
	}
	302	{
	    # Redirect.

	    Httpd_Redirect $result $sock
	    return ""
	}
	default {
	    # Exception will cause error page to be returned.

	    global errorInfo errorCode
	    return -code $code -errorinfo $errorInfo -errorcode $errorCode \
		    $result
	}
    }

    # See if a content type has been registered for the URL.

    # Save any return cookies which have been set.
    # This works with the Doc_SetCookie procedure that populates
    # the global cookie array.
    ::Cookie_Save $sock

    ::Httpd_ReturnData $sock $type $result
    return ""
}

Added modules/httpd/open.tcl.

























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# opentrace.tcl --
#
# This is a wrapper around the open command that keeps track of what
# file (or pipe) was opened for a particular channel.  Useful for
# debugging file descriptor leaks.
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: open.tcl,v 1.3 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::opentrace 1.0

#package require httpd::utils	;# file

if {[info commands "open-orig"] == ""} {
    rename open open-orig
    proc open {path {mode r} {perms {}}} {
	global OpenFiles
	if {[catch {
	    if {[string length $perms]} {
		set io [open-orig $path $mode $perms]
	    } else {
		set io [open-orig $path $mode]
	    }
	} err]} {
	    return -code error $err
	}
	set OpenFiles($io) $path
	return $io
    }
}

if {[info commands "close-orig"] == ""} {
    rename close close-orig
    proc close {io} {
	global OpenFiles
	if {[info exist OpenFiles($io)]} {
	    set OpenFiles($io) "CLOSED $OpenFiles($io)"
	}
	close-orig $io
    }
}

Added modules/httpd/passcheck.tcl.















































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# passcheck.tcl
# 
package provide httpd::passcheck 1.0

namespace eval passcheck { }

# Copyright(c) Genesys Software Romania srl., 2000
#
# License is granted here to use this code for any purpose, 
# No warranties included.
#
# 
# 
# Provides password checking against various systems.
# Useful with TCLHTTPD server, available from http://www.tcl.tk/
#
# The purpose is to avoid maintaining duplicate password tables
# for tclhttpd, and re-use instead existing systems available in your local net.
# This way users dont need to remember many passwords - just use known passwords.
#
#
# Currently implemented are pop3 and odbc checkers. 
#
# Use pop3 pass checker to authenticate users against an pop mail server
# it requires pop3 package 
# 
# Use odbc pass checker to perform authentication against a ODBC datasource 
# available locally to the web server. 
# 
# 
# You can add your passcheckers by providing procedures with the following
# syntax and name conventioni: (we consider thi will authenticate against LDAP:
#
# proc ::passcheck::verify_ldap {sock realm user pass {config {}}} { .... return 1 or 0 }
# 
# the sock, realm, user, pass arguments are the same as received by a .tclaccess "callback"
# command.
#
# the config argument should provide significant configuration options for the checker.
# e.g. for pop3 it should be a mail server machine name, running pop3 service, 
# and for odbc - a datasource name.
#
# Other usefull commands are here - to see wich types of checkers are available, 
# to clear password caches
# for specific or all realms, to see wich realms and how are configured. 
# Author: Cezar Totth <[email protected]>
#
set ::passcheck::comment {

 #
 # You'll probably need to add these in your tclhttpd.rc file..
 #
 package require httpd::passcheck
 #
 ################# POP3 example 
 # Configure checker to use pop3 authentication for the realm named "LocalMail" against 
 # an existing local pop server. 

 set pop3server 192.168.50.5 
 ::passcheck::setChecker LocalMail pop3 $pop3server

 #
 ######################## 
 #Then  you can specify within any .tclaccess file:
 realm LocalMail
 callback ::passcheck::Verify

 ########################
 
 ################# ODBC example ##########################
 # Configure it to authenticate against a datasource.
 # The realm will be named "DbServer"
 ::passcheck::setChecker DbServer odbc $datasource

 ###### and in .tclaccess files: 
 realm DbServer
 callback ::passcheck::Verify

}

################################  End of comment here ...

proc ::passcheck::setChecker {realm passcheckerName {confopt {}}} {
  set ::passcheck::_Config($realm) [list verify_$passcheckerName $confopt]
}

proc ::passcheck::unsetConf {realm} {
  catch {unset ::passcheck::_Config($realm)}
}
#
# The pass checker configuration for all realms. 
#
set ::passcheck::DefaultChecker [list verify_deny {}]

proc ::passcheck::getChecker realm { 
  upvar #0 ::passcheck::_Config($realm) myConf
  if {[info exists myConf]} { return $myConf }
  return ${::passcheck::DefaultChecker}
}

proc ::passcheck::getCheckerConf {realm} { return  [lindex [::passcheck::getChecker $realm] 1] }
proc ::passcheck::getCheckerName {realm} { return  [lindex [::passcheck::getChecker $realm] 0] }

#
# Returns the available types of passcheckers (e.g. pop3, odbc, never, allways..)
proc ::passcheck::getCheckerTypes {} {
  set toR {}
  foreach cname [info commands ::passcheck::verify_*] {
    lappend toR [lindex [split $cname _] 1]
  }
  return $toR
}

#
# returns wich realms are controlled by our pass checkers
proc ::passcheck::getRealms {} {
  return [array names ::passcheck::_Config] 
}

#
# Use this to clear password caches. Needed after users changed their passwords.
# No realm specified means to clear all caches of all realms.
proc ::passcheck::clearCache {{realm {}}} {
  if {![llength $realm]} { 
     set rlist [info vars ::passcheck::_passCache_*]
  } else { set rlist ::passcheck::_passCache_$realm } 
  foreach carr $rlist {
     catch { unset $carr } 
  }
}

#
# this is to be specified from .tclaccess files on tclhttpd.
# add lines:
# 
# set realm ARealmName
# set callback ::passcheck::Verify
# 
proc ::passcheck::Verify {socket realm user pass}  {
   upvar #0 ::passcheck::_passCache_$realm pcache
   set kpass [crypt $pass 91] 
   if {[info exists pcache($user)]} {
     if { "$kpass" == "$pcache($user)" } { 
       set ::env(REMOTE_USER) $user
       return 1 
     } else { unset pcache($user) }
   } 
   set pcheck [::passcheck::getChecker $realm]
   set tocall [list [lindex $pcheck 0] $socket $realm $user $pass [lindex $pcheck 1]]
   # puts "will call: $tocall"
   set rez 0 
   catch { set rez [eval $tocall] } 
   if {$rez} {
       set pcache($user) $kpass
       set ::env(REMOTE_USER) $user 
   }
   return $rez
}

############################## Basic Auth --> Pop3 authentication ######################
#
# By default the tcl server is considered to run on the email server.
# On most Unix-like systems this means authentication is made against
# the local system
proc ::passcheck::verify_pop3 {socket realm user pass {conf localhost}} {
   if {[catch {::pop3::close [::pop3::open $conf $user $pass]}] } { 
       return 0 
   } 
   return 1
}

############################# TCLODBC Datasource authentication #######################
proc ::passcheck::verify_odbc {socket realm user pass {conf passcheck}} {
  if {[catch {
         database _passCheck_db$conf$user $conf $user $pass
      } ] } { return 0 }
  _passCheck_db$conf$user disconnect
  return 1
}
#
############################ Dummy pass checkers ######################################
# These are dummy pass checkers. Usefull in automated tests, or to temporarly lock/unlock
# realms
proc ::passcheck::verify_deny  {socket realm user pass {conf {}}} { return 0 }
proc ::passcheck::verify_allow {socket realm user pass {conf {}}} { return 1 }

########################### external packages availability #######################
# 
# warning messages. Shall it go to server's log too? 
proc ::passcheck::warning message { 
    puts "passcheck: $message" 
}
#
#
# Is better to have crypt handy  to cache passwords with more confidence. 
if { [catch { package require crypt } ] } {
  # we provide a dummy crypt...
  package require tclcrypt
  #::passcheck::warning {no crypt package available! passwords cached in cleartext!}
  #proc crypt {word salt} { return "${word}$salt" }
}

#
# checking for POP3 
if { [catch { package require pop3 } ] } { 
  ::passcheck::warning {no POP3 pass check available! verify pop3 package}
  # rename pop3_verify pop3_notAvail 
}

#
# checking for TCLODBC 
if { [catch { package require tclodbc } ] } {
  ::passcheck::warning {no ODBC pass check available! verify tclodbc package}
  # rename odbc_verify odbc_notAvail 
}

Added modules/httpd/passgen.tcl.









































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# password generator
# generate a password according to the passgen_rules array
#
# Source: http://mini.net/tcl/Password%20Generator
# Author: Mark Oakden http:/wiki.tcl.tk/MNO
# Version: 1.0

# no sanity checks on the supplied rules are done.

package provide httpd::passgen 1.0

# datasets for password generation:-
# separate lowercase and UPPERCASE letters so we can demand minimum
# number of each separately.
array set passgen {
    letters "abcdefghijklmnopqrstuvwxyz"
    LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    numbers "0123456789"
    punctuation "!\"\x{00A3}$%^&*()_+-={};':@#~<>,.?/\\|"
}

# a simpler set might be, for example:-
#
# set passgen(letters) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
# set passgen(numbers) "0123456789"
# set passgen(punctuation) "!\"\x{00A3}$%^&*()_+-={};':@#~<>,.?/\\|"
    
# the rules determine characteristics of the randomly generated passwords
# presently available are:-
# passgen_rules(len) password length
# passgen_rules(<dataset_name>,min) minimum number of characters from <dataset_name>
# entry on the passgen array

# example rules:-
# password 7 chars long, with at least one U/C char, one l/c char,
# one number and one punctuation.
array set passgen_rules {
    len 7
    letters,min 1
    LETTERS,min 1
    numbers,min 1
    punctuation,min 1
}

# example rules appropriate to the commented "simpler" datasets above:-
#
# set passgen_rules(len) 7
# set passgen_rules(numbers,min) 1
# set passgen_rules(punctuation,min) 1

# picks a (pseudo)random char from str
proc PassgenOneCharFrom { str } {
    set len [string length $str]
    set indx [expr int(rand()*$len)]
    return [string index $str $indx]
}

# given a string, and integers i and j, swap the ith and jth chars of str
# return the result
proc PassgenSwap { str i j } {
    if { $i == $j } {
	return $str
    }
    if { $i > $j } {
	set t $j
	set j $i
	set i $t
    }
    set pre [string range $str 0 [expr $i - 1]]
    set chari [string index $str $i]
    set mid [string range $str [expr $i + 1] [expr $j - 1]]
    set charj [string index $str $j]
    set end [string range $str [expr $j + 1] end]
    
    set ret ${pre}${charj}${mid}${chari}${end}
    return $ret
}

# for a string of length n,  swap random pairs of chars n times
# and return the result
proc PassgenShuffle { str } {
    set len [string length $str]
    for { set i 1 } { $i <= $len } { incr i 1 } {
	set indx1 [expr int(rand()*$len)]
	set indx2 [expr int(rand()*$len)]
	set str [PassgenSwap $str $indx1 $indx2]
    }
    return $str
}

# generate a password
proc Passgen_Generate {} {
    variable passgen
    variable passgen_rules

    # Algorithm
    # 1. foreach dataset with a min parameter, choose exactly min
    #    random chars from it
    # 2. concatenate results of above into password
    # 3. concatenate all datasets into large dataset
    # 4. choose desired_length-password_length chars from large
    # 5. concatenate (4) and (2)
    # 6. shuffle (5)
    
    set password {}
    foreach indx [array names passgen_rules *,min] {
	set ds_name [lindex [split $indx ,] 0]
	set num $passgen_rules($indx)
	for {set i 1} {$i <= $num} {incr i 1} {
	    append password [PassgenOneCharFrom $passgen($ds_name)]
	}
    }
    
    set all_data {}
    foreach set [array names passgen] {
	append all_data $passgen($set)
    }
    
    set rem_len [expr $passgen_rules(len) - [string length $password]]
    for {set i 1} {$i <= $rem_len} {incr i 1} {
	append password [PassgenOneCharFrom $all_data]
    }
    
    return [PassgenShuffle $password]
}

set passgen(saltstr) "$passgen(LETTERS)$passgen(letters)$passgen(numbers)"
proc Passgen_Salt {} {
    global passgen
    set slen [string len $passgen(saltstr)]
    return "[string index $passgen(saltstr) [expr round(rand() * $slen)]][string index $passgen(saltstr) [expr round(rand() * $slen)]]"
}

Added modules/httpd/pkgIndex.tcl.







































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex -direct" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd 1.7 [list source [file join $dir httpd.tcl]]
package ifneeded httpd::admin 1.0 [list source [file join $dir admin.tcl]]
package ifneeded httpd::auth 2.0 [list source [file join $dir auth.tcl]]
package ifneeded httpd::cgi 1.1 [list source [file join $dir cgi.tcl]]
package ifneeded httpd::config 1.0 [list source [file join $dir config.tcl]]
package ifneeded httpd::cookie 1.0 [list source [file join $dir cookie.tcl]]
package ifneeded httpd::counter 2.0 [list source [file join $dir counter.tcl]]
package ifneeded httpd::debug 1.0 [list source [file join $dir debug.tcl]]
package ifneeded httpd::digest 1.0 [list source [file join $dir digest.tcl]]
package ifneeded httpd::direct 1.1 [list source [file join $dir direct.tcl]]
package ifneeded httpd::dirlist 1.1 [list source [file join $dir dirlist.tcl]]
package ifneeded httpd::doc 1.1 [list source [file join $dir doc.tcl]]
package ifneeded httpd::doc_error 1.0 [list source [file join $dir doc_error.tcl]]
package ifneeded httpd::doctools 1.0 [list source [file join $dir doctools.tcl]]
package ifneeded httpd::fallback 1.0 [list source [file join $dir fallback.tcl]]
package ifneeded httpd::imagemap 1.0 [list source [file join $dir imagemap.tcl]]
package ifneeded httpd::include 1.0 [list source [file join $dir include.tcl]]
package ifneeded httpd::ismaptcl 1.0 [list source [file join $dir maptcl.tcl]]
package ifneeded httpd::ismaptk 1.0 [list source [file join $dir maptk.tcl]]
package ifneeded httpd::log 1.1 [list source [file join $dir log.tcl]]
package ifneeded httpd::logstd 1.0 [list source [file join $dir logstd.tcl]]
package ifneeded httpd::mail 1.0 [list source [file join $dir mail.tcl]]
package ifneeded httpd::md5hex 1.0 [list source [file join $dir md5hex.tcl]]
package ifneeded httpd::mtype 1.1 [list source [file join $dir mtype.tcl]]
package ifneeded httpd::opentrace 1.0 [list source [file join $dir open.tcl]]
package ifneeded httpd::passcheck 1.0 [list source [file join $dir passcheck.tcl]]
package ifneeded httpd::passgen 1.0 [list source [file join $dir passgen.tcl]]
package ifneeded httpd::redirect 1.0 [list source [file join $dir redirect.tcl]]
package ifneeded httpd::safecgio 1.0 [list source [file join $dir safecgio.tcl]]
package ifneeded httpd::session 1.0 [list source [file join $dir session.tcl]]
package ifneeded httpd::srvui 1.0 [list source [file join $dir srvui.tcl]]
package ifneeded httpd::status 1.0 [list source [file join $dir status.tcl]]
package ifneeded httpd::stdin 1.1 [list source [file join $dir stdin.tcl]]
package ifneeded httpd::subst 1.0 [list source [file join $dir subst.tcl]]
package ifneeded httpd::template 1.0 [list source [file join $dir template.tcl]]
package ifneeded httpd::threadmgr 1.0 [list source [file join $dir thread.tcl]]
package ifneeded httpd::upload 1.0 [list source [file join $dir upload.tcl]]
package ifneeded httpd::url 1.2 [list source [file join $dir url.tcl]]
package ifneeded httpd::utils 1.0 [list source [file join $dir utils.tcl]]
package ifneeded httpd::version 4.0 [list source [file join $dir version.tcl]]
package ifneeded tclcrypt 1.0 [list source [file join $dir tclcrypt.tcl]]

Added modules/httpd/prodebug.tcl.























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# prodebug.tcl --
#
#	This file contains the public routines used to start debugging user
#	code in a remote application.
#
# Copyright (c) 1998-2000 by Ajuba Solutions
# All rights reserved.
#
# RCS: @(#) $Id: prodebug.tcl,v 1.1 2000/08/02 07:06:53 welch Exp $


#
# This file comprises the public interface to the TclPro Debugger for use
# by applications that are not launched directly from the debugger.  The
# public interface consists of the two commands "debugger_init" and
# "debugger_eval".  A typical application will source this file then invoke
# "debugger_init" to initiate the connection to the debugger.  Once
# connected, the application can use the "debugger_eval" command to
# evaluate scripts that the debugger will be able to step through.
# Additionally, various other Tcl commands including "source" and "proc"
# will automatically instrument code.  Any blocks of code (e.g. procedure
# bodies) that existed before "debugger_init" was invoked will execute
# without any instrumentation.
#


# debugger_init --
#
#	This function initiates a connection to the TclPro Debugger.  Files
#	that are sourced and procedures that are defined after this
#	function completes will be instrumented by the debugger.
#
# Arguments:
#	host	Name of the host running the debugger.
#	port	TCP port that the debugger is using.
#
# Results:
#	Returns 1 on success and 0 on failure.


proc debugger_init {{host 127.0.0.1} {port 2756}} {
    global tcl_version

    if {[catch {set socket [socket $host $port]}] != 0} {
	return 0
    }
    fconfigure $socket -blocking 1 -translation binary

    # Send the loader and tcl library version

    set msg [list HELLO 1.0 $tcl_version]
    puts $socket [string length $msg]
    puts -nonewline $socket $msg
    flush $socket

    # Get the rest of the nub library and evaluate it in the current scope.
    # Note that the nub code assumes there will be a "socket" variable that
    # contains the debugger socket channel.

    if {[gets $socket bytes] == -1} {
	close $socket
	return 0
    }
    set msg [read $socket $bytes]
    eval [lindex $msg 1]
    return 1
}

# debugger_eval --
#
#	Instrument and evaluate a script.  This routine is a trivial
#	implementation that is replaced when the nub is downloaded.
#
# Arguments:
#	args		One or more arguments, the last of which must
#			be the script to evaluate.
#
# Results:
#	Returns the result of evaluating the script.

proc debugger_eval {args} {
    global errorInfo errorCode
    set length [llength $args]
    if {$length < 1} {
	error "wrong # args: should be \"debugger_eval ?options? script\""
    }
    set code [catch {uplevel 1 [lindex $args [expr {$length - 1}]]} result]
    return -code $code -errorcode $errorCode -errorinfo $errorInfo $result
}


Added modules/httpd/redirect.tcl.







































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# redirect.tcl
#
# Support for redirecting URLs.
# You can either do a single redirect (Redirect_Url)
# or you can redirect a whole subtree elsewhere (Redirect_UrlTree)
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: redirect.tcl,v 1.7 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::redirect 1.0

package require httpd	;# Httpd_Redirect Httpd_RedirectSelf Httpd_SelfUrl
package require httpd::direct	;# Direct_Url
package require httpd::url	;# Url_AccessInstall Url_Dispatch Url_PrefixInstall Url_Unwind
#package require httpd::utils	;# file

# Redirect_To --
#
# Trigger a page redirect
#
# Arguments:
#	newurl	The new URL
#
# Results:
#	None
#
# Side Effects:
#	Raises a special error that is caught by Url_Unwind

proc Redirect_To {newurl} {
    return -code error \
	    -errorcode  [list HTTPD_REDIRECT $newurl] \
	    "Redirect to $newurl"
}

# Redirect_Self --
#
#	Like Redirect_To, but to a URL that is relative to this server.
#
# Arguments:
#	newurl	Server-relative URL
#
# Results:
#	None
#
# Side Effects:
#	See Redirect_To

proc Redirect_Self {newurl} {
    set thispage [ncgi::urlStub]
    set thisurl [Httpd_SelfUrl $thispage]
    set newurl [uri::resolve $thisurl $newurl]
    Redirect_To $newurl
}


# Redirect_QuerySelf --
#
#	Like Redirect_Self, but preserves query data
#
# Arguments:
#	newurl	Server-relative URL
#
# Results:
#	None
#
# Side Effects:
#	See Redirect_To

proc Redirect_QuerySelf {sock newurl} {
    upvar #0 Httpd$sock data

    # Preserve query data when bouncing among pages.
    if {[info exist data(query)] && [string length $data(query)]} {
	append newurl ? $data(query)
    }

    Redirect_Self $newurl	;# offer what we have to the client
}

# Redirect_Dir --
#
# Generate a redirect because the trailing slash isn't present
# on a URL that corresponds to a directory.
#
# Arguments:
#	sock	Socket connection
#
# Results:
#	None
#
# Side Effects:
#	Generate a redirect page.

proc Redirect_Dir {sock} {
    global Httpd
    upvar #0 Httpd$sock data

    set url  $data(url)/
    if {[info exist data(query)] && [string length $data(query)]} {
	# maintain the query data
	append url ? $data(query)
    }
    Httpd_Redirect $url $sock
}

# Redirect_Init
#
#	Initialize the redirect module.
#
# Arguments:
#	url	(optional) Direct URL for redirect control.
#
# Side Effects:
#	Registers access hook to implement redirects.
#	May register direct domain

proc Redirect_Init {{url {}}} {
    if {[string length $url]} {
	Direct_Url $url Redirect
    }
    # The [list] makes the eval in Url_Dispatch run slightly faster
    Url_AccessInstall [list RedirectAccess]

    # Load the default redirect file
    Redirect/reload
}

# Redirect_UrlTree
#
#	Map a whole URL hierarchy to a new place
#
# Arguments:
#	old	Old location, (e.g., /olddir)
#	new	New location, (e.g., /newdir)
#
# Side Effects:
#	Future requests to old/a/b/c will redirect to new/a/b/c

proc Redirect_UrlTree {old new} {
    Url_PrefixInstall $old [list RedirectDomain $new]
}

# RedirectDomain
#
#	Set up a domain that redirects requests elsewhere
#	To use, make a call like this:
#
#	Url_PrefixInstall /olddir [list RedirectDomain /newdir]
#
# Arguments:
#	prefix	The Prefix of the domain
#	url	The other URL to which to redirect
#
# Results:
#	This always raises a redirect error

proc RedirectDomain {url sock suffix} {
    set newurl $url$suffix
    Httpd_Redirect $newurl $sock
}

# Redirect_Url
#
#	Redirect a single URL to another, fully-qualified URL.
#
# Arguments:
#	old	Old location, (e.g., /olddir/file.html)
#	new	New location, (e.g., http://www.foo.bar/newdir/newfile.html)
#
# Side Effects:
#	Future requests to $old will redirect to $new

proc Redirect_Url {old new} {
    global Redirect
    set Redirect($old) $new
}

# Redirect_UrlSelf
#
#	Redirect a single URL to another location on the same server.
#
# Arguments:
#	old	Old location, (e.g., /olddir/file.html)
#	new	New location, (e.g., /newdir/newfile.html)
#
# Side Effects:
#	Future requests to $old will redirect to $new

proc Redirect_UrlSelf {old new} {
    global RedirectSelf

    # Cannot make the "self" computation until we have
    # a socket and know the protocol and server name for sure

    set RedirectSelf($old) $new
}

# RedirectAccess
#
#	This is invoked as an "access checker" that will simply
#	redirect a URL to another location.
#
# Arguments:
#	sock	Current connection
#	url	The url of the connection
#
# Results:
#	Returns "denied" if it triggered a redirect.  This stops URL processing.
#	Returns "skip" otherwise, so other access control checks can be made.

proc RedirectAccess {sock url} {
    global Redirect
    global RedirectSelf

    if {[info exist RedirectSelf($url)]} {
	
	# Note - this is not an "internal" redirect, but in this case
	# the server simply qualifies the url with its own name

	Httpd_RedirectSelf $RedirectSelf($url) $sock
	return denied
    }
    if {[info exist Redirect($url)]} {
	Httpd_Redirect $Redirect($url) $sock
	return  denied
    }
    return skip
}

# Redirect/reload
#
#	Direct URL to reload the redirect configuration file.
#
# Arguments:
#	none
#
# Side Effects:
#	Sources "redirect" from the document root.

proc Redirect/reload {} {
    global Doc
    set path [file join $Doc(root) redirect]
    if { ! [file exists $path]} {
	return
    }
    source $path
    set html "<h3>Reloaded redirect file</h3>"
    append html [Redirect/status]
    return $html
}

# Redirect/status
#
#	Display the Redirection tables
#
# Arguments:
#	none
#
# Results:
#	An HTML table

proc Redirect/status {} {
    global Redirect
    global RedirectSelf
    global Url	;# hack alert

    append html "<h3>Redirect Table</h3>\n"
    append html "<table>\n"
    append html "<tr><th colspan=2>Single URLs</th></tr>\n"
    foreach old [lsort [array names RedirectSelf]] {
	append html "<tr><td>$old</td><td>$RedirectSelf($old)</td></tr>\n"
    }
    foreach old [lsort [array names Redirect]] {
	append html "<tr><td>$old</td><td>$Redirect($old)</td></tr>\n"
    }
    append html "<tr><th colspan=2>URL Subtrees</th></tr>\n"
    foreach prefix [lsort [array names Url command,*]] {
	if {[string match RedirectDomain* $Url($prefix)]} {
	    set new [lindex $Url($prefix) 1]
	    regsub command, $prefix {} prefix
	    append html "<tr><td>$prefix</td><td>$new</td></tr>\n"
	}
    }
    append html </table>\n
    return $html
}

Added modules/httpd/safecgio.tcl.















































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# safecgio.tcl
# Brent Welch (c) 1996 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
#
# RCS: @(#) $Id: safecgio.tcl,v 1.8 2004/10/22 03:43:06 coldstore Exp $
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

# Safe Tcl security policy for server-side CGI-like processing.
# The HTTPD will "subst" an html page in the context of a safecgio interpreter
# in order to efficiently compute a page.  This security policy gives the
# safe interpreter limited access to files within a specified directory.
#
#  The script has access to the "env" array, which contains the same
#  information as for a CGI bin script.
#
#  Any query information, either from a POST or GET query is available
#  as a name-value list in the "Query" variable.

package provide httpd::safecgio 1.0

package require httpd::log	;# Log
package require httpd::utils	;# Stderr file

# start a safe CGI server 

proc SafeCGI_Server {port} {
    if {[catch {socket -server SafeCGI_Accept $port} oops]} {
	Stderr "SafeCGI_Server: $oops"
	exit 1
    }
}

# Accept a connection from Httpd server.

proc SafeCGI_Accept {sock addr port} {
    fconfigure $sock -blocking off
    fileevent $sock readable [list SafeCGIRead $sock]
}

# Read and execute commands from the Http server

proc SafeCGIRead {sock} {
    global Env Query

    if {[eof $sock]} {
	close $sock
    } else {
	set command {}
	foreach {command value} [gets $sock] break
	switch -- $command {
	    SetEnv	{ catch {array set Env $value} }
	    SetQuery	{ set Query $value }
	    DoFile	{ SafeCGIDo $sock $value }
	    Exit	{ exit }
	}
    }
}

# Create a safe interpreter to "subst" a data file.

proc SafeCGIDo {sock filename} {
    global Query Env argv0

    if {![catch {open $filename} fd]} {
	append Query {}
	set child child$sock		;# Name of child interpreter
	SafeCGI_Create $child 
	interp transfer {} $fd $child
	interp eval $child {
	    proc DoCGI {fd Query envlist} {
		global env
		array set env $envlist
		subst [read $fd]
	    }
	}

	if {![catch {
	    interp eval $child [list DoCGI $fd $Query [array get Env]]
	} result]} {
	    puts -nonewline $sock $result
	} else {
	    Log $sock SafeCGIDo "$argv0 Error in $filename\n\t<$result>"
	}
	interp delete $child		;# Does close of transferred fd
    }
    close $sock
}

# security policy defined below.
#####################################################################
#
# Create a child that is limted to a few open files within
# a given directory.  If they open for writing, limit the size
# of the output file.

proc SafeCGI_Create {name {directory .} {maxopen 4} {maxsize 4096}} {
    global interpState
    interp create -safe $name
    interp alias $name open {} SafeCGI_Open $name $maxopen $directory
    interp eval  $name {rename puts {}}
    interp alias $name puts {} SafeCGI_Puts $name $maxsize
    interp eval  $name {rename close _close}	;# would rather "hide" this
    interp alias $name close {} SafeCGI_Close $name
    interp alias $name exit {} SafeCGI_Cleanup $name
    set interpState(channels,$name) {}
}

# Open files in a given directory.
# Paramters set by the definition of the alias:
# 	interp is a child interperter
# 	maxopen is the max number of open files for the child
# 	directory is the directory
# Parameters from the child's call
# 	file is the name of the file
# 	access is the I/O mode

proc SafeCGI_Open {interp maxopen directory file {access r}} {
    global interpState

    if {[llength $interpState(channels,$interp)] >= $maxopen} {
	error "couldn't open \"$file\": too many open files"
    }
    if {[regexp "^\[ \t\]*|" $file]} {
	error "no pipes allowed"
    }
    # Constrain the pathname to a one-component relative name
    if {([llength [file split $file]] != 1) ||
	    [file pathtype $file] != "relative"} {
	error "couldn't open \"$file\": permission denied"
    }
    # Disallow symbolic links and other non-file types
    set path [file join $directory $file]
    if {[file exists $path]} {
	file lstat $path stat		;# lstat here prevents symlinks
	if {$stat(type) != "file"} {
	    error "couldn't open \"$file\": not a plain file"
	}
    }
    set out [open $path $access]
    lappend interpState(channels,$interp) $out
    interp share {} $out $interp
    return $out
}
    # This is an alias to clean up children that exit
    # interp is the exiting child
    # interpState records open files for the child
    # We share them, so we must close our references.

proc SafeCGI_Cleanup {interp} {
    global interpState

    interp delete $interp
    foreach out $interpState(channels,$interp) {
	catch {close $out}
    }
    unset interpState(channels,$interp)
}

# This is an alias for puts that limits file size
# Parameters set by the alias definition:
# 	interp is the child interpreter
# 	max is the file size limit, in bytes
# Parameters set in the call to the alias
#   args is ?-nonewline? chan string
# 		chan is the I/O channel
# 		string is the output data

proc SafeCGI_Puts {interp max args} {
    if {[string match "-nonewline" [lindex $args 0]]} {
	set flag -nonewline
	set args [lrange $args 1 end]
    } else {
	set flag ""
    }
    if {[llength $args] == 1} {
	# Flag output to stdout as coming from the unsafe interpreter
	set chan stdout
	set string "Untrusted code $name says: [lindex $args 0]"
    } elseif {[llength $args] == 2} {
	set chan [lindex $args 0]
	set string [lindex $args 1]
    } else {
	error "wrong # args: should be \"puts ?-nonewline? ?channelId? string\""
    }
    if {[string match "stdout" $chan"]} {
	set size [string length $string]	;# Tell makes no sense
    } else {
	set size [expr [tell $chan] + [string length $string]]
    }
    if {$size > $max} {
	    interp eval $interp [list close $chan]
	    error "File size exceeded"
    } else {
	    eval puts $flag {$chan $string}
    }
}

# An alias for close that lets the parent clean up its reference

proc SafeCGI_Close {interp chan} {
	global interpState
	set ix [lsearch $interpState(channels,$interp) $chan]
	if {$ix >= 0} {
	    catch {close $chan}
	    set interpState(channels,$interp) \
		    [lreplace $interpState(channels,$interp) $ix $ix]
	}
	$interp eval _close $chan	;# Need "invoke" hidden close
}

    proc bgerror {msg} {
	global errorInfo
	Stderr $errorInfo
    }

Added modules/httpd/session.tcl.













































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
 # session.tcl -- 
# Session management support.
#
# A session is implemented as a safe slave interpreter that holds its state.
#
# Creating a session with Session_Create returns either a 4 character ID
# (if MD5 is missing or Session(short) is true) or an unforgeable MD5
# hash.
#
# Use Session_Match to find and/or create a session based on query data.
#
# Use Session_Destroy to delete one session, and Session_Reap to
# clean up "old" sessions.
#
# A session has a type, which is used to automatically create aliases for
# the slave.  If the type is Foo, then every Tcl procedure named Foo_*
# in the master will be created as an alias.  The Foo_ prefix gets
# stripped off the alias name in the slave.
#
# Certain first arguments are treated specially for the aliases:
# if the first argument is "session", then the alias automatically
# gets called with the current session ID as the first argument.
# if the first argument is "interp", then the alias automatically
# gets called with the interp name as the first argument.
# (From a session you get also get the interp name).
#
# In addition, a few aliases are defined for all types:
# session - returns the session identifier
# sequence - returns an increasing sequence number used to chain together
# 	pages and detect bookmarks and "backs" that screw things up.
# group - set or get the current session "group".
# value - get a value from the current "group", or a default value
#
# Session state can be organized in "groups", which are just Tcl arrays
# in the safe interpreters.  The master keeps track of the current group
# for a session, and the slave can change the group and query group
# values with the "value" alias.  There is no standard for setting
# group values, but typically query data is copied into them by
# the module that uses the sessions.
#
# Stephen Uhler  (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: session.tcl,v 1.16 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::session 1.0

package require httpd::cookie	;# Cookie_GetSock Cookie_Make
package require httpd::doc	;# Doc_Root
package require httpd::utils	;# Stderr file iscommand randomx

# use long session IDs
if {![info exists Session(short)]} {
    set Session(short) 0
}

# how long do session cookies last?
if {![info exists Session(expires)]} {
    set Session(expires) "now + 10 years"	;# should be long enough
}

# if an MD5 package is available, we use it to make
# an unforgeable session ID, otherwise default to 
# the old 4-digit session ID
if {($Session(short) == 1) || [catch {package require httpd::md5hex}]} {
    # we have no usable md5 or have elected short session IDs
    proc SessionGenId {} {
	return [randomx]
    }
} else {
    # generate a long and unforgeable session id
    proc SessionGenId {} {
	return [md5hex [randomx]]
    }
}

proc Session_Authorized {id} {
    upvar #0 Session:$id session
    if {![info exists session(interp)]} {
	set interp [SessionCreate $id]
	SessionAuthorizedAliases $interp $id
    }
    return $session(interp)
}

proc SessionAuthorizedAliases {interp id} {
    upvar #0 Session:$id session
    interp alias $interp require {} Session_Require $id
    interp alias $interp exit {} Session_Destroy $id
}

proc Session_Require {id tag} {
    upvar #0 Session:$id session
    if {![info exists session(init)]} {
	if {![iscommand ${tag}_Init]} {
	    set html "
		<h4>No ${tag}_Init proc</h4>
	    "
	} else {
	    set html [${tag}_Init Session:$id]
	}
    } else {
	set html "<-- Session $id -->"
    }
    return $html
}
proc Dummy_Init {name} {
    upvar #0 $name session
    return "<-- Dummy_Init was here -->"
}

# Create a new session as a safe slave interpreter.
# Populate it with the useful aliases.
#   Type:  An arbitrary session type, used for automatic alias creation.

proc Session_Create {type {isSafe 1}} {

    # Pick a unique session id, create the interpreter and global state.

    while {[info globals *[set id [SessionGenId]]*] != ""} {}
    Session_CreateWithID $type $id $isSafe
}

proc Session_CreateWithID {type id {isSafe 1}} {
    set interp [SessionCreate $id $isSafe]
    SessionTypeAliases $interp $id $type
}

proc SessionCreate {id {isSafe 1}} {
    upvar #0 Session:$id session
    if {$isSafe} then {
	set interp [interp create -safe interp$id]
    } else {
        set interp [interp create interp$id]
    }
    set session(start) [clock seconds]
    set session(current) $session(start)
    set session(count) 0
    set session(interp) $interp
    return $interp
}

proc SessionTypeAliases {interp id type} {
    upvar #0 Session:$id session
    set session(type) $type

    # Set up the  document specific aliases for this interp  This
    # looks for all procedures in the master interpreter that start
    # with "<type>_".  Since some of them might be auto-loaded, look
    # in the auto index array.  The names get stored in an array to
    # remove duplicates.

    global auto_index
    foreach name "[info commands ${type}_*] [array names auto_index ${type}_*]" {
    	set procs($name) {}
    }

    # Look at the *name* of the first argument to each alias-able proc.
    # Some names are treated specally.

    foreach proc [array names procs] {
	regexp -- ${type}_(.*) $proc {} alias
	catch {lindex [info args $proc] 0} arg0
	switch -- $arg0 {
	    session {interp alias $interp $alias {} $proc $id}
	    interp  {interp alias $interp $alias {} $proc $interp}
	    default {interp alias $interp $alias {} $proc}
	}
    }

    # Set up the common aliases for all session interpreters.

    interp alias $interp session {} Session_Session $id
    interp alias $interp sequence {} Session_Sequence $id
    interp alias $interp group {} Session_Value $id group
    interp alias $interp value {} Session_Variable $id

    return $id
}

# Destroy all sessions older than a certain age (in seconds)
#    age:  time (in seconds) since the most recent access
#    type: a regexp to mach session types with (defaults to all)

proc Session_Reap {age {type .*}} {
    foreach id [info globals Session:*] {
	upvar #0 $id session
	set old [expr {[clock seconds] - $age}]
	if {[regexp -- $type $session(type)] && $session(current) < $old} {
	    catch {interp delete $session(interp)}
	    Stderr "Reaping session $id"
	    unset session
	}
    }
}

# Destroy a single session

proc Session_Destroy {id} {
    upvar #0 Session:$id session
    if {[info exists session]} {
	interp delete $session(interp)
	unset session
	SessionDiscard $id
	return 1
    } else {
    	return 0
    }
}


# Find the correct session, and return the proper interp or error.
# This is identical to Session_Match, but uses cookies to store
# session id.
# If the session is "new", then create a new one.
# - query: optional alist containing the form and/or url query
# - type:  The type of this session
# - error_name:  The variable holding the error result (if any)

proc Session_Cookie {{querylist {}} {type {}} {error_name error} {isSafe 1}} {
    upvar $error_name error
    global Httpd
    set sock $Httpd(currentSocket)

    # fetch cookies pertaining to session
    set old 0
    foreach {key var} {session session session_sequence sequence} {
	set x [Cookie_GetSock $sock ${type}_$key]
	if {$x != ""} {
	    incr old
	    lappend querylist $var [lindex $x 0]
	}
    }

    # try to find an existing or saved session
    set error ""
    array set query $querylist
    set id [Session_Match [array get query] $type error $isSafe]

    # we must have lost the old session. lose the cookies and try again
    if {$error == "Session: Invalid session id."} {
	set query(session) new
	set error ""
	set id [Session_Match [array get query] $type error $isSafe]
	set old 0
    }

    # set the session cookies
    if {!$old} {
	global Session
	upvar #0 Session:$id session

	foreach {key var} {session id
	    session_sequence session(sequence)
	    session_type session(type)} {
	    if {[info exists $var]} {
		Httpd_SetCookie $sock [Cookie_Make -expires $Session(expires) -path / -name ${type}_$key -value [set $var]] 1
	    }
	}
    }

    # we accept an additional session_cmd argument to manipulate sessions
    if {[info exists query(session_cmd)]} {
	switch $query(session_cmd) {
	    save {
		Session_Save $id
	    }
	}
    }

    return $id
}

# Create and return the session directory for saved sessions
proc SessionDir {} {
    if {![info exists Session(dir)]} {
	# I'm not keen on this default location, as it could
	# be exposed to URL fetches
	set Session(dir) [file join [Doc_Root] .sessions]
    }
    file mkdir $Session(dir)
    return $Session(dir)
}

# Destroy the session cookie for this type
# note, this won't take immediate effect,
# you may have to reload the page to get the new cookies
proc Session_CookieDestroy {{type {}}} {
    global Httpd
    set sock $Httpd(currentSocket)
    
    foreach key {session session_sequence} {
	Httpd_RemoveCookies $sock ${type}_*
    }
}

# Save session state in a file under $Session(dir),
# for later reconstruction
proc Session_Save {id} {
    upvar #0 Session:$id session

    # create a session save file, write state
    set sfile [file join [SessionDir] ${id}.sess]
    set fd [open $sfile w]
    puts $fd $session(type)
    puts $fd [interp issafe interp$id]
    puts $fd [array get session]

    # add Self Vars
    set vars ""
    set arrays ""
    foreach sv [interp eval $session(interp) info vars] {
	switch -regexp -- $sv {
	    tcl_* -
	    env -
	    errorCode -
	    errorInfo -
	    arg[cv] -
	    auto_* {}
	    default {
		if {[interp eval $session(interp) array exists $sv]} {
		    append arrays "array set $sv [list [interp eval $session(interp) array get $sv]]" \n
		} else {
		    append vars "set $sv [list [interp eval $session(interp) set $sv]]" \n
		}
	    }
	}
    }
    puts $fd $vars
    puts $fd $arrays

    close $fd
}

# SessionDiscard - destroy persistent record of session $id
proc SessionDiscard {id} {
    set sfile [file join [SessionDir] ${id}.sess]
    if {[file exists $sfile]} {
	# delete the session save file
	file delete $sfile
    }
}

# SessionFetch - fetch persistent record of session $id
proc SessionFetch {id} {
    upvar #0 Session:$id session
    set sfile [file join [SessionDir] ${id}.sess]
    if {[file exists $sfile]} {
	# open a session save file, read state
	set fd [open $sfile r]
	set type [gets $fd]
	set isSafe [gets $fd]
	set sarray [gets $fd]
	set script [read $fd]
	close $fd
	
	# create the interpreter
	Session_CreateWithID $type $id $isSafe
	array set session $sarray	;# set session vars
	interp eval $session(interp) $script

	# consistency check
	if {$type != {} && $type != $session(type)} {
	    return "Session: Invalid session type."
	}

	return ""
    } else {
	# there's no stored session
	return "Session: Invalid session id."
    }
}

# Find the correct session, and return the proper interp or error.
# If the session is "new", then create a new one.
# - query:       The array containing the form and/or url query
#    session:	Either an ID or "new".  
#               an ID will return that ID to confirm that the session is valid
#                 or will return an empty string if session is invalid.
#               "new" will create a new session.
#    sequence:   Sequence position if this is a sequential set of pages.
# - type:        The type of this session
# - error_name:  The variable holding the error result (if any)
# - isSafe:      True to create a safe interp, false for normal.

proc Session_Match {querylist {type {}} {error_name error} {isSafe 1}} {
    upvar $error_name error

    # Check the session informatioin provided in the query data.

    if {[catch {
	array set query $querylist
    }]} {
	Stderr "Bogus querylist\n$querylist"
    }

    if {![info exists query(session)]} {
	set error "Session: no session id provided."
	return {}
    }

    set id $query(session)
    if {$id == "new"} {
	set id [Session_Create $type $isSafe]
    } elseif {[regexp "kill(.+)" $id x id]} {
	Session_Destroy $id
	set id [Session_Create $type $isSafe]
    } elseif {[regexp "save(.+)" $id x id]} {
	Session_Save $id
    }

    upvar #0 Session:$id session
    if {![array exists session]} {
	# see if there's a session to be instantiated
	set error [SessionFetch $id]
	if {$error != ""} {
	    return {}
	}
    } else {
	# session's already instantiated
    }

    # Check sequence number (if any).
    if {[info exists session(sequence)]} {
    	if {![info exists query(sequence)]} {
	    set error "Session: Sequence number required, not provided."
	    return $id
    	}
    	if {$query(sequence) != $session(sequence)} {
	    set error "Session: Sequence number invalid."
	    return $id
    	}
    	unset session(sequence)
    }

    # Update the session access time and count, and return the session id.

    set session(current) [clock seconds]
    incr session(count)
    return $id
}

# Import variables from a global array into the local scope.
#  valid:  The array containing the legal values to import.  If valid
#          is {}, then all names in "array" will be imported.
#  array:  The name of the global array  in "Interp" to import from.
#  Interp: The interpreter to import it from.

proc Session_Import {valid array {interp {}}} { 
    upvar $valid ok
    foreach {name value} [interp eval $interp [list array get $array]] {
    	if {$valid == {} || [info exists ok(-$name)]} {
	    upvar $name var
	    set var $value
	}
    }
}

###################################
# Common Aliases for interpreters

# Return the (constant) session id.  The id is a constant created at 
# alias time.

proc Session_Session {arg} {
    return $arg
}    

# set up a sequence number.  Id is the session id, passed in at alias time.

proc Session_Sequence {id} {
    upvar #0 Session:$id session
    set session(sequence)  $session(count)
}

# Set or return a session variable.  The slave alias may be set up to allow
# read access only.

proc Session_Variable {id var {value ""}} {
    upvar #0 Session:$id state
    if {$value != {}} {
    	set state($var) $value
    } 
    if {[info exists state($var)]} {
    	return $state($var)
    } else {
    	return ""
    }
}

# Get a group variable, specify a default if not set

proc Session_Value {id var {default {}}} {
    upvar #0 Session:$id session
    set group $session(group)
    if {[catch {interp eval $session(interp) set ${group}($var)} value]} {
	set value $default
    }
    return $value
}

Added modules/httpd/srvui.tcl.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# srvui.tcl
# Trivial Tk control panel for the server.
#
# Brent Welch  (c) 1997 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: srvui.tcl,v 1.9 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::srvui 1.0

package require httpd	;# Httpd_Shutdown
package require httpd::counter	;# Count CountVarName
package require httpd::utils	;# file

proc SrvUI_Init {title} {
    global Httpd Doc
    option add *font 9x15
    
    wm title . $Httpd(name):$Httpd(port)
    wm protocol . WM_DELETE_WINDOW {Httpd_Shutdown; exit}
    wm iconname . $Httpd(name):$Httpd(port)
	set msgText "$title\n$Httpd(name):$Httpd(port)"
    if {[info exists Httpd(https_listen)]} {
    	append msgText "\n$Httpd(name):$Httpd(https_port) (Secure Server)"
    }
    append msgText "\n$Doc(root)"
    message .msg -text $msgText -aspect 1000
    grid .msg -columnspan 2 -sticky news

    foreach {url label} {
	    / "Home Page"
	    } {
	label .l$url -text $label
	label .n$url -textvariable counterhit($url) -width 0
	grid .l$url .n$url -sticky w
	grid configure .n$url -sticky e
    }
    foreach {counter label} {
	    urlhits "URL Requests"
	    urlreply "URL Replies"
	    cgihits "CGI Hits"
	    maphits "Image Map Hits"
	    errors	"Errors"
	    } {
	label .l$counter -text $label
	label .n$counter -textvariable [CountVarName $counter] -width 0
	grid .l$counter .n$counter -sticky w
	grid configure .n$counter -sticky e
    }
    # Expose webmaster and debug passwords
    foreach {varname label} {
        webmaster_password "webmaster Password"
        DebugPassword     "debug Password"
    } {
	label .l$varname -text $label
	label .n$varname -textvariable $varname -width 0
	grid .l$varname .n$varname -sticky w
	grid configure .n$varname -sticky e
    }
    button .quit -text Quit -command {Httpd_Shutdown ; exit}
    grid .quit -columnspan 2
}

Added modules/httpd/status.tcl.







































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# status.tcl --
#
#	Application-direct URLs to give out status of the server.
# 	Tcl procedures of the form Status/hello implement URLS
#	of the form /status/hello
#
# Brent Welch (c) Copyright 1997 Sun Microsystems, Inc.
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: status.tcl,v 1.29 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::status 1.0

package require httpd	;# Httpd_ReturnData Httpd_ReturnFile
package require httpd::counter	;# Count Counter_StartTime
package require httpd::direct	;# Direct_Url
package require httpd::log	;# Log
package require httpd::subst	;# Subst_ReturnFile
package require httpd::threadmgr	;# Thread_Enabled Thread_Id Thread_IsFree Thread_List Thread_Send Thread_SendAsync
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_Dispatch
package require httpd::utils	;# K file setmax

proc Status_Url {dir {imgdir /images}} {
    global _status
    set _status(dir) $dir
    set _status(images) $imgdir
    Direct_Url $dir Status
}

# Status/hello --
#
#	Show the string "hello".
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns the string "hello".

proc Status/hello {args} {return hello}

# StatusHeader --
#
#       Standard HTML header for status pages.
#
# Arguments:
#       title - also used as <h1>
#
# Results:
#       Html for head and <body>

proc StatusHeader {title} {
    return "<html><head>
    <title>$title</title>
    </head>
    <body bgcolor=white text=black>
    <h1>$title</h1>
"
}

# Status/threads --
#
#	Show the list of threads running in the server.
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns the list of threads running in the server.

proc Status/threads {args} {
    append html [StatusHeader "Thread List"]
    append html [StatusMenu]\n
    if {[catch {Thread_List} x]} {
	append html "No thread support\n"
    } else {
	append html $x
    }
    return $html
}

proc StatusSortForm {action label {pattern *} {sort number}} {
    if {[string compare $sort "number"] == 0} {
	set numcheck checked
	set namecheck ""
    } else {
	set numcheck ""
	set namecheck checked
    }
    append result "<form action=$action>"
    append result "Pattern <input type=text name=pattern value=$pattern><br>"
    append result "Sort by $label <input type=radio name=sort value=number $numcheck> or Name <input type=radio name=sort value=name $namecheck><br>"
    append result "<input type=submit name=submit value=\"Again\">"
    append result "</form>"
}

proc StatusMenu {} {
    global _status
    set sep ""
    set html "<p>\n"
    foreach {url label} [list \
	/		"Home" \
	$_status(dir)/	"Graphical Status" \
	$_status(dir)/text	"Text Status" \
	$_status(dir)/domain	"Domains" \
	$_status(dir)/doc	"Documents" \
	$_status(dir)/notfound	"Not Found" \
	$_status(dir)/threads	"Threads" \
	$_status(dir)/size	"Memory Size" \
    ] {
	append html "$sep<a href=$url>$label</a>\n"
	set sep " | "
    }
    append html "</p>\n"
    return $html
}

# Status/doc --
#
#	Show the number of hits for documents matching the pattern.
#
# Arguments:
#	pattern	(optional) the glob pattern of the URL to report on.
#	sort	(optional) how to sort the output.  If the default "number" is
#		not given, output is sorted by url alphabetically.
#
# Results:
#	Returns HTML code that displays document hit info.

proc Status/doc {{pattern *} {sort number}} {
    global _status
    set result ""
    append result [StatusHeader "Document Hits"]
    append result [StatusMenu]
    append result [StatusSortForm $_status(dir)/doc "Hit Count" $pattern $sort]
    append result [StatusPrintArray [counter::get hit -histVar] * $sort Hits Url]
}

# Status/domain --
#
#	Show the number of hits for documents in different domains.
#
# Arguments:
#	pattern	(optional) the glob pattern of the domain to report on.
#	sort	(optional) how to sort the output.  If the default "number" is
#		not given, output is sorted by url alphabetically.
#
# Results:
#	Returns HTML code that displays document hit info.

proc Status/domain {{pattern *} {sort number}} {
    global _status
    set result ""
    append result [StatusHeader "Domain Hits"]
    append result [StatusMenu]
    append result [StatusSortForm $_status(dir)/domain "Hit Count" $pattern $sort]
    append result [StatusPrintArray [counter::get domainHit -histVar] * $sort Hits Domain]
}

proc StatusPrintArray {aname pattern sort col1 col2} {
    upvar #0 $aname a
    set result ""
    append result <pre>\n
    append result [format "%6s %s\n" $col1 $col2]
    set list {}
    set total 0
    foreach name [lsort [array names a $pattern]] {
	set value $a($name)
	lappend list [list $value $name]
	incr total $value
    }
    if {[string compare $sort "number"] == 0} {
	if {[catch {lsort -index 0 -integer -decreasing $list} newlist]} {
	    set newlist [lsort -command StatusSort $list]
	}
    } else {
	if {[catch {lsort -index 1 -integer -decreasing $list} newlist]} {
	    set newlist [lsort -command StatusSortName $list]
	}
    }
    append result [format "%6d %s\n" $total Total]
    foreach k $newlist {
	set url [lindex $k 1]
	append result [format "%6d %s\n" [lindex $k 0] $url]
    }
    append result </pre>\n
    return $result
}
proc StatusSort {a b} {
    set 1 [lindex $a 0]
    set 2 [lindex $b 0]
    if {$1 == $2} {
	return [string compare $a $b]
    } elseif {$1 < $2} {
	return 1
    } else {
	return -1
    }
}
proc StatusSortName {a b} {
    set 1 [lindex $a 1]
    set 2 [lindex $b 1]
    return [string compare $1 $2]
}

# Status/notfound --
#
#	Show the number of hits for nonexistent documents matching the pattern.
#
# Arguments:
#	pattern	(optional) the glob pattern of the URL to report on.
#	sort	(optional) how to sort the output.  If the default "number" is
#		not given, output is sorted by url alphabetically.
#
# Results:
#	Returns HTML code that displays document hit info for docs that were
#	not found.

proc Status/notfound {{pattern *} {sort number}} {
    global Doc Referer _status
    set result ""
    append result [StatusHeader "Documents Not Found"]
    append result [StatusMenu]
    append result [StatusSortForm $_status(dir)/notfound "Hit Count" $pattern $sort]
    append result [StatusPrintNotFound $pattern $sort]
}

proc StatusPrintNotFound {{pattern *} {sort number}} {
    global Doc Referer _status
    upvar #0 [counter::get notfound -histVar] histogram
    append result <pre>\n
    append result [format "%6s %s\n" Miss Url]
    set list {}
    foreach i [lsort [array names histogram $pattern]] {
	lappend list [list $histogram($i) $i]
    }
    if {[catch {lsort -index 0 -integer -decreasing $list} newlist]} {
	set newlist [lsort -command StatusSort $list]
    }
    foreach k $newlist {
	set url [lindex $k 1]
	append result [format "%6d <a href=%s>%s</a>\n" \
	    [lindex $k 0] [lindex $k 1] [lindex $k 1]]
	if {[info exists Referer($url)]} {
	    set i 0
	    append result <ul>
	    foreach r $Referer($url) {
		append result "<li> <a href=\"$r\">$r</a>\n"
	    }
	    append result </ul>\n
	}
    }
    append result </pre>\n
#    append result "<a href=$_status(dir)/notfound/reset>Reset counters</a>"
    return $result
}

# Status/notfound/reset --
#
#	Reset the number of hits for nonexistent documents to 0.
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns HTML code that confirms that the reset occurred.

proc Status/notfound/reset {args} {
    global Referer
    counter::reset notfound
    catch {unset Referer}
    return [StatusHeader "Reset Notfound Counters"]
}

# Status/size --
#
#	Show both the code size and data size.
#
# Arguments:
#	args	arguments are ignored.
#
# Results:
#	Returns HTML.

proc Status/size {args} {
    global StatusDataSize StatusCodeSize
    append top_html [StatusHeader "Memory Size"]
    append top_html [StatusMenu]\n
    append html [Status/datasize]\n
    append html [Status/codesize]\n
    append top_html "<h2>Grand Total</h3>"
    append top_html "Bytes [expr $StatusDataSize(bytes) + $StatusCodeSize(bytes)]"
    return $top_html$html
}

# Status/datasize --
#
#	Show the data size for the entire server or for a particular namespace.
#
# Arguments:
#	ns	(optional) if given, show the data size for this namespace
#
# Results:
#	Returns HTML.

proc Status/datasize {{ns ::}} {
    global StatusDataSize
    array set StatusDataSize {
	vars	0
	values	0
	bytes	0
    }
    append html [StatusHeader "Data Size"]
    append html [StatusDataSize $ns]
    append top_html "<h2>Total Data Size</h2>\n
	Num Variables $StatusDataSize(vars)<br>\n\
	Num Values $StatusDataSize(values)<br>\n\
	Data Bytes $StatusDataSize(bytes)"
    return $top_html$html
}
proc StatusDataSize {ns} {
    global StatusDataSize
    set ng 0
    set nv 0
    set size 0
    foreach g [info vars ${ns}::*] {
	incr ng
	if {[array exists $g]} {
	    foreach {name value} [array get $g] {
		set size [expr {$size + [string length $name] + [string length $value]}]
		incr nv
	    }
	} elseif {[info exist $g]} {
	    # info vars returns declared but undefined namespace vars
	    set size [expr {$size + [string length $g] + [string length [set $g]]}]
	    incr nv
	}
    }
    set html "<h3>$ns</h3>\n\
		Num Variables $ng<br>\n\
		Num Values $nv<br>\n\
		Data Bytes $size"
    incr StatusDataSize(vars) $ng
    incr StatusDataSize(values) $nv
    incr StatusDataSize(bytes) $size

    append html "<ul>"
    foreach child [namespace children $ns] {
	append html [StatusDataSize $child]
    }
    append html "</ul>"
    return $html
}

# Status/codesize --
#
#	Show the code size for the entire server or for a particular namespace.
#
# Arguments:
#	ns	(optional) if given, show the code size for this namespace
#
# Results:
#	Returns HTML.

proc Status/codesize {{ns ::}} {
    global StatusCodeSize
    array set StatusCodeSize {
	procs	0
	bytes	0
    }
    set html [StatusHeader "Code Size"]
    append html [StatusCodeSize $ns]
    append top_html "<h2>Total Code Size</h2>\n
	Num Procs $StatusCodeSize(procs)<br>\n\
	Code Bytes $StatusCodeSize(bytes)"
    return $top_html$html
}
proc StatusCodeSize {{ns ::}} {
    global StatusCodeSize
    set np 0
    set size 0
    foreach g [info procs ${ns}::*] {
	incr np
	set size [expr {$size + [string length $g] +
			    [string length [info args $g]] +
			    [string length [info body $g]]}]
    }
    set html "<h3>$ns</h3>\n\
		Num Procs $np<br>\n\
		Code Bytes $size"
    incr StatusCodeSize(procs) $np
    incr StatusCodeSize(bytes) $size
    append html "<ul>"
    foreach child [namespace children $ns] {
	append html [StatusCodeSize $child]
    }
    append html "</ul>"
}

# StatusMainTable --
#
#	Display the main status counters. This gathers information
#	from worker threads, if possible.
#
# Arguments
#	None
#
# Results
#	Html

proc StatusMainTable {} {
    global Httpd Doc status tcl_patchLevel tcl_platform Thread
    global StatusThreadTable

    set html "<H1>$Httpd(name):$Httpd(port)</h1>\n"
    append html "<H2>Server Info</h2>"
    append html "<table border=0>"
    append html "<tr><td>Start Time</td><td>[clock format [Counter_StartTime]]</td></tr>\n"
    append html "<tr><td>Current Time</td><td>[clock format [clock seconds]]</td></tr>\n"
    append html "<tr><td>Server</td><td>$Httpd(server)</td></tr>\n"
    append html "<tr><td>Tcl Version</td><td>$tcl_patchLevel</td></tr>"
    switch $tcl_platform(platform) {
	unix {
	    append html "<tr><td colspan=2>[exec uname -a]</td></tr>"
	}
	macintosh -
	windows {
	    append html "<tr><td colspan=2>$tcl_platform(os) $tcl_platform(osVersion)</td></tr>"
	}
    }

    append html </table>

    append html "<br><br><br>\n"

    append html "<p>[StatusTable]<p>\n"

    # Per thread stats
    if {[Thread_Enabled]} {
        set self [Thread_Id]
	foreach id [lsort -integer [Thread_List]] {
	    if {$id == $self} {
		continue
	    }
	    append html "<h4>Thread $id</h4>\n"
	    global counter_thread_$id
	    if {[Thread_IsFree $id]} {
		set StatusThreadTable($id) \
		    [Thread_Send $id StatusTable]
	    } else {
		# Use cached version of the other threads counters,
		# but update our stats for next time.
		append html "<i>busy, using cached values</i>\n"
		Thread_SendAsync $id [list StatusThreadUpdate $id $self]
	    }
	    if {[info exist StatusThreadTable($id)]} {
		append html $StatusThreadTable($id)
	    }
	}
    }
    return $html
}

proc StatusThreadUpdate {self master} {
    Thread_SendAsync $master [list array set ::counter_thread_$self \
	[array get ::counter]]
}

proc StatusTable {} {
    append html "<table bgcolor=#eeeeee>\n"

    set hit 0
    foreach {c label} {
	    / "Home Page Hits"
	    } {
	set N [counter::get hit -hist $c]
	if {$N > 0} {
	    append html "<tr><td>$label</td><td>$N</td>\n"
	    set hit 1
	    append html </tr>\n
	}
    }
    foreach {c label} {
	    urlhits "URL Requests"
	    Url_Dispatch "URL Dispatch"
	    UrlToThread "Thread Dispatch"
	    UrlEval "Direct Dispatch"
	    UrlCacheHit "UrlCache eval"
	    urlreply "URL Replies"
	    accepts "Total Connections"
	    accept_https "HTTPS Connections"
	    keepalive "KeepAlive Requests"
	    http1.0 "OneShot Connections"
	    http1.1 "Http1.1 Connections"
	    threads "Worker Threads"
	    sockets "Open Sockets"
	    cgihits "CGI Hits"
	    tclhits "Tcl Safe-CGIO Hits"
	    maphits "Image Map Hits"
	    cancel	"Timeouts"
	    notfound	"Not Found"
	    errors	"Errors"
	    Status	"Status"
	    } {
	if {[counter::exists $c]} {
	    set t [counter::get $c -total]
	    if {$t > 0} {
		append html "<tr><td>$label</td><td>$t</td>\n"
		set hit 1
		set resetDate [counter::get $c -resetDate]
		if {[string length $resetDate]} {
		    append html "<td>[clock format $resetDate -format "%B %d, %Y"]</td>"
		}
		append html </tr>\n
	    }
	}
    }
    if {!$hit} {
	foreach c [counter::get "" -allTagNames] {
	    append html "<tr><td>$name</td><td>[counter::get $c -total]</td>\n"
	    set resetDate [counter::get $c -resetDate]
	    if {[string length $resetDate]} {
		append html "<td>[clock format $resetDate -format "%B %d, %Y"]</td>"
	    }
	    append html </tr>\n
	}
    }
    append html </table>\n

    return $html
}

proc StatusTclPower {{align left}} {
    global _status
    set html "<img src=$_status(images)/pwrdLogo150.gif align=$align width=97 height=150>\n"
}

# Status/all --
#
#	Show the page hist per minute, hour, and day using images.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status/all {args} {
    global _status page
    set html [StatusHeader "Tcl HTTPD Status"]
    append html [StatusMenu]
    append html [StatusTclPower left]
    append html [StatusMainTable]
    append html "<br><a href=/status/text>Text only view.</a>\n"

    append html "<p>\n<table border=0 cellpadding=0 cellspacing=0>\n"
    append html [counter::histHtmlDisplayRow serviceTime \
	    -title "Service Time" -unit seconds \
	    -width 1 -skip 10 -min 0 -max 400 \
	    -images $_status(images)]

    append html [counter::histHtmlDisplayRow urlhits \
	    -title "Url Hits" -unit minutes \
	    -min 0 -max 60 \
	    -images $_status(images)]
    append html [counter::histHtmlDisplayRow urlhits \
	    -title "Url Hits" -unit hours \
	    -min 0 -max 24 \
	    -images $_status(images)]
    append html [counter::histHtmlDisplayRow urlhits \
	    -title "Url Hits" -unit days \
	    -images $_status(images)]
    
    append html </table>
    return $html
}

# Status/text --
#
#	Show the page hist per minute, hour, and day in text format.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status/text {args} {
    global _status
    set html [StatusHeader "Tcl HTTPD Status"]
    append html [StatusMenu]
    append html [StatusTclPower left]
    append html [StatusMainTable]
    append html "<p><a href=$_status(dir)/all>Bar Chart View.</a>"
    catch {
	append html [counter::histHtmlDisplay serviceTime \
		-title "Service Time" -unit seconds -max 100 -text 1]
    }
    catch {
	append html [counter::histHtmlDisplay urlhits \
		-title "Per Minute Url Hits" -unit minutes -text 1]
	append html [counter::histHtmlDisplay urlhits \
		-title "Hourly Url Hits" -unit hours -text 1]
	append html [counter::histHtmlDisplay urlhits \
		-title "Daily Url Hits" -unit days -text 1]
    }
    return $html
}

# Status/ --
#
#	Same as Status/all.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status/ {args} {
  Status/all {*}$args
}

# Status --
#
#	Same as Status/all.
#
# Arguments:
#	args	arguments are ignored
#
# Results:
#	Returns HTML.

proc Status {args} {
  Status/all {*}$args
}

proc Version {} {
    global tcl_patchLevel Httpd
    append html "$Httpd(server)"
    append html "<br>Tcl version $tcl_patchLevel"
    return $html
}

# NOTUSED

proc StatusTimeText {array title unit what time} {
    global counter
    upvar #0 $array data
    regsub ^Cnt $array Age agebitName
    upvar #0 $agebitName agebit
    set total 0
    set max 0
    set base 100
    foreach {name value} [array get data] {
	setmax max $value
    }
    switch $unit {
	Min	{set delta 60 ; set fmt %R}
	Hour	{set delta 3600 ; set fmt "%h %e %R"}
	Day	{set delta 86400 ; set fmt %D}
    }

    append result "<h3>$title ($max max)</h3>"
    append result <ul>
    append result "<h4>Starting at [clock format $time]</h4>"
    append result "<table cellpadding=2 cellspacing=2 border><tr>\n"
    append result "<tr><th>$unit</th><th>$what</th></tr>"
    foreach t [lsort -integer [array names data]] {
	set value $data($t)

	# Minutes time we infer from the starting time and the agebits,
	# which indicate minute buckets for the previous hour.

	if {[info exists agebit($t)]} {
	    set tt [expr $time - 3600]
	} else {
	    set tt $time
	}

	# Hours have their own base time in counter(hour,$hour)

	if {$unit == "Hour"} {
	    set tt $counter(hour,$t)
	}

	# Wrap separator

	if {[info exists lasttime] && ($lasttime > $tt)} {
	    append result "<tr><td><hr></td><td><hr></td></tr>"
	}
	set lasttime $tt
	append result "<tr><td>[clock format $tt -format $fmt]</td><td>$value</td></tr>"
	incr time $delta
    }
    append result "</table>"
    append result </ul>
    return $result
}

# Handle .stat templates. (NOTUSED)
# First process the incoming form data in an Status-specific way,
# then do a normal Subst into a safe interpreter
#   path:	The path name of the document
#   suffix:     The file suffix
#   sock:	The name of the socket, and a handle for the socket state

# It turns out this is not used, but you could use it as a template
# for your own application's template processor.

proc Doc_application/x-tcl-status {path suffix sock} {
    global status
    upvar #0 Httpd$sock data

    append data(query) ""
    set queryList [Url_DecodeQuery $data(query)]

    # Put the query data into an array.
    # If a key appears multiple times, the resultant array value will
    # be a list of all the values.

    foreach {name value} $queryList {
    	lappend query($name) $value
    }

    if {![info exists status(session)]} {
	set status(session) [session_create Status]
    }

    # Process the query data from the previous page.

    if {[catch {StatusProcess $session $queryList} result]} {
	Httpd_ReturnData $sock text/html $result
	return
    } 

    # Expand the page in the correct session interpreter, or treat
    # the page as ordinary html if the session has ended.

    if {$result} {
	Subst_ReturnFile $sock $path interp$session
    } else {
	Httpd_ReturnFile $sock text/html $path
    }
}

if {0} {
    proc StatusPrintHits {aname {pattern *} {sort number}} {
	append result [StatusPrintArray [counter::get hit -histVar] *\
		$sort Hits Url]
    }
}

Added modules/httpd/stdin.tcl.





























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# stdin.tcl
#
# (c) 1997 Sun Microsystems Laboratories (Stephen Uhler)
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: stdin.tcl,v 1.5 2004/10/22 03:43:06 coldstore Exp $

# The following is an event-driven command loop for testing with tclsh
# with command history:
#	!<pattern> run 1st command matching pattern
#	!<pattern>/xxx/yyy/ as above, but substitute yyy for xxx
# Nb: history doesn't work, too many changes to the tcl api to track.

package provide httpd::stdin 1.1

package require httpd::log	;# Log Log_Flush
#package require httpd::utils	;# file

set Stdin(maxHistory) 100
append Stdin(history) {}
proc StdinRead {prompt} {
    global Stdin
    if {[eof stdin]} {
	set Stdin(Wait) 1
	fileevent stdin readable {}
	return
    }
    append Stdin(command) [gets stdin]
    if {[info complete $Stdin(command)]} {
	set s1 ""; set s2 ""
	if {[regexp {^!([^/]+)(/([^/]+)/([^/]*))?} $Stdin(command) \
		    {} history {} s1 s2]} {
	    set match [lsearch -regexp $Stdin(history) "^ *$history"]
	    if {$match >= 0} {
	    	set Stdin(command) [lindex $Stdin(history) $match]
		if {$s1 != ""} {
		    catch {regsub -- $s1 $Stdin(command) $s2 Stdin(command)}
		}
		puts stderr $Stdin(command)
	    } else {
	    	puts -nonewline "No \"$history\" in history list\n$prompt"
		set Stdin(command) ""
		flush stdout
		return
	    }
	}
	if {$Stdin(command) != "" && \
		$Stdin(command) != [lindex $Stdin(history) 0]} {
	    set Stdin(history) [lrange "[list $Stdin(command)] \
		    $Stdin(history)" 0 $Stdin(maxHistory)]
	}
        catch {uplevel #0  $Stdin(command)} result
        puts -nonewline "$result\n$prompt"
        flush stdout
        set Stdin(command) ""
    } else {
    	append Stdin(command) \n
    }
}

proc Stdin_Start {{prompt "% "}} {
    global Stdin
    set Stdin(command) ""
    puts -nonewline $prompt
    flush stdout
    fileevent stdin readable [list StdinRead $prompt]
    vwait Stdin(wait)
}

if {[info procs bgerror] == ""} {
    proc bgerror {args} {
	global errorInfo
	Log {} bgerror $errorInfo ; Log_Flush
	puts stderr $errorInfo
    }
}					

Added modules/httpd/subst.tcl.































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# subst.tcl
#@c Subst support
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: subst.tcl,v 1.10 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::subst 1.0

package require httpd	;# Httpd_RequestAuth Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv
package require httpd::session	;# Session_Authorized
#package require httpd::utils	;# file

# Subst_ReturnFile --
#
# Subst a file and return the result to the HTTP client.
# Note that ReturnData has no Modification-Date so the result is not cached.
#
# Arguments:
#	sock	The socket connection.
#	path	The template file pathname.
#	interp 	The Tcl intepreter in which to subst.
#
# Results:
#	None
#
# Side Effects:
#	Returns a page to the client.

proc Subst_ReturnFile {sock path {interp {}}} {
    Httpd_ReturnData $sock text/html [Subst_File $path $interp]
}

# SubstCleanScope --
#
# Substitute the data in this clean (no vars set) scope.
#
# Arguments:
#	_html_data	The data to substitute.
#
# Results:
#	The subst'ed data.
#
# Side Effects:
#	None

proc SubstCleanScope {_html_data} {
    return [subst $_html_data]
}

# Subst_Scope --
#
# When processing templates in the current interpreter, decide whether to
# use the global or local scope (that of DocSubst) to process templates.
#
# Arguments:
#	scope	0 means global and non-zero means local.
#
# Results:
#	None
#
# Side Effects:
#	Sets the scope for all Doc domain substs.

proc Subst_Scope {scope} {
    global Subst
    set Subst(templateScope) $scope
}
if {![info exists Subst(templateScope)]} {
    set Subst(templateScope) 0
}

# SubstFile --
#
# Subst a file in an interpreter context.  If no interp is given, use the
# current interp.  If using the current interp, use the scope
# variable to decide whether to use the global or current scope.
#
# Arguments:
#	path	The file pathname of the template.
#	interp  The interpreter in which to subst.
#
# Results:
#	The subst'ed page.
#
# Side Effects:
#	None

proc SubstFile {path {interp {}}} {
    global Subst

    set in [open $path]
    set script [read $in]
    close $in

    if {[string length $interp] == 0} {
        # Substitution occurs in the current interp.
        if {$Subst(templateScope) == 0} {
            # Substitution occurs at the global level.
            set result [uplevel #0 [list subst $script]]
        } else {
            # Substitution occurs at a clean level, one-off from global.
            set result [uplevel [list SubstCleanScope $script]]
        }
    } else {
        # Substitution occurs in the given interp.
        set result [interp eval $interp [list subst $script]]
    }

    # Perform the post-processing of the output, as installed via Subst_Install.
    foreach hook $Subst(substHooks) {
        set result [$hook $result]
    }
    return $result
}

# Subst_File --
#
# Subst a file or directory in an interpreter context.
# As SubstFile except that a path which is a directory is evaluated
# by evaluating a file $path/index.tml, and returning that as the substituted
# value of the $path directory.
#
proc Subst_File {path {interp {}}} {
    global Subst

    switch [file type $path] {
	file {
	    return [uplevel 1 [list SubstFile $path $interp]]
	}
	link {
	    set link [file readlink $path]
	    if {[file pathtype $link] == "relative"} {
		set link [file join [file dirname $path] $link]
	    }
	    return [uplevel 1 [list Subst_File $link $interp]]
	}
	directory {
	    return [uplevel 1 [list SubstFile [file join $path index.tml] $interp]]
	}
	default {
	    error "Can't process [file type $path] files."
	}
    }
}

# Subst_Install
#
#	Install a subst hook.  Each installed hook will be performed over the
#	substituted template.
#
# Arguments
#	proc	This is a command prefix that is invoked with one additional
#		arguments to process:
#			text	The text to process.
#		The subst hook returns the HTML that will be returned by the server.
#
# Results:
#	None
#
# Side Effects
#	Save the subst hook.

proc Subst_Install {proc} {
    global Subst
    if {[lsearch $Subst(substHooks) $proc] < 0} {
	lappend Subst(substHooks) $proc
    }
    return
}

if {![info exist Subst(substHooks)]} {
    set Subst(substHooks) {}
}

# Doc_application/x-tcl-auth --
#
# Like tcl-subst, but a basic authentication cookie is used for session state
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Returns a page to the client.

proc Doc_application/x-tcl-auth {path suffix sock} {
    upvar #0 Httpd$sock data

    if {![info exists data(session)]} {
	Httpd_RequestAuth $sock Basic "Random Password"
	return
    }
    set interp [Session_Authorized $data(session)]

    # Need to make everything look like a GET so the Cgi parser
    # doesn't read post data from stdin.  We've already read it.

    set data(proto) GET

    Doc_application/x-tcl-subst $path $suffix $sock
}

# Doc_application/x-tcl-subst --
#
# Tcl-subst a template that mixes HTML and Tcl.
# This subst is just done in the context of the specified
# interpreter with not much other support.
# See x-tcl-template for something more sophisticated
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#	interp	The interp to use for subst'ing.
#
# Results:
#	None
#
# Side Effects:
#	Sets the env array in interp and calls Subst_ReturnFile.

proc Doc_application/x-tcl-subst {path suffix sock {interp {}}} {
    upvar #0 Httpd$sock data

    Cgi_SetEnv	$sock $path pass
    interp eval $interp [list uplevel #0 [list array set env [array get pass]]]
    Subst_ReturnFile $sock $path $interp
}

Added modules/httpd/tclcrypt.tcl.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# tclcrypt.tcl
#
# Unix crypt in pure tcl
# From http://mini.net/tcl/crypt by Michael A. Cleverly (23/Nov/2000)
#
# Used as a fallback for installations without libcrypt.so compiled.
# It's always better to have the compiled C version available, of course
# This package provides two implementations of crypt, and will choose
# the fastest possible depending upon Tcl version

package provide tclcrypt 1.0

proc crypt {password salt} {

    array set IP {
	0 58  1 50  2 42  3 34  4 26  5 18  6 10  7 2
	8 60  9 52 10 44 11 36 12 28 13 20 14 12 15 4
	16 62 17 54 18 46 19 38 20 30 21 22 22 14 23 6
	24 64 25 56 26 48 27 40 28 32 29 24 30 16 31 8
	32 57 33 49 34 41 35 33 36 25 37 17 38  9 39 1
	40 59 41 51 42 43 43 35 44 27 45 19 46 11 47 3
	48 61 49 53 50 45 51 37 52 29 53 21 54 13 55 5
	56 63 57 55 58 47 59 39 60 31 61 23 62 15 63 7}
    
    array set FP {
	0 40  1 8  2 48  3 16  4 56  5 24  6 64  7 32
	8 39  9 7 10 47 11 15 12 55 13 23 14 63 15 31
	16 38 17 6 18 46 19 14 20 54 21 22 22 62 23 30
	24 37 25 5 26 45 27 13 28 53 29 21 30 61 31 29
	32 36 33 4 34 44 35 12 36 52 37 20 38 60 39 28
	40 35 41 3 42 43 43 11 44 51 45 19 46 59 47 27
	48 34 49 2 50 42 51 10 52 50 53 18 54 58 55 26
	56 33 57 1 58 41 59  9 60 49 61 17 62 57 63 25}
    
    array set PC1_C {
	0 57  1 49  2 41  3 33  4 25  5 17  6  9
	7  1  8 58  9 50 10 42 11 34 12 26 13 18
	14 10 15  2 16 59 17 51 18 43 19 35 20 27
	21 19 22 11 23  3 24 60 25 52 26 44 27 36}
    
    array set PC1_D {
	0 63  1 55  2 47  3 39  4 31  5 23  6 15
	7  7  8 62  9 54 10 46 11 38 12 30 13 22
	14 14 15  6 16 61 17 53 18 45 19 37 20 29
	21 21 22 13 23  5 24 28 25 20 26 12 27  4}
    array set shifts {
	0 1 1 1  2 2  3 2  4 2  5 2  6 2  7 2
	8 1 9 2 10 2 11 2 12 2 13 2 14 2 15 1}
    
    array set PC2_C {
	0 14  1 17  2 11  3 24  4  1  5  5
	6  3  7 28  8 15  9  6 10 21 11 10
	12 23 13 19 14 12 15  4 16 26 17  8
	18 16 19  7 20 27 21 20 22 13 23  2}
    
    array set PC2_D {
	0 41  1 52  2 31  3 37  4 47  5 55
	6 30  7 40  8 51  9 45 10 33 11 48
	12 44 13 49 14 39 15 56 16 34 17 53
	18 46 19 42 20 50 21 36 22 29 23 32}
    
    array set e {
	0 32  1  1  2  2  3  3  4  4  5  5
	6  4  7  5  8  6  9  7 10  8 11  9
	12  8 13  9 14 10 15 11 16 12 17 13
	18 12 19 13 20 14 21 15 22 16 23 17
	24 16 25 17 26 18 27 19 28 20 29 21
	30 20 31 21 32 22 33 23 34 24 35 25
	36 24 37 25 38 26 39 27 40 28 41 29
	42 28 43 29 44 30 45 31 46 32 47  1}
    
    array set S {
        0,0  14 0,1   4 0,2  13 0,3   1 0,4   2 0,5  15 0,6  11 0,7   8
        0,8   3 0,9  10 0,10  6 0,11 12 0,12  5 0,13  9 0,14  0 0,15  7
        0,16  0 0,17 15 0,18  7 0,19  4 0,20 14 0,21  2 0,22 13 0,23  1
        0,24 10 0,25  6 0,26 12 0,27 11 0,28  9 0,29  5 0,30  3 0,31  8
        0,32  4 0,33  1 0,34 14 0,35  8 0,36 13 0,37  6 0,38  2 0,39 11
        0,40 15 0,41 12 0,42  9 0,43  7 0,44  3 0,45 10 0,46  5 0,47  0
        0,48 15 0,49 12 0,50  8 0,51  2 0,52  4 0,53  9 0,54  1 0,55  7
        0,56  5 0,57 11 0,58  3 0,59 14 0,60 10 0,61  0 0,62  6 0,63 13
        1,0  15 1,1   1 1,2   8 1,3  14  1,4  6 1,5  11 1,6   3 1,7   4
        1,8   9 1,9   7 1,10  2 1,11 13 1,12 12 1,13  0 1,14  5 1,15 10
        1,16  3 1,17 13 1,18  4 1,19  7 1,20 15 1,21  2 1,22  8 1,23 14
        1,24 12 1,25  0 1,26  1 1,27 10 1,28  6 1,29  9 1,30 11 1,31  5
        1,32  0 1,33 14 1,34  7 1,35 11 1,36 10 1,37  4 1,38 13 1,39  1
        1,40  5 1,41  8 1,42 12 1,43  6 1,44  9 1,45  3 1,46  2 1,47 15
        1,48 13 1,49  8 1,50 10 1,51  1 1,52  3 1,53 15 1,54  4 1,55  2
        1,56 11 1,57  6 1,58  7 1,59 12 1,60  0 1,61  5 1,62 14 1,63  9
	
        2,0  10 2,1   0 2,2   9 2,3  14 2,4   6  2,5  3 2,6  15 2,7   5
        2,8   1 2,9  13 2,10 12 2,11  7 2,12 11 2,13  4 2,14  2 2,15  8
        2,16 13 2,17  7 2,18  0 2,19  9 2,20  3 2,21  4 2,22  6 2,23 10
        2,24  2 2,25  8 2,26  5 2,27 14 2,28 12 2,29 11 2,30 15 2,31  1
        2,32 13 2,33  6 2,34  4 2,35  9 2,36  8 2,37 15 2,38  3 2,39  0
        2,40 11 2,41  1 2,42  2 2,43 12 2,44  5 2,45 10 2,46 14 2,47  7
        2,48  1 2,49 10 2,50 13 2,51  0 2,52  6 2,53  9 2,54  8 2,55  7
        2,56  4 2,57 15 2,58 14 2,59  3 2,60 11 2,61  5 2,62  2 2,63 12
	
        3,0   7 3,1  13 3,2  14 3,3   3  3,4  0  3,5  6 3,6   9 3,7  10
        3,8   1 3,9   2 3,10  8 3,11  5 3,12 11 3,13 12 3,14  4 3,15 15
        3,16 13 3,17  8 3,18 11 3,19  5 3,20  6 3,21 15 3,22  0 3,23  3
        3,24  4 3,25  7 3,26  2 3,27 12 3,28  1 3,29 10 3,30 14 3,31  9
        3,32 10 3,33  6 3,34  9 3,35  0 3,36 12 3,37 11 3,38  7 3,39 13
        3,40 15 3,41  1 3,42  3 3,43 14 3,44  5 3,45  2 3,46  8 3,47  4
        3,48  3 3,49 15 3,50  0 3,51  6 3,52 10 3,53  1 3,54 13 3,55  8
        3,56  9 3,57  4 3,58  5 3,59 11 3,60 12 3,61  7 3,62  2 3,63 14
	
        4,0   2 4,1  12 4,2   4 4,3   1 4,4   7 4,5  10 4,6  11 4,7   6
        4,8   8 4,9   5 4,10  3 4,11 15 4,12 13 4,13  0 4,14 14 4,15  9
        4,16 14 4,17 11 4,18  2 4,19 12 4,20  4 4,21  7 4,22 13 4,23  1
        4,24  5 4,25  0 4,26 15 4,27 10 4,28  3 4,29  9 4,30  8 4,31  6
        4,32  4 4,33  2 4,34  1 4,35 11 4,36 10 4,37 13 4,38  7 4,39  8
        4,40 15 4,41  9 4,42 12 4,43  5 4,44  6 4,45  3 4,46  0 4,47 14
        4,48 11 4,49  8 4,50 12 4,51  7 4,52  1 4,53 14 4,54  2 4,55 13
        4,56  6 4,57 15 4,58  0 4,59  9 4,60 10 4,61  4 4,62  5 4,63  3
	
        5,0  12 5,1   1 5,2  10 5,3  15 5,4   9 5,5   2 5,6   6 5,7   8
        5,8   0 5,9  13 5,10  3 5,11  4 5,12 14 5,13  7 5,14  5 5,15 11
        5,16 10 5,17 15 5,18  4 5,19  2 5,20  7 5,21 12 5,22  9 5,23  5
        5,24  6 5,25  1 5,26 13 5,27 14 5,28  0 5,29 11 5,30  3 5,31  8
        5,32  9 5,33 14 5,34 15 5,35  5 5,36  2 5,37  8 5,38 12 5,39  3
        5,40  7 5,41  0 5,42  4 5,43 10 5,44  1 5,45 13 5,46 11 5,47  6
        5,48  4 5,49  3 5,50  2 5,51 12 5,52  9 5,53  5 5,54 15 5,55 10
        5,56 11 5,57 14 5,58  1 5,59  7 5,60  6 5,61  0 5,62  8 5,63 13
	
        6,0   4 6,1  11 6,2   2 6,3  14 6,4  15 6,5   0 6,6   8 6,7  13
        6,8   3 6,9  12 6,10  9 6,11  7 6,12  5 6,13 10 6,14  6 6,15  1
        6,16 13 6,17  0 6,18 11 6,19  7 6,20  4 6,21  9 6,22  1 6,23 10
        6,24 14 6,25  3 6,26  5 6,27 12 6,28  2 6,29 15 6,30  8 6,31  6
        6,32  1 6,33  4 6,34 11 6,35 13 6,36 12 6,37  3 6,38  7 6,39 14
        6,40 10 6,41 15 6,42  6 6,43  8 6,44  0 6,45  5 6,46  9 6,47  2
        6,48  6 6,49 11 6,50 13 6,51  8 6,52  1 6,53  4 6,54 10 6,55  7
        6,56  9 6,57  5 6,58  0 6,59 15 6,60 14 6,61  2 6,62  3 6,63 12
	
        7,0  13 7,1   2 7,2   8 7,3   4 7,4   6 7,5  15 7,6  11 7,7   1
        7,8  10 7,9   9 7,10  3 7,11 14 7,12  5 7,13  0 7,14 12 7,15  7
        7,16  1 7,17 15 7,18 13 7,19  8 7,20 10 7,21  3 7,22  7 7,23  4
        7,24 12 7,25  5 7,26  6 7,27 11 7,28  0 7,29 14 7,30  9 7,31  2
        7,32  7 7,33 11 7,34  4 7,35  1 7,36  9 7,37 12 7,38 14 7,39  2
        7,40  0 7,41  6 7,42 10 7,43 13 7,44 15 7,45  3 7,46  5 7,47  8
        7,48  2 7,49  1 7,50 14 7,51  7 7,52  4 7,53 10 7,54  8 7,55 13
        7,56 15 7,57 12 7,58  9 7,59  0 7,60  3 7,61  5 7,62  6 7,63 11}
    
    array set P {
	0 16  1  7  2 20  3 21
	4 29  5 12  6 28  7 17
	8  1  9 15 10 23 11 26
	12  5 13 18 14 31 15 10
	16  2 17  8 18 24 19 14
	20 32 21 27 22  3 23  9
	24 19 25 13 26 30 27  6
	28 22 29 11 30  4 31 25}
    
    for {set i 0} {$i < 66} {incr i} {
        set block($i) 0
    }
    
    set pw [split $password ""]
    set pw_pos 0
    for {set i 0} \
	{[scan [lindex $pw $pw_pos] %c c] != -1 && $i < 64} \
	{incr pw_pos} {
	    for {set j 0} {$j < 7} {incr j ; incr i} {
		set block($i) [expr {($c >> (6 - $j)) & 01}]
	    }
	    incr i
	}

    for {set i 0} {$i < 28} {incr i} {
        set C($i) $block([expr {$PC1_C($i) - 1}])
        set D($i) $block([expr {$PC1_D($i) - 1}])
    }

    for {set i 0} {$i < 16} {incr i} {
        for {set k 0} {$k < $shifts($i)} {incr k} {
            set t $C(0)
            for {set j 0} {$j < 27} {incr j} {
                set C($j) $C([expr {$j + 1}])
            }
            set C(27) $t
            set t $D(0)
            for {set j 0} {$j < 27} {incr j} {
                set D($j) $D([expr {$j + 1}])
            }
            set D(27) $t
        }
	
        for {set j 0} {$j < 24} {incr j} {
            set KS($i,$j) $C([expr {$PC2_C($j) - 1}])
            set KS($i,[expr {$j + 24}]) $D([expr {$PC2_D($j) - 28 - 1}])
        }
    }
    
    for {set i 0} {$i < 48} {incr i} {
        set E($i) $e($i)
    }
    
    for {set i 0} {$i < 66} {incr i} {
        set block($i) 0
    }
    
    set salt [split $salt ""]
    set salt_pos 0
    set val_Z 90
    set val_9 57
    set val_period 46
    for {set i 0} {$i < 2} {incr i} {
        scan [lindex $salt $salt_pos] %c c
        incr salt_pos
        set iobuf($i) $c
        if {$c > $val_Z} {
            incr c -6
        }
        if {$c > $val_9} {
            incr c -7
        }
        incr c -$val_period
        for {set j 0} {$j < 6} {incr j} {
            if {[expr {($c >> $j) & 01}]} {
                set temp $E([expr {6 * $i + $j}])
                set E([expr {6 * $i + $j}]) $E([expr {6 * $i + $j + 24}])
                set E([expr {6 * $i + $j + 24}]) $temp
            }
        }
    }
    
    set edflag 0
    for {set h 0} {$h < 25} {incr h} {
        for {set j 0} {$j < 64} {incr j} {
            set L($j) $block([expr {$IP($j) - 1}])
        }
	
        for {set ii 0} {$ii < 16} {incr ii} {
            if {$edflag} {
                set i [expr {15 - $ii}]
            } else {
                set i $ii
            }
	    
            for {set j 0} {$j < 32} {incr j} {
                set tempL($j) $L([expr {$j + 32}])
            }
	    
            for {set j 0} {$j < 48} {incr j} {
                set preS($j) [expr {$L([expr {$E($j) - 1 + 32}]) ^ $KS($i,$j)}]
            }

            for {set j 0} {$j < 8} {incr j} {
	set t [expr {6 * $j}]
	set k $S($j, [expr {
			    ($preS($t) << 5) + 
			    ($preS([expr {$t + 1}]) << 3) + 
			    ($preS([expr {$t + 2}]) << 2) + 
			    ($preS([expr {$t + 3}]) << 1) + 
			    $preS([expr {$t + 4}])       + 
			    ($preS([expr {$t + 5}]) << 4)
			}])

                set t [expr {4 * $j}]
                set f($t) [expr {($k >> 3) & 01}]
                set f([expr {$t + 1}]) [expr {($k >> 2) & 01}]
                set f([expr {$t + 2}]) [expr {($k >> 1) & 01}]
                set f([expr {$t + 3}]) [expr { $k       & 01}]
            }

            for {set j 0} {$j < 32} {incr j} {
                set L([expr {$j + 32}]) [expr {$L($j) ^ $f([expr {$P($j) - 1}])}]
            }

            for {set j 0} {$j < 32} {incr j} {
                set L($j) $tempL($j)
            }
        }

        for {set j 0} {$j < 32} {incr j} {
            set t $L($j)
            set L($j) $L([expr {$j + 32}])
            set L([expr {$j + 32}]) $t
        }

        for {set j 0} {$j < 64} {incr j} {
            set block($j) $L([expr {$FP($j) - 1}])
        }
    }

    for {set i 0} {$i < 11} {incr i} {
        set c 0
        for {set j 0} {$j < 6} {incr j} {
            set c [expr {$c << 1}]
            set c [expr {$c | $block([expr {6 * $i + $j}])}]
        }
        incr c $val_period
        if {$c > $val_9} {
            incr c 7
        }
        if {$c > $val_Z} {
            incr c 6
        }
        set iobuf([expr {$i + 2}]) $c
    }
    
    if {$iobuf(1) == 0} {
        set iobuf(1) $iobuf(0)
    }
    
    set elements [lsort -integer [array names iobuf]]
    set encrypted ""
    
    foreach element $elements {
        append encrypted [format %c $iobuf($element)]
    }
    
    return $encrypted
}

if {[package present Tcl] < 8.4} {
    # we must use the slower non lset version
    return
}

#This version uses the [lset] command introduced in Tcl 8.4.
#It seems to result in a 40-45% improvement in speed over the original version which uses [array]s.

proc crypt {password salt} {
    set IP {58 50 42 34 26 18 10  2 60 52 44 36 28 20 12  4 62 54 46 38 30
	22 14  6 64 56 48 40 32 24 16  8 57 49 41 33 25 17  9  1 59 51
	43 35 27 19 11  3 61 53 45 37 29 21 13  5 63 55 47 39 31 23 15 7}

    set FP {40  8 48 16 56 24 64 32 39  7 47 15 55 23 63 31 38  6 46 14 54
	22 62 30 37  5 45 13 53 21 61 29 36  4 44 12 52 20 60 28 35  3
	43 11 51 19 59 27 34  2 42 10 50 18 58 26 33  1 41  9 49 17 57 25}
    
    set PC1_C {57 49 41 33 25 17  9  1 58 50 42 34 26 18 10  2 59 51 43 35 27
	19 11  3 60 52 44 36}
    
    set PC1_D {63 55 47 39 31 23 15  7 62 54 46 38 30 22 14  6 61 53 45 37 29
	21 13  5 28 20 12  4}
    
    set shifts {1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1}
    
    set PC2_C {14 17 11 24 1 5 3 28 15 6 21 10 23 19 12 4 26 8 16 7 27 20 13 2}
    
    set PC2_D {41 52 31 37 47 55 30 40 51 45 33 48 44 49 39 56 34 53 46 42 50
	36 29 32}
    
    set e {32  1  2  3  4  5  4  5  6  7  8  9  8  9 10 11 12 13 12 13 14 15
	16 17 16 17 18 19 20 21 20 21 22 23 24 25 24 25 26 27 28 29 28 29
	30 31 32 1}
    
    set S {{14  4 13  1  2 15 11  8  3 10  6 12  5  9  0  7  0 15  7  4 14  2
	13  1 10  6 12 11  9  5  3  8  4  1 14  8 13  6  2 11 15 12  9  7
	3 10  5  0 15 12  8  2  4  9  1  7  5 11  3 14 10  0  6 13}
	
	{15  1  8 14  6 11  3  4  9  7  2 13 12  0  5 10  3 13  4  7 15  2
	    8 14 12  0  1 10  6  9 11  5  0 14  7 11 10  4 13  1  5  8 12  6
	    9  3  2 15 13  8 10  1  3 15  4  2 11  6  7 12  0  5 14 9}
	
	{10  0  9 14  6  3 15  5  1 13 12  7 11  4  2  8 13  7  0  9  3  4
	    6 10  2  8  5 14 12 11 15  1 13  6  4  9  8 15  3  0 11  1  2 12
	    5 10 14  7  1 10 13  0  6  9  8  7  4 15 14  3 11  5  2 12}
	
	{ 7 13 14  3  0  6  9 10  1  2  8  5 11 12  4 15 13  8 11  5  6 15
	    0  3  4  7  2 12  1 10 14  9 10  6  9  0 12 11  7 13 15  1  3 14
	    5  2  8  4  3 15  0  6 10  1 13  8  9  4  5 11 12  7  2 14}
	
	{ 2 12  4  1  7 10 11  6  8  5  3 15 13  0 14  9 14 11  2 12  4  7
	    13  1  5  0 15 10  3  9  8  6  4  2  1 11 10 13  7  8 15  9 12  5
	    6  3  0 14 11  8 12  7  1 14  2 13  6 15  0  9 10  4  5  3}
	
	{12  1 10 15  9  2  6  8  0 13  3  4 14  7  5 11 10 15  4  2  7 12
	    9  5  6  1 13 14  0 11  3  8  9 14 15  5  2  8 12  3  7  0  4 10
	    1 13 11  6  4  3  2 12  9  5 15 10 11 14  1  7  6  0  8 13}
	
	{ 4 11  2 14 15  0  8 13  3 12  9  7  5 10  6  1 13  0 11  7  4  9
	    1 10 14  3  5 12  2 15  8  6  1  4 11 13 12  3  7 14 10 15  6  8
	    0  5  9  2  6 11 13  8  1  4 10  7  9  5  0 15 14  2  3 12}
	
	{13  2  8  4  6 15 11  1 10  9  3 14  5  0 12  7  1 15 13  8 10  3
	    7  4 12  5  6 11  0 14  9  2  7 11  4  1  9 12 14  2  0  6 10 13
	    15  3  5  8  2  1 14  7  4 10  8 13 15 12  9  0  3  5  6 11}}
    
    set P {16  7 20 21 29 12 28 17  1 15 23 26  5 18 31 10  2  8 24 14 32 27
	3  9 19 13 30  6 22 11  4 25}
    
    set block {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	0 0 0 0 0 0}
    
    set KS {{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
	{0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
	    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}}
    
    set iobuf {0 0 0 0 0 0 0 0 0 0 0 0 0}
    set f {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
    
    set pw [split $password ""]
    set pw_pos 0
    for {set i 0} {[scan [lindex $pw $pw_pos] %c c] != -1 && $i < 64} \
	{incr pw_pos} {
	    
	    for {set j 0} {$j < 7} {incr j ; incr i} {
		lset block $i [expr {($c >> (6 - $j)) & 01}]
	    }
	    incr i
	    
	}
    
    set C [list]
    set D [list]
    for {set i 0} {$i < 28} {incr i} {
	lappend C [lindex $block [expr {[lindex $PC1_C $i] - 1}]]
	lappend D [lindex $block [expr {[lindex $PC1_D $i] - 1}]]
    }
    
    for {set i 0} {$i < 16} {incr i} {
	for {set k 0} {$k < [lindex $shifts $i]} {incr k} {
	    set t [lindex $C 0]
	    for {set j 0} {$j < 27} {incr j} {
		lset C $j [lindex $C [expr {$j + 1}]]
	    }

	    lset C 27 $t
	    set t [lindex $D 0]
	    for {set j 0} {$j < 27} {incr j} {
		lset D $j [lindex $D [expr {$j + 1}]]
	    }
	    lset D 27 $t
	}
	
	for {set j 0} {$j < 24} {incr j} {
	    lset KS $i $j [lindex $C [expr {[lindex $PC2_C $j] - 1}]]
	    lset KS $i [expr {$j + 24}] \
		[lindex $D [expr {[lindex $PC2_D $j] - 28 - 1}]]
	}
    }
    
    set E [list]
    for {set i 0} {$i < 48} {incr i} {
	lappend E [lindex $e $i]
    }
    
    for {set i 0} {$i < 66} {incr i} {
	lset block $i 0
    }
    
    set salt [split $salt ""]
    set salt_pos 0
    set val_Z 90
    set val_9 57
    set val_period 46
    
    for {set i 0} {$i < 2} {incr i} {
	scan [lindex $salt $salt_pos] %c c
	incr salt_pos
	lset iobuf $i $c
	
	if {$c > $val_Z} {
	    incr c -6
	}
	if {$c > $val_9} {
	    incr c -7
	}
	incr c -$val_period
	for {set j 0} {$j < 6} {incr j} {
	    if {[expr {($c >> $j) & 01}]} {
		set temp [lindex $E [expr {6 * $i + $j}]]
		lset E [expr {6 * $i + $j}] \
		    [lindex $E [expr {6 * $i + $j + 24}]]
		lset E [expr {6 * $i + $j + 24}] $temp
	    }
	}
    }
    
    set edflag 0
    for {set h 0} {$h < 25} {incr h} {
	set L [list]
	for {set j 0} {$j < 64} {incr j} {
	    lappend L [lindex $block [expr {[lindex $IP $j] - 1}]]
	}
	
	for {set ii 0} {$ii < 16} {incr ii} {
	    if {$edflag} {
		set i [expr {15 - $ii}]
	    } else {
		set i $ii
	    }
	    
	    set tempL [list]
	    for {set j 0} {$j < 32} {incr j} {
		lappend tempL [lindex $L [expr {$j + 32}]]
	    }
	    
	    set preS [list]
	    for {set j 0} {$j < 48} {incr j} {
		lappend preS \
		    [expr {[lindex $L [expr {[lindex $E $j] - 1 + 32}]] ^ [lindex $KS $i $j]}]
	    }

	    for {set j 0} {$j < 8} {incr j} {
		set t [expr {6 * $j}]
		set k [lindex $S $j [expr {
				([lindex $preS $t] << 5) +
				([lindex $preS [expr {$t + 1}]] << 3) +
				([lindex $preS [expr {$t + 2}]] << 2) +
				([lindex $preS [expr {$t + 3}]] << 1) +
				[lindex $preS [expr {$t + 4}]] +
				([lindex $preS [expr {$t + 5}]] << 4)
			    }]]

		set t [expr {4 * $j}]
		lset f $t              [expr {($k >> 3) & 01}]
		lset f [expr {$t + 1}] [expr {($k >> 2) & 01}]
		lset f [expr {$t + 2}] [expr {($k >> 1) & 01}]
		lset f [expr {$t + 3}] [expr { $k       & 01}]
	    }
	    
	    for {set j 0} {$j < 32} {incr j} {
		lset L [expr {$j + 32}] \
		    [expr {[lindex $L $j] ^ [lindex $f [expr {[lindex $P $j] - 1}]]}]
	    }
	    
	    for {set j 0} {$j < 32} {incr j} {
		lset L $j [lindex $tempL $j]
	    }
	}
	
	for {set j 0} {$j < 32} {incr j} {
	    set t [lindex $L $j]
	    lset L $j [lindex $L [expr {$j + 32}]]
	    lset L [expr {$j + 32}] $t
	}
	
	for {set j 0} {$j < 64} {incr j} {
	    lset block $j [lindex $L [expr {[lindex $FP $j] - 1}]]
	}
    }
    
    for {set i 0} {$i < 11} {incr i} {
	set c 0
	for {set j 0} {$j < 6} {incr j} {
	    set c [expr {$c << 1}]
	    set c [expr {$c | [lindex $block [expr {6 * $i + $j}]]}]
	}
	incr c $val_period
	if {$c > $val_9} {
	    incr c 7
	}
	if {$c > $val_Z} {
	    incr c 6
	}
	lset iobuf [expr {$i + 2}] $c
    }
    
    if {[lindex $iobuf 1] == 0} {
	lset iobuf 1 [lindex $iobuf 0]
    }
    
    set encrypted ""
    foreach element $iobuf {
	append encrypted [format %c $element]
    }
    
    return $encrypted
}

Added modules/httpd/template.tcl.









































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# template.tcl
#@c Template support
#
# Derived from doc.tcl
# Stephen Uhler / Brent Welch (c) 1997-1998 Sun Microsystems
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: template.tcl,v 1.20 2004/10/22 08:32:56 coldstore Exp $

package provide httpd::template 1.0

package require httpd	;# Httpd_PostDataSize Httpd_ReturnData
package require httpd::cgi	;# Cgi_SetEnv Cgi_SetEnvInterp
package require httpd::cookie	;# Cookie_Save
package require httpd::doc	;# Doc_GetPath
package require httpd::log	;# Log
package require httpd::mtype	;# Mtype
package require httpd::subst	;# Subst_File
package require httpd::url	;# Url_Decode Url_DecodeQuery Url_ReadPost
package require httpd::utils	;# file file_latest lappendOnce
package require Markdown ;# Markdown handler

# Set the file extension for templates
if {![info exists Template(mdExt)]} {
    set Template(mdExt) .md
}
if {![info exists Template(tmlExt)]} {
    set Template(tmlExt) .tml
}
if {![info exists Template(env)]} {
    set Template(env) 1
}

if {![info exists Template(htmlExt)]} {
    switch $tcl_platform(platform) {
	windows {
	    set Template(htmlExt) .htm
	}
	default {
	    set Template(htmlExt) .html
	}
    }
}

set Template(htmlMatch) {([.]html?)}

# Template_Check --
#
# Allow or disable automatic template checking
#
# Arguments:
#	how 	A boolen that enables or disables template handling.
#
# Results:
#	None
#
# Side Effects:
#	Sets the checkTemplates variable.

proc Template_Check {{how 1}} {
    global Template
    set Template(checkTemplates) $how
}
if {![info exists Template(checkTemplates)]} {
    set Template(checkTemplates) 0
}

# Template_Interp --
#
# Choose an alternate interpreter in which to process templates
#
# Arguments:
#	interp	The Tcl interpreter in which to process templates.
#
# Results:
#	None
#
# Side Effects:
#	Sets the interpreter for all Doc domain templates.

proc Template_Interp {interp} {
    global Template
    if {[string length $interp] && ![interp exists $interp]} {
	interp create $interp
    }
    set Template(templateInterp) $interp
}
if {![info exists Template(templateInterp)]} {
    set Template(templateInterp) {}
}

# Template_Library --
#
# Define the auto_load library for template support
#
# Arguments:
#	dir	The directory to add to the auto_path
#
# Results:
#	None
#
# Side Effects:
#	Updates the auto_path variable in the interpreter used
#	for templates.

proc Template_Library {dir} {
    global Template auto_path
    set Template(templateLibrary) $dir
    if {$Template(templateInterp) != {}} {
	interp eval $Template(templateInterp) [list lappendOnce ::auto_path $dir]
    } else {
	lappendOnce auto_path $dir
    }
}

# Doc_application/x-tcl-template --
#
# Tcl-subst a template that mixes HTML and Tcl.
#
# Arguments:
#	path	The file pathname.
#	suffix	The URL suffix.
#	sock	The socket connection.
#
# Results:
#	None
#
# Side Effects:
#	Sets up the interpreter context and subst's the page,
#	which is returned to the client.

proc Doc_application/x-tcl-template {path suffix sock} {
    upvar #0 Httpd$sock data
    global Template

    # This is always dynamic (ReturnData has no modification date)
    # so the result is not cached at the remote end, nor is a local
    # .html file cached.

    set content [TemplateInstantiate $sock $path {} $suffix {} $Template(templateInterp)]
    # If the content type was set, use it.  Otherwise, use the default.
    if {[info exists data(contentType)]} {
	set ctype $data(contentType)
    } else {
	set ctype text/html
    }
    return [Httpd_ReturnData $sock $ctype $content]
}

# TemplateInstantiate --
#
# Generate a .html file from a template
# and from any .tml files in directories leading up to the root.
# The processing is done in the specified interpreter.
# State set in the global array "page":
#	url		The URL past the document root
#	template	The filename of the template file
#	filename	The filename of the associated htmlfile
#	root		The ../ path up to the root
#	dynamic		If 1, then this page is dynamically generated
#			on every fetch.  Otherwise the page has a cached
#			static representation.
#
# Arguments:
#	sock		The client socket.
#	template	The file name of the template.
#	htmlfile	The file name of the corresponding .html file.
#	suffix		The URL suffix.
#	dynamicVar	Name of var to set to dynamic property of the page.
#	interp		The interp to use for substing.
#
# Results:
#	html, or an error generated by the template
#
# Side Effects:
#	Generates a page.  Will set up the CGI environment via the ncgi
#	module, and will do environment variable settings.
#	data(contentType) contains the mime type of generated content.

proc TemplateInstantiate {sock template htmlfile suffix dynamicVar {interp {}}} {
    upvar #0 Httpd$sock data
    upvar $dynamicVar dynamic
    global Template

    # Compute a relative path back to the root.

    set dirs [lreplace [split [string trimleft $data(url) /] /] end end]
    set root ""
    foreach d $dirs {
	append root ../
    }

    # Populate the global "page" array with state about this page
    if {[string length $htmlfile]} {
	set filename $htmlfile
	set dynamic 0
    } else {
	set filename $template
	set dynamic 1
    }
    interp eval $interp {uplevel #0 {catch {unset page}}}

    interp eval $interp [list uplevel #0 [list array set page [list \
	url		$data(url)	\
	template 	$template	\
	includeStack 	[list [file dirname $template]]	\
	filename	$filename	\
	root		$root		\
	dynamic		$dynamic	\
    ]]]

    # Populate the global "env" array similarly to the CGI environment
    if {$Template(env)} {
	Cgi_SetEnvInterp $sock $filename $interp
    }

    # Check query data.

    if {[Httpd_PostDataSize $sock] > 0 && ![info exists data(query)]} {
	set data(query) {}
    }
    if {[info exist data(query)]} {
	if {![info exist data(mime,content-type)] || $data(proto) == "GET"} {
	    
	    # The check against GET is because IE 5 has the following bug.
	    # If it does a POST with content-type multipart/form-data and
	    # keep-alive reuses the connection for a subsequent GET request,
	    # then the GET request erroneously has a content-type header
	    # that is a copy of the one from the previous POST!

	    set type application/x-www-urlencoded
	} else {
	    set type $data(mime,content-type)
	}

	# Read and append the pending post data to data(query).

	Url_ReadPost $sock data(query)

	# Initialize the Standard Tcl Library ncgi package so its
	# ncgi::value can be used to get the data.  This replaces
	# the old Url_DecodeQuery interface.

	interp eval $interp [list ncgi::reset $data(query) $type]
	interp eval $interp [list ncgi::parse]
	interp eval $interp [list ncgi::urlStub $data(url)]

	# Define page(query) and page(querytype)
	# for compatibility with older versions of TclHttpd
	# This is a bit hideous because it reaches inside ::ncgi
	# to avoid parsing the data twice.

	interp eval $interp [list uplevel #0 [list set page(querytype) \
		[string trim [lindex [split $type \;] 0]]]]
	interp eval $interp [list uplevel #0 {
	    set page(query) {}
	    foreach n $ncgi::varlist {
		foreach v $ncgi::value($n) {
		    lappend page(query) $n $v
		}
	    }
	}]

    } else {
	interp eval $interp [list ncgi::reset ""]
	interp eval $interp [list uplevel #0 [list set page(query) {}]]
	interp eval $interp [list uplevel #0 [list set page(querytype) {}]]
    }

    # Source the .tml files from the root downward.

    foreach libdir [Doc_GetPath $sock $template] {
	set libfile [file join $libdir $Template(tmlExt)]
	if {[file exists $libfile]} {
	    interp eval $interp [list uplevel #0 [list source $libfile]]
	}
    }

    # Process the template itself

    set code [catch {Subst_File $template $interp} html]

    if {$code != 0} {
	# pass errors up - specifically Redirect return code

	# stash error information so Cookie_Save doesn't interfere
	global errorCode errorInfo
	set ec $errorCode
	set ei $errorInfo

	# Save return cookies, if any
	Cookie_Save $sock $interp

	return -code $code -errorcode $ec -errorinfo $ei
    }

    # Save return cookies, if any
    Cookie_Save $sock $interp

    set dynamic [interp eval $interp {uplevel #0 {set page(dynamic)}}]
    if {!$dynamic} {

	# Cache the result

	catch {file delete -force $htmlfile}

	# process any filters
	if {[info exists data(filter)]} {
	    while {[llength $data(filter)]} {
		set cmd [lindex $data(filter) end]
		set data(filter) [lrange $data(filter) 0 end-1]
		catch {
		    set html [eval $cmd $sock [list $html]]
		}
	    }
	}

	if {[catch {open  $htmlfile w} out]} {
	    set dynamic 1
	    Log $sock "Template" "no write permission"
	} else {
	    puts -nonewline $out $html
	    close $out
	}
    }
    return $html
}

# Template_Dynamic
#	Supress generation of HTML cache
#
# Arguments:
#
# Results:
#	None
#
# Side Effects:
#	Sets the dynamic bit so the page is not cached.

proc Template_Dynamic {} {
    global page
    set page(dynamic) 1
    return "<!-- DynamicOnly -->\n"
}

# TemplateCheck --
#
# Check modify times on all templates that affect a page
#
# Arguments:
#	sock		The client connection
#	template	The file pathname of the template.
#	htmlfile	The file pathname of the cached .html file.
#
# Results:
#	1 if the template or any dependent .tml file are newer than
#	the cached .html file.
#
# Side Effects:
#	None

proc TemplateCheck {sock template htmlfile} {
    global Template

    if {[file exists $htmlfile]} {
	set mtime [file mtime $htmlfile]
    } else {
	return 1
    }

    # Look for .tml library files down the hierarchy.
    global Doc
    set rlen [llength [file split $Doc(root)]]
    set dirs [lrange [file split [file dirname $template]] $rlen end]
	
    foreach libdir [Doc_GetPath $sock $template] {
	set mdfile [file join $libdir $Template(mdExt)]
	if {[file exists $mdfile] && ([file mtime $mdfile] > $mtime)} {
	    return 1
	}
	set libfile [file join $libdir $Template(tmlExt)]
	if {[file exists $libfile] && ([file mtime $libfile] > $mtime)} {
	    return 1
	}
    }

    # make index.html regeneration depend upon the whole directory's
    # modification time, not just the modification time of index.tml
    global dirlist
    if {[file root [file tail $htmlfile]] == [file root $dirlist(indexpat)]} {
	if {[file mtime [file dirname $htmlfile]] > $mtime} {
	    return 1
	}
    }

    return [expr {[file mtime $template] > $mtime}]
}


# Template_try --
# process a template file which is newer than the path (if path exists).
#
# Arguments:
#	sock	The client connection
#	path	The file system pathname of the file.
#	suffix	The URL suffix.
#
# Results:
#	1 if the request has been completed (by a dynamic template)
#	0 if the request hasn't been handled, either because there is
#	  no template, or because cache file is (now) newer and can be
#	  handled by caller
#
# Side Effects:
#	May have generated a page - 
#	data(contentType) contains the mime type of generated content.

proc Template_Try {sock path suffix} {
    upvar #0 Httpd$sock data
    global Template

    if {!$Template(checkTemplates)} {
	return 0
    }
    
    set mdtemplate ${path}$Template(mdExt)
    if {[file exists $mdtemplate]} {
      # we have a matching template and extension for path
      # See if the cached result is up-to-date
      set dynamic 0
      if {[TemplateCheck $sock $mdtemplate $path]} {
        # Template file is newer than its cached version
        # Do the subst and cache the result in the .html file
        # We set a provisional type based on the file extension, but
        # the template processing can override that
        set data(contentType) text/html
        set fin [open $mdtemplate r]
        set mdtxt [read $fin]
        close $fin
        
        set html [::Markdown::convert $mdtxt]

        if {$dynamic} {
          # return the data directly
          Httpd_ReturnData $sock $data(contentType) $html
          return 1
        } else {
          set fout [open $path w]
          puts $fout $html
          close $fout
          # we have generated a cached file from the template.
          # leave it to caller to return newly generated file
          return 0
        }
      } else {
        # cache file is newer
        return 0
      }
    } else {
      set template ${path}$Template(tmlExt)

      if {![file exists $template]} {
  	# special case, x.tml generates x.html
  	set template [file root $path]$Template(tmlExt)
  	
  	# ensure request was for *.htm[l]? and .tml exists
  	if {![regexp $Template(htmlMatch) [file extension $path]]
  	    || ![file exists $template]} {
  	    # no template found
  	    return 0
  	}
      }
    
      # we have a matching template and extension for path
      # See if the cached result is up-to-date
      if {[TemplateCheck $sock $template $path]} {
        # Template file is newer than its cached version
        # Do the subst and cache the result in the .html file
        # We set a provisional type based on the file extension, but
        # the template processing can override that
        set data(contentType) [Mtype $path]
        set html [TemplateInstantiate $sock $template $path $suffix dynamic \
                      $Template(templateInterp)]

        if {$dynamic} {
          # return the data directly
          Httpd_ReturnData $sock $data(contentType) $html
          return 1
        } else {
          # we have generated a cached file from the template.
          # leave it to caller to return newly generated file
          return 0
        }
      } else {
        # cache file is newer
        return 0
      }
    }
}

# Template_Choose - what mime-type does this file
# represent, or generate?
# a.x.tml is considered to return/match .x
proc Template_Choose {accept choices} {
    global Template

    # generate a map map from mime_type -> choices
    foreach f $choices {
	# get first of two extensions eg .css.tml
	set type [file extension [file root $f]]	;# use .css in .css.tml
	if {$type == ""} {
	    set type [file extension $f]	;# path has only a single extension
	    if {$type == $Template(tmlExt)} {
		# we've found a .tml file - x.tml matches x.html
		set type $Template(htmlExt)
	    }
	}
	lappend mtype([Mtype $type]) $f
    }

    # array mtype is now a mapping from mime types to files
    # for the collection of files we can offer.

    # look at what mime types the client accepts, in order of presentation
    # (nb FIXME: the spec says we should accept them in q= order)
    foreach t [split $accept ,] {
	# find something that matches 
	regsub {;.*} $t {} t	;# Nuke quality parameters
	set t [string trim [string tolower $t]]

	# collect string-matching mtypes we can offer
	set hits {}
	foreach {mime files} [array get mtype $t] {
            set hits [concat $hits $files]
	}

	# if some file choices match on type, choose the most recent
	if {[llength $hits] > 1} {
	    set hit [file_latest $hits]
	} else {
	    set hit [lindex $hits 0]
	}

	if {[string length $hit]} {
	    # we have a matching file
	    if {[file extension $hit] == $Template(tmlExt)} {
		# our candidate is a template file
		# return the name of the file as it will be.
		if {[file extension [file root $hit]] == ""} {
		    # we're about to offer a .tml - as an .html
		    return "[file root $hit]$Template(htmlExt)"
		} else {
		    # strip the .tml and return for redirection
		    return [file root $hit]
		}
	    }
	    return $hit	;# not a templated match
	}
    }

    return {}	;# no acceptable matches
}

Added modules/httpd/thread.tcl.









































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# threadmgr.tcl
#	Wrappers around basic thread commands
#
#	"Thread" is the C-based Tcl extension
#	"threadmgr" is the TclHttpd thread manager
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: thread.tcl,v 1.16 2004/09/05 05:10:14 coldstore Exp $

package provide httpd::threadmgr 1.0

package require httpd	;# Httpd_GetPostData
package require httpd::config	;# Config
package require httpd::counter	;# Count
package require httpd::log	;# Log
package require httpd::url	;# Url_Unwind
package require httpd::utils	;# Stderr file ldelete

# The "Thread" package is implemented by a C extension.
# We let the main .rc script do the appropriate package
# require, and then fall back to the testthread command if necessary.

# Default is no threading until Thread_Init is called

if {![info exist Thread(enable)]} {
    set Thread(enable) 0
}

# Thread_Init
#
#	Initialize the thread dispatcher
#
# Arguments
#	max	Maximum number of threads to create.
#
# Side Effects
#	Initializes variables used by the thread dispatcher

proc Thread_Init {{max 4}} {
    global Thread
    package require Thread 2.0
    set Thread(maxthreads) $max	;# Number of threads we can create
    set Thread(threadlist) {}	;# List of threads we have created
    set Thread(freelist) {}	;# List of available threads
    set Thread(deletelist) {}	;# List of running threads to delete when done
    set Thread(queue) {}	;# List of queued requests, ?socket? cmd
    set Thread(enable) 1
}

# Thread_IsMaster
#
#	Find out if this thread is the master.
#
# Arguments
#	none
#
# Results
#	Returns true iff this thread is the master.

proc Thread_IsMaster {} {
    return [expr {![info exists ::Thread_MasterId]}]
}

# Thread_Enabled
#
#	Find out if the threading system is turned on
#
# Arguments
#	none
#
# Results
#	none

proc Thread_Enabled {} {
    global Thread
    return $Thread(enable)
}

# Thread_List
#
#	Return the list of threads
#
# Arguments
#	none
#
# Results
#	a list

proc Thread_List {} {
    global Thread
    if {$Thread(enable)} {
        return [thread::names]
    }
    return ""
}


# Thread_Start --
#	This starts a worker thread.  The big pain here is that a
#	virgin thread has none of our Tcl scripts, so we have to
#	bootstrap into a useful state.
#
# Arguments:
#	None
#
# Results:
#	The ID of the created thread

proc Thread_Start {} {
    global auto_path tcl_library
    set id [Thread_Create]
    Thread_Send $id \
	{puts stderr "Thread  starting."}

    # Set up auto_loading.  These steps may become redundent once the
    # TclpSetLibraryPath code works correctly in threads.

    Thread_Send $id \
	[list set tcl_library $tcl_library]
    Thread_Send $id \
	{source $tcl_library/init.tcl}
    Thread_Send $id \
	[list set auto_path $auto_path]

    # Suck up all the necessary packages
    # Most state comes from the initialization in the config file.
    # There is just a bit of info in the Httpd array that is set up
    # when the main server is started, which we need (e.g., the name)

    global Httpd Config
    Thread_Send $id \
	[list array set Httpd [array get Httpd]]
    Thread_Send $id \
	[list array set Config [array get Config]]

    # Let the new thread know its master's Id.  Only slave threads have
    # the "Thread_MasterId" global varaible set.
    Thread_Send $id [list set Thread_MasterId [Thread_Id]]

    Thread_Send $id [list source $Config(main)]

    return $id
}

# Thread_Dispatch --
#	This dispatches the HTTP request to a worker thread.
#	That thread should use Thread_Respond or raise an error
#	to complete the request.
#
# Arguments:
#	sock	Client connection
#	cmd	Command to invoke in a worker
#
# Side Effects:
#	Allocate a thread or queue the command/sock for later execution

proc Thread_Dispatch {sock cmd} {
    global Thread Url
    upvar #0 Httpd$sock data
    if {!$Thread(enable) || $Thread(maxthreads) == 0} {
	eval $cmd
    } else {
	if {[llength $Thread(freelist)] == 0} {
	    if {[llength $Thread(threadlist)] < $Thread(maxthreads)} {

		# Add a thread to the free pool

		set id [Thread_Start]
		lappend Thread(threadlist) $id
		lappend Thread(freelist) $id
	    } else {

		# Queue the request until a thread is available

		lappend Thread(queue) [list $sock $cmd]
		Count threadqueue
		return
	    }
	}
	set id [lindex $Thread(freelist) 0]
	set Thread(freelist) [lrange $Thread(freelist) 1 end]
	set data(master_thread) [Thread_Id]

	# Until we can pass sockets, read the post data here

	if {[info exist Url(postlength)]} {
	    while {$Url(postlength) > 0} {
		set Url(postlength) [Httpd_GetPostData $sock data(query)]
	    }
	    unset Url(postlength)
	}
	Thread_SendAsync $id [list Thread_Invoke $sock [array get data] $cmd]
    }
}

# Thread_Dispatch_General --
#	This dispatches the command to a worker thread.
#	That thread should use Thread_Respond_General or raise an error
#	to complete the request.
#
# Arguments:
#	cmd	Command to invoke in a worker
#
# Side Effects:
#	Allocate a thread or queue the command/sock for later execution

proc Thread_Dispatch_General {cmd} {
    global Thread Url
    if {!$Thread(enable) || $Thread(maxthreads) == 0} {
	eval $cmd
    } else {
	if {[llength $Thread(freelist)] == 0} {
	    if {[llength $Thread(threadlist)] < $Thread(maxthreads)} {

		# Add a thread to the free pool

		set id [Thread_Start]
		lappend Thread(threadlist) $id
		lappend Thread(freelist) $id
	    } else {

		# Queue the request until a thread is available

		lappend Thread(queue) [list $cmd]
		Count threadqueue
		return
	    }
	}
	set id [lindex $Thread(freelist) 0]
	set Thread(freelist) [lrange $Thread(freelist) 1 end]

	Thread_SendAsync $id [list Thread_Invoke_General $cmd]
    }
}

# Thread_Invoke --
#	This is invoked in a worker thread to handle an HTTP request.
#
# Arguments:
#	sock	The name of the socket connection.  Probably is not
#		an actual I/O socket.
#	datalist The contents of the connection state in array get format
#	cmd	Tcl command to eval in this thread
#
# Results:
#	None

proc Thread_Invoke {sock datalist cmd} {
    upvar #0 Httpd$sock data
    if {[info exist data]} {
	unset data
    }
    Count urlhits
    array set data $datalist

    # Make sure the thread knows which socket it's currently processing.
    # This is needed for redirects from within doc templates.
    set ::Httpd(currentSocket) $sock

    if {[catch $cmd result]} {
	global errorInfo errorCode
	Count errors
	Thread_Respond $sock [list Url_Unwind $sock $errorInfo $errorCode]
    } else {
	return $result
    }
}

# Thread_Invoke_General --
#	This is invoked in a worker thread to handle general eval request.
#
# Arguments:
#	cmd	Tcl command to eval in this thread
#
# Results:
#	None

proc Thread_Invoke_General {cmd} {
    if {[catch $cmd result]} {
	global errorInfo errorCode
	Count errors

        # An error occurred, so log it.
        Log {} bgerror "Error with code $errorCode in thread [Thread_Id]:\n$errorInfo"
    }

    Thread_MasterEvalAsync [list Thread_Free [Thread_Id]]
    return
}

# Thread_Respond --
#	This is invoked in a worker thread to respond to a request
#
# Arguments:
#	sock	Client connection
#	cmd	Command to invoke to complete the request
#
# Results:
#	1 if the request was passed to the master thread, else 0

proc Thread_Respond {sock cmd} {
    upvar #0 Httpd$sock data
    if {[info exist data(master_thread)] &&
	    $data(master_thread) != [Thread_Id]} {

	# Pass request back to the master thread
	# This includes a copy of the Httpd state (e.g., cookies)

	Thread_SendAsync $data(master_thread) [list Thread_Unwind \
		 [Thread_Id] $sock [array get data] $cmd]

        # The next iteration of the thread should not have access to
        # past connection data.
	unset data
	return 1
    } else {
	return 0
    }

}

# Thread_Unwind --
#	Invoke a response handler for a thread that handled an HTTP request.
#	This cleans up the connection in the main thread.
#
# Arguments:
#	id	The ID of the worker thread.
#	sock	The ID of the socket connection
#	datalist name, value list for the Httpd state array
#	cmd	The command to eval in the main thread
#
# Side Effects:
#	Invoke the response handler.

proc Thread_Unwind {id sock datalist cmd} {
    upvar #0 Httpd$sock data
    array set data $datalist
    if {[catch $cmd err]} {
	global errorCode errorInfo
	Url_Unwind $sock $errorInfo $errorCode
    }
    Thread_Free $id
}

# Thread_Free --
#	Mark a thread as available
#
# Arguments:
#	id	The ID of the worker thread.
#
# Side Effects:
#	Reap the thread, put it on the freelist, or perhaps handle
#	a queued request.

proc Thread_Free {id} {
    global Thread

    if {[ldelete Thread(deletelist) $id]} {
        # This thread was marked for deletion, so tell it to exit.
        Thread_SendAsync $t thread::exit
        ldelete Thread(threadlist) $id
    } elseif {[llength $Thread(queue)] > 0} {
	set state [lindex $Thread(queue) 0]
	set Thread(queue) [lrange $Thread(queue) 1 end]
        if {[llength $state] == 1} {
            # No socket was given, so just eval the command in the thread.
            set cmd [lindex $state 0]
            Thread_SendAsync $id [list Thread_Invoke_General $cmd]
        } else {
            set sock [lindex $state 0]
            set cmd [lindex $state 1]
            upvar #0 Httpd$sock data
            set data(master_thread) [Thread_Id]
            Thread_SendAsync $id [list Thread_Invoke $sock [array get data] $cmd]
        }
    } else {
	lappend Thread(freelist) $id
    }
}

# Thread_Create --
#	thread create
#
# Arguments:
#	Optional startup script
#
# Results:
#	The ID of the created thread

proc Thread_Create {{script {}}} {
    Count threads
    if {[string length $script]} {
	return [thread::create $script]
    } else {
	return [thread::create]
    }
}

# Thread_Send --
#	thread send
#
# Arguments:
#	id	Target thread
#	script	Script to send
#
# Results:
#	The results of the script

proc Thread_Send {id script} {
    if {[catch {thread::send $id $script} result]} {
	return -code error $result
    } else {
	return $result
    }
}

# Thread_MasterEval
#
#	Evaluate the given script synchronously in the master thread.
#
# Arguments
#	script	The script to evaluate.
#
# Results
#	Returns the result of evaluating the script in the master.

proc Thread_MasterEval {script} {
    if {[info exists ::Thread_MasterId]} {
        return [Thread_Send $::Thread_MasterId $script]
    } else {
        return [eval $script]
    }
}

# Thread_SendAsync --
#	thread send -async
#
# Arguments:
#	id	Target thread
#	script	Script to send
#
# Results:
#	The results of the script

proc Thread_SendAsync {id script} {
    if {[catch {thread::send -async $id $script} result]} {
	return -code error $result
    } else {
	return $result
    }
}

# Thread_MasterEvalAsync
#
#	Evaluate the given script asynchronously in the master thread.
#
# Arguments
#	script	The script to evaluate.
#
# Results
#	none.

proc Thread_MasterEvalAsync {script} {
    if {[info exists ::Thread_MasterId]} {
        return [Thread_SendAsync $::Thread_MasterId $script]
    } else {
        after 0 [list eval $script]
        return
    }
}

# Thread_Id --
#	thread::id
#
# Arguments:
#	none
#
# Results:
#	The thread ID

proc Thread_Id {} {
    thread::id
}

# Thread_IsFree --
#	Find out if a thread is on the free list.
#
# Arguments:
#	id	The thread ID
#
# Results:
#	1 or 0

proc Thread_IsFree {id} {
    global Thread
    return [expr {[lsearch $Thread(freelist) $id] >= 0}]
}

# Thread_ReapAll --
#	The master thread should reap all free threads and mark all busy
#	threads for deletion upon completion of their task.
#
# Arguments:
#	None.
#
# Results:
#	None.

proc Thread_ReapAll {} {
    if {![Thread_IsMaster]} {
        # This proc should only be called by the master thread.
        return
    }

    global Thread
    set Thread(deletelist) {}

    foreach id $Thread(threadlist) {
        if {[lsearch $Thread(freelist) $id] != -1} {
            # Free threads are told to exit and removed from the freelist.
            Thread_SendAsync $id thread::exit
        } else {
            # Busy threads are marked for deletion upon completion of their task.
            lappend Thread(deletelist) $id
        }
    }

    set Thread(threadlist) $Thread(deletelist)
    set Thread(freelist) {}
    return
}

# Thread_SendAll --
#	The master thread serially sends this script to all free threads,
#	including itself.
#
# Arguments:
#	cmd	The script to send to all threads.
#
# Results:
#	Returns the list of alternating thread id and result, or {} if
#	this thread is not the master.

proc Thread_SendAll {cmd} {
    if {![Thread_IsMaster]} {
        # This proc should only be called by the master thread.
        return {}
    }

    global Thread
    foreach id $Thread(threadlist) {
        if {[lsearch $Thread(freelist) $id] != -1} {
            # Send the same script to all free threads.
            lappend result $id [Thread_Send $id $cmd]
        }
    }
    # Also eval the script in this thread.
    catch {eval $cmd} res
    lappend result [thread::id] $res
    return $result
}

Added modules/httpd/upload.tcl.









































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# upload.tcl
#
# File upload domain.  This implements a domain handler that
# specializes in file uploading of multipart/form-data.
# It uploads files into a particular directory and enforces
# limits on the number of files, their size, etc.
# It invokes handler procedures similar to application-direct
# handlers after doing the file upload.
#
# Brent Welch (c) 2001
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: upload.tcl,v 1.13 2004/09/05 05:10:14 coldstore Exp $

package require ncgi

package provide httpd::upload 1.0

package require httpd	;# Httpd_Error Httpd_Redirect Httpd_ReturnData Httpd_Suspend
package require httpd::url	;# Url_PostHook Url_PrefixInstall
package require httpd::utils	;# Incr K Stderr file

# Upload_Url
#	Define a subtree of the URL hierarchy that handles
#	file uploads.
#
# Arguments
#	virtual The URL prefix of the upload domain.
#	dir	The upload directory - files get placed here.	
#	command	The Tcl command to invoke after an upload.
#	args	option-value flags described below.
#		-thread <boolean>
#			If true, dispatch domain in a thread
#		-maxfiles <integer>
#			Maximum files in upload directory
#		-maxbytes <integer>
#			Maximum number of bytes in a file
#		-totalbytes <integer>
#			Limit on total bytes in all files
#			in the upload directory
#		-unique <boolean>
#			Give uploads unique names
#
# Side Effects
#	Register a prefix

proc Upload_Url {virtual dir command args} {
    global Upload
    array set opt {
	    -inThread 0
	    -maxfiles -1
	    -maxbytes -1
	    -totalbytes -1
	    -unique 0
    }
    array set opt $args
    Url_PrefixInstall $virtual [list UploadDomain $dir $command \
	$opt(-maxfiles) $opt(-maxbytes) $opt(-totalbytes) $opt(-unique)] \
	-thread $opt(-inThread) \
        -callback [list UploadTidyUp] \
	-readpost 0
}

# UploadDomain
# Main handler for Upload domains 
# This uploads the file, if it does not exceed the byte
# and file limits, then invokes the callback.
#
# Arguments
#	dir	Upload directory
#	cmd	Tcl command to call after upload
#	maxfiles	Max files per upload diretory
#	maxbytes	File byte limit
#	totalbytes	Total bytes per upload directory
#	sock	The socket back to the client
#	suffix	The part of the url after the domain prefix.
#

proc UploadDomain {dir cmd maxfiles maxbytes totalbytes unique sock suffix} {
    upvar #0 Httpd$sock data
    upvar #0 Upload$sock upload

    # Testing
    if {[string match *test* $suffix]} {
	set fd [open $dir/test w]
	fconfigure $fd -trans binary
	puts -nonewline $fd [read $sock $data(mime,content-length)]
	close $fd
	Httpd_ReturnData $sock text/html $dir/test
    }
    # Extract multi-part boundary from the headers

    if {![info exist data(mime,content-type)] || $data(proto) == "GET"} {
	set type application/x-www-urlencoded
    } else {
	set type $data(mime,content-type)
    }
    set parsedType [ncgi::parseMimeValue $type]
    if {![string match multipart/* [lindex $parsedType 0]]} {
	return -code error "Not a multipart Content-Type: [lindex $parsedType 0]"
    }
    array set options [lindex $parsedType 1]
    if {![info exists options(boundary)]} {
	return -code error "No boundary given for multipart document"
    }

    # Record upload instance data and set up a read event handler
    # so we can read large files without blocking.

    if {[info exist upload]} {
	unset upload
    }
    set upload(boundary) $options(boundary)
    set upload(dir) $dir
    set upload(cmd) $cmd
    set upload(maxfiles) $maxfiles
    set upload(totalbytes) $totalbytes
    set upload(maxbytes) $maxbytes
    set upload(suffix) $suffix
    set upload(count) $data(count)
    set upload(unique) $unique

    # These are temporary storage used when parsing the headers of each part

    set upload(headers) {}
    set upload(formName) {}
    set upload(formNames) {}

    if {$upload(maxfiles) != -1} {
	set files [glob -nocomplain -- [file join $upload(dir) *]]
	if {[llength $files] >= $upload(maxfiles)} {
	    Httpd_Error $sock 503 "Max files ($upload(maxfiles)) exceeded.<br>Unable to upload"
	    return
	}
    }

    if {$upload(maxbytes) != -1} {
	if {$upload(count) >= $upload(maxbytes)} {
	    Httpd_Error $sock 503 "File size limit ($upload(maxbytes) bytes) exceeded.<br>Unable to upload."
	    return
	}
    }

    if {$upload(totalbytes) != -1} {
	set tot $upload(count)
	foreach f [glob -nocomplain -- [file join $upload(dir) 0]] {
	    incr tot [file size $f]
	}
	if {$tot >= $upload(totalbytes)} {
	    Httpd_Error $sock 503 "Total size limit ($upload(totalbytes) bytes) exceeded.<br>Unable to upload."
	    return
	}
    }

    # Now that we are going to read the post data, clear out the
    # hook and the data count so noone else tries to read it

    Url_PostHook $sock 0
    set data(count) 0

    # Accept cr-lf endings in the headers
    fconfigure $sock -trans auto
    fileevent $sock readable [list UploadFindBoundary $sock]
}

# Look for the first boundary - should be the first line read,
# but done in a fileevent to avoid blocking.

proc UploadFindBoundary {sock} {
    upvar #0 Upload$sock upload
    if {[eof $sock]} {
	UploadDone $sock
	return
    }
    if {[gets $sock line] > 0} {
	if {[regexp ^--$upload(boundary) $line]} {
	    fileevent $sock readable [list UploadReadHeader $sock]
	} else {
	    Stderr "UploadFindBoundary Unexpected line $line"
	}
    }
}

# UploadReadHeader --
#	This is a fileeventhandler used to read the header
#	of each part in a multipart POST payload.

proc UploadReadHeader {sock} {
    upvar #0 Upload$sock upload

    if {[eof $sock]} {
	UploadDone $sock
	return
    }

    # Read through the POST data line-by-line looking for the
    # boundary and diverting file content into files in the
    # upload directory.  We read in binary mode to preserve whatever
    # line-ending mode is in the uploaded file.

    while {[gets $sock line] >= 0} {
        # Check for an empty or white-space only line.
	if {[string length [string trim $line]] == 0} {

	    # End of headers.  We should have seen a name header
	    # that is now in formName.  Keep a list of those, and 
	    # store the other headers under that key.

	    lappend upload(formNames) $upload(formName)
	    set upload(hdrs,$upload(formName)) $upload(headers)

	    # Now switch to reading the content of that part.

	    # Use binary mode so we don't corrupt the file
	    fconfigure $sock -trans binary -encoding binary

	    if {[info exist upload(fd)]} {
		fileevent $sock readable [list UploadReadFile $sock]
	    } else {
		fileevent $sock readable [list UploadReadPart $sock]
	    }
	    return
	}
	if {[regexp {([^:	 ]+):(.*)$} $line x hdrname value]} {
	    set hdrname [string tolower $hdrname]
	    set valueList [ncgi::parseMimeValue $value]
	    if {[string equal $hdrname "content-disposition"]} {

		# Promote Conent-Disposition parameters up to headers,
		# and look for the "name" that identifies the form element

		lappend upload(headers) $hdrname [lindex $valueList 0]
		foreach {n v} [lindex $valueList 1] {
		    lappend upload(headers) $n $v
		    switch -- $n {
			"name" {
			    set upload(formName) $v
			}
			"filename" {
			    # Open the upload file

			    # If the uploade file is empty string,
			    # then use a temporary name--this request
			    # will fail later.  Netscape allows you
			    # to upload dirnames like /a/b/, which
			    # end up as empty string here.
			    if {$v == ""} {
				set v "directory"
			    }

			    # I'm a bit suprised that "file tail"
			    # when run on a Unix box will not deal
			    # with c:\a\b\c.txt correctly...
			    regsub -all {\\} $v / v
			    set tail [file tail $v]
			    if {$upload(unique)} {
				# make the file a unique name
				set path [file join $upload(dir) ${tail}.[clock clicks]]
			    } else {
				set path [file join $upload(dir) $tail]
			    }

			    set upload(fd) [open $path w]
			    set upload(lastLineExists) 0

			    # always do binary transfers
			    fconfigure $upload(fd) -trans binary
			    set upload(file,$upload(formName)) $path
			}
		    }
		}
	    } else {
		lappend upload(headers) $hdrname $valueList
	    }
	}
    }

    if {[fblocked $sock]} {
	return
    }
}

# Look for the boundary at the end of a content part.

proc UploadReadPart {sock} {
    upvar #0 Upload$sock upload
    if {[eof $sock]} {
	UploadDone $sock
	return
    }
    if {[gets $sock line] > 0} {
	if {[regexp ^--$upload(boundary)(--)? $line x end]} {
	    if {$end == "--"} {
		UploadDone $sock
	    } else {
		set upload(formName) ""
		set upload(headers) ""
		fileevent $sock readable [list UploadReadHeader $sock]
	    }
	} else {
            # Trim the string to remove carriage returns.
	    append upload(data,$upload(formName)) [string trim $line]
	}
    }
}

# Read a content part and copy it to a file.
# Because the server is non-blocking, this may be called multiple times to
# process a file.

proc UploadReadFile {sock} {
    upvar #0 Upload$sock upload

    # Maximum size of the buffer, in characters, before we schedule
    # another read and update other waiting tasks.  Increasing this
    # number will probably make uploads a little faster at the expense
    # of some responsiveness on the part of other clients attempting
    # to connect to the server.
    set maxbuffersize 1000
    set buffersize 0

    if {[eof $sock]} {
	UploadDone $sock
	return
    }

    while {[gets $sock line] >= 0} {
	if {[regexp ^--$upload(boundary)(--)? $line x end]} {
	    if {$upload(lastLineExists)} {
		# At least 1 line was read.  Write the last line to the
		# file without the trailing newline character.
		puts -nonewline $upload(fd) [string range $upload(lastLine) 0 end-1]
	    }

	    set buffersize 0
	    close $upload(fd)
	    unset upload(fd)
	    if {$end == "--"} {
		UploadDone $sock
	    } else {
		set upload(formName) ""
		set upload(headers) ""
		fileevent $sock readable [list UploadReadHeader $sock]
	    }
	    return
	} else {
	    # Delay the writing of each line to make sure we don't add an
	    # extra trailing newline to the last line.
	    if {$upload(lastLineExists)} {
		puts $upload(fd) $upload(lastLine)
	    } else {
		set upload(lastLineExists) 1
	    }
	    set upload(lastLine) $line
	}
	incr buffersize [string bytelength $line]
	if { $buffersize > $maxbuffersize } {
	    set buffersize 0
	    fileevent $sock readable [list UploadReadFile $sock]
	    update idletasks
	    break
	}
    }
}

proc UploadDone {sock} {
    upvar #0 Upload$sock upload

    if {[catch {
	# The first argument is a list of file names that were uploaded
	# The second argument is a name-value list of the other data
	set flist {}
	set vlist {}
	foreach x $upload(formNames) {
	    if {[info exist upload(file,$x)]} {
		lappend flist $x $upload(file,$x)
	    } else {
		lappend vlist $x $upload(data,$x)
	    }
	}
	eval $upload(cmd) [list $flist $vlist]
    } result] == 1} {
	# handle special error codes
	set ec $::errorCode
	switch -- [lindex $ec 0] {
	    HTTPD_REDIRECT {
		Httpd_Redirect [lindex $ec 1] $sock
		return
	    }
	    HTTPD_SUSPEND {
		Httpd_Suspend $sock
		return
	    }
	}
    }

    Httpd_ReturnData $sock text/html $result
}

# This is called as the "final" completion callback to clean up

proc UploadTidyUp {sock errmsg} {
    upvar #0 Upload$sock upload

    unset upload
}

# UploadTest --
#	Sample callback procedure for an upload domain

proc UploadTest {flist vlist} {
    set html "<title>Upload Test</title>\n"
    append html "<h1>Upload Test</h1>\n"
    append html "<h2>File List</h2>\n"
    append html [html::tableFromList $flist]\n
    append html "<h2>Data List</h2>\n"
    append html [html::tableFromList $vlist]\n
    return $html
}

Added modules/httpd/url.tcl.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
# url.tcl
#
# This is the URL dispatcher.  The URL hierarchy is divided into "domains"
# that are subtrees of the URL space with a particular type.  A domain is
# identified by the name of its root, which is a prefix of the URLs in
# that domain.  The dispatcher selects a domain by the longest matching
# prefix, and then calls a domain handler to process the URL.  Different
# domain handlers correspond to files (Doc), cgi-bin directories (Cgi),
# and things built right into the application (Direct).
#
# URL processing is divided into two parts: access control and
# url implementation.  You register access hooks with
# Url_AccessInstall, and you register URL implementations with
# Url_PrefixInstall.
#
# Brent Welch (c) 1997 Sun Microsystems, 1998-2000 Scriptics Corporation.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# SCCS: @(#) url.tcl 1.7 97/08/20 11:50:13

package provide httpd::url 1.2

package require httpd	;# Httpd_CompletionCallback Httpd_Error Httpd_Filter Httpd_GetPostData Httpd_ReadPostDataAsync Httpd_Redirect Httpd_RequestComplete Httpd_SockClose Httpd_Suspend
package require httpd::counter	;# Count CountName
package require httpd::doc_error	;# Doc_Error
package require httpd::threadmgr	;# Thread_Dispatch Thread_Enabled
package require httpd::utils	;# File_Reset file ldelete

# This pattern cannot occur inside a URL path component
# On windows we disallow : to avoid drive-letter attacks

switch $tcl_platform(platform) {
    windows	{ set Url(fsSep) {[/\\:]} }
    macintosh	{ set Url(fsSep) : }
    unix	-
    default	{ set Url(fsSep) / }
}

# Url_Dispatch
#
#	Dispatch to a type-specific handler for a URL
#
# Arguments
#	sock	THe client socket connection
#
# Side Effects
#	Handle the request

proc Url_Dispatch {sock} {
    global Url UrlCache
    upvar #0 Httpd$sock data

    catch {after cancel $data(cancel)}
    set url $data(url)

    CountName $url hit
    if {[catch {

	# INLINE VERSION OF Url_PrefixMatch

	# Collapse multiple // to avoid tricks like //cgi-bin that fail
	# to match the /cgi-bin prefix
	regsub -all /+ $url / url

	if {![regexp ^($Url(prefixset))(.*) $url x prefix suffix] ||
		([string length $suffix] && ![string match /* $suffix])} {

	    # Fall back and assume it is under the root
            if {[string match /* $url]} {
              set suffix [string trimleft $url /]
              set prefix /
            } else {
              # Requested URL doesn't start with slash - bad request
              Httpd_Error $sock 400
              return
            }
	}

	# END INLINE

	# Do access control before dispatch,
	# but after prefix/suffix determination

	set data(prefix) $prefix
	set data(suffix) $suffix
	CountName $prefix domainHit

	foreach hook $Url(accessHooks) {
	    switch -- [eval $hook [list $sock $url]] {
		ok	{ break }
                return  -
		denied	{
		    # A URL implementation should have generated the
		    # appropriate response, such as a 403, to request
		    # a retry. But, if it hasn't, we generate a default.

		    if {![Httpd_RequestComplete $sock]} {
			Httpd_Error $sock 403
		    }
		    return
		}
		skip	{ continue }
	    }
	}

	# Register a callback with the Httpd layer

	if {[info exist Url(callback,$prefix)]} {
	    Httpd_CompletionCallback $sock $Url(callback,$prefix)
	}

	if {[info exist Url(filter,$prefix)]} {
	    Httpd_Filter $sock $Url(filter,$prefix)
	}

	# Pre-read the post data, if the domain wants that

	if {$Url(readpost,$prefix) && $data(count) > 0} {
	    
	    Httpd_ReadPostDataAsync $sock \
		[list Url_DeferredDispatch $prefix $suffix]
	    return
	}

	# Invoke the URL domain handler either in this main thread
	# or in a worker thread

        if {[info exists Url(dispatch,$prefix)]} {
	    Count UrlCustom
	    $Url(dispatch,$prefix) $sock \
		    [concat $Url(command,$prefix) [list $sock $suffix]]
	} elseif {$Url(thread,$prefix)} {
	    Count UrlToThread
	    Thread_Dispatch $sock \
		    [concat $Url(command,$prefix) [list $sock $suffix]]
	} else {
	    Count UrlEval
	    eval $Url(command,$prefix) [list $sock $suffix]
	}
    } error] == 1} {

	# Only do this on uncaught errors.
	# Note that the return statement for the "denied" case of the
	# access hook will result in catch returning code == 2, not 1 (or zero)

	global errorInfo
	global errorCode
	Url_Unwind $sock $errorInfo $errorCode
    }
}

# Url_DeferredDispatch
#
#	Dispatch to a type-specific handler for a URL after the
#	post data has been read.
#
# Arguments
#	sock	The client socket connection
#
# Side Effects
#	Handle the request

proc Url_DeferredDispatch {prefix suffix sock varname errmsg} {
    global Url

    if {[string length $errmsg]} {
	Httpd_SockClose $sock 1 $errmsg
	return
    }
    Url_PostHook $sock 0	;# Turn of Url_ReadPost
    if {[catch {
	# Invoke the URL domain handler either in this main thread
	# or in a worker thread

	if {$Url(thread,$prefix)} {
	    Count UrlToThread
	    Thread_Dispatch $sock \
		    [concat $Url(command,$prefix) [list $sock $suffix]]
	} else {
	    Count UrlEval
	    eval $Url(command,$prefix) [list $sock $suffix]
	}
    } error] == 1} {
	global errorInfo
	global errorCode
	Url_Unwind $sock $errorInfo $errorCode
    }
}

# Url_PrefixMatch
#	Match the domain prefix of a URL
#
# Arguments
#	url	The input URL
#	suffixVar	Output variable, the suffix
#	prefixVar	Output variable, the prefix
#
# Results
#	Fills in prefix and suffix result variables

proc Url_PrefixMatch {url prefixVar suffixVar} {
    global Url
    upvar 1 $prefixVar prefix
    upvar 1 $suffixVar suffix

    # Prefix match the URL to get a domain handler
    # Fast check on domain prefixes with regexp
    # Check that the suffix starts with /, otherwise the prefix
    # is not a complete component.  E.g., "/tcl" vs "/tclhttpd"
    # where /tcl is a domain prefix but /tclhttpd is a directory
    # in the / domain.

    # IF YOU CHANGE THIS  - FIX in-line CODE IN URL_DISPATCH

    # Collapse multiple // to avoid tricks like //cgi-bin that fail
    # to match the /cgi-bin prefix
    regsub -all /+ $url / url

    if {![info exist Url(prefixset)] ||
	    ![regexp ^($Url(prefixset))(.*) $url x prefix suffix] ||
	    ([string length $suffix] && ![string match /* $suffix])} {
	# Fall back and assume it is under the root
        # We assume that Url_Dispatch has filtered out bad urls already
        set suffix [string trimleft $url /]
        set prefix /
    }
}

# Url_PrefixExists
#	Determine if a prefix has been registered.
#
# Arguments
#	prefix	The input URL
#
# Results
#	0 or 1

proc Url_PrefixExists {prefix} {
    global Url
    return [info exist Url(command,$prefix)]
}

# Url_Unwind
#	Do common error handling after a URL request
#
# Arguments
#	sock	The client connection
#	ei	The errorInfo from the command
#	ec	The errorCode from the command
#
# Side Effects
#	Clean up the connection and ensure a reply

proc Url_Unwind {sock ei ec} {

    # URL implementations can raise special errors to unwind their processing.

    set key [lindex $ec 0]
    set error [lindex [split $ei \n] 0]
    switch -- $key {
        HTTPD_REDIRECT {

	    # URL implementations can raise an error and put redirect info
	    # into the errorCode variable, which should be of the form
	    # HTTPD_REDIRECT $newurl

            Httpd_Redirect [lindex $ec 1] $sock
            return
        }
        HTTPD_SUSPEND {
	    
	    # The domain handler has until Httpd(timeout2) to complete this request
	    
            Httpd_Suspend $sock
            return
        }
    }

    switch -glob -- $ei {
	"*can not find channel*"  {
	    Httpd_SockClose $sock 1 $error
	}
	"*too many open files*" {
	    # this is lame and probably not necessary.
	    # Early bugs lead to file descriptor leaks, but
	    # these are all plugged up.
	    Count numfiles
	    Httpd_SockClose $sock 1 $error
	    File_Reset
	} 
	default {
	    Doc_Error $sock $ei
	}
    }
}

# Url_AccessInstall
#
#	Install an access check hook.
#
# Arguments
#	proc	This is a command prefix that is invoked with two additional
#		arguments to check permissions:
#			sock	The handle on the connection
#			url	The url being accessed
#		The access hook should return:
#			"ok"	Meaning access is allowed
#			"denied" Access is denied and the hook is responsible
#				for generating the Authenticate challenge
#			"skip"	Meaning the hook doesn't care about the URL,
#				but perhaps another access control hook does.
#
# Side Effects
#	Save the access control hook

proc Url_AccessInstall {proc} {
    global Url
    if {[lsearch $Url(accessHooks) $proc] < 0} {
	lappend Url(accessHooks) $proc
    }
    return
}

# Url_AccessInstallPrepend
#
#       Exactly like AccessInstall, but puts the hook first in the list

proc Url_AccessInstallPrepend {proc} {
    global Url
    if {[lsearch $Url(accessHooks) $proc] < 0} {
	set Url(accessHooks) [concat $proc $Url(accessHooks)]
    }
    return
}
# Url_AccessUnInstall
#
#       Remove an access control hook
#
# Arguments
#	proc	A procedure previously registered with Url_AccessInstall
#
# Side Effects
#	Remove the access control hook

proc Url_AccessUnInstall {proc} {
    global Url
    set ix [lsearch $Url(accessHooks) $proc]
    if {$ix >= 0} {
	set Url(accessHooks) [lreplace $Url(accessHooks) $ix $ix]
    }
    return
}

if {![info exist Url(accessHooks)]} {
    set Url(accessHooks) {}
}

# Url_PrefixInstall
#	Declare that a handler exists for a point in the URL tree
#	identified by the prefix of all URLs below that point.
#
# Arguments:
#	prefix	The leadin part of the URL, (e.., /foo/bar)
#	command	THe Domain handler command.  This is invoked with one
#		additional arument, $sock, that is the handle identifier
#		A well-known state array is available at
#		upvar #0 Httpd$sock 
#	args	This is either a single boolean that, for backwards
#		compatibility, indicates if the domain handler runs
#		in a thread, or an option-value list of:
#		-thread boolean
#			To indicate the domain handler runs in a thread
#		-callback cmd
#			A callback to make when the request completes
#			with or without error, timeout, etc.
#		-readpost boolean
#			To indicate we should pre-read POST data.
#		-filter cmd
#			A command filter to be run on dynamic content
#               -dispatch cmd
#                       A custom dispatcher.  The receiving command should
#                       accept arguments similar to Thread_Dispatch.

proc Url_PrefixInstall {prefix command args} {
    global Url

    # Add the url to the prefixset, which is a regular expression used
    # to pick off the prefix from the URL

    regsub -all {([][\\().*+?$|])} $prefix {\\\1} prefixquoted

    if {[string compare $prefix "/"] == 0} {
	# / is not in the prefixset because of some special cases.
	# See Url_Dispatch
    } elseif {![info exists Url(prefixset)]} {
	set Url(prefixset) $prefixquoted
    } else {
	set list [split $Url(prefixset) |]
	if {[lsearch $list $prefixquoted] < 0} {
	    lappend list $prefixquoted
	}
	set Url(prefixset) [join [lsort -command UrlSort $list] |]
    }

    # Install the unquoted prefix so the Url dispatch works right

    set Url(command,$prefix) $command

    # Most domains have small amounts of POST data so we read it
    # by default for them.  If you post massive amounts, create
    # a special domain that handles the post data specially.

    set readpost 1

    # Check for options on the domain

    if {[llength $args] == 1} {

	# Compatibility with early 3.* versions that didn't take
	# arbitrary flags

	set tothread [lindex $args 0]
    } else {
	set tothread 0
	foreach {n v} $args {
	    switch -- $n {
		-thread {
		    set tothread $v
		}
		-callback {
		    set Url(callback,$prefix) $v
		}
		-readpost {
		    set readpost $v
		}
		-filter {
		    set Url(filter,$prefix) $v
		}
		-dispatch {
		    set Url(dispatch,$prefix) $v
		}
		default {
		    return -code error "Unknown option $n.\
                        Must be -callback, -dispatch, -filter, -readpost or -thread"
		}
	    }
	}
    }
    set Url(readpost,$prefix) $readpost

    # The decision to use worker threads is done on a domain-by-domain basis
    #
    # Do the check against Thread_Enabled here instead of inside
    # Url_Dispatch.  This means you cannot easily turn
    # threading on and off without restarting the server.

    set Url(thread,$prefix) [expr {[Thread_Enabled] ? $tothread : 0}]
}

# Url_PrefixRemove
#
#	Undo a prefix registration
#
# Arguments:
#	prefix	The leadin part of the URL, (e.., /foo/bar)
#
# Side Effects:
#	Remove the prefix from the dispatch set.

proc Url_PrefixRemove {prefix} {
    global Url

    # Delete the prefix from the regular expression used to match URLs

    regsub -all {([][\\().*+?$|])} $prefix {\\\1} prefixquoted
    set list [split $Url(prefixset) |]
    ldelete list $prefixquoted
    set Url(prefixset) [join [lsort -command UrlSort $list] |]
    if {[info exist Url(command,$prefix)]} {
	unset Url(command,$prefix)
	unset Url(thread,$prefix)
    }
    if {[info exist Url(callback,$prefix)]} {
	unset Url(callback,$prefix)
    }
    if {[info exist Url(filter,$prefix)]} {
	unset Url(filter,$prefix)
    }
}

# UrlSort
#
#	Sort the URL prefixes so the longest ones are first.
#	The makes the regular expression match the longest
#	matching prefix.
#
# Arguments:
#	a, b	To URL prefixes
#
# Results:
#	1 if b should sort before a, -1 if a should sort before b, else 0

proc UrlSort {a b} {
    set la [string length $a]
    set lb [string length $b]
    if {$la == $lb} {
	return [string compare $a $b]
    } elseif {$la < $lb} {
	return 1
    } else {
	return -1
    }
}

# Url_Handle
#
#	Cache the handler for the url, then invoke it
#
# Arguments:
#	cmd	The command to eval to handle a URL
#	sock	The socket for the current connection.
#
# Side Effects:
#	None - used to "Caches the command used to handle the URL"

proc Url_Handle {cmd sock} {
#    upvar #0 Httpd$sock data
#    global UrlCache
#    set UrlCache($data(url)) $cmd
    eval $cmd [list $sock]
}

# Url_UnCache
#
#	Deleted the cached handler for a URL
#
# Arguments:
#	sock	The socket for the current connection.
#	force	If set, there is no special case for the redirect hack
#
# Side Effects:
#	Deletes the cached handler

proc Url_UnCache {sock {force 0}} {
    upvar #0 Httpd$sock data
    global UrlCache
    if {[info exists UrlCache($data(url))]} {
	set redirect [regexp Redirect $UrlCache($data(url))]
	if {$force || !$redirect} {
	    unset UrlCache($data(url))
	}
    }
}

# Url_PathCheck
#
#	Validate a pathname.  Make sure it doesn't sneak out of its domain.
#
# Arguments:
#	urlsuffix	The URL after the domain prefix
#
# Results:
#	Raises an error, or returns a list of components in the pathname

proc Url_PathCheck {urlsuffix} {
    global Url
    set pathlist ""
    foreach part  [split $urlsuffix /] {
	if {[string length $part] == 0} {

	    # It is important *not* to "continue" here and skip
	    # an empty component because it could be the last thing,
	    # /a/b/c/
	    # which indicates a directory.  In this case you want
	    # Auth_Check to recurse into the directory in the last step.

	}
	set part [Url_Decode $part]

	# Disallow Mac and UNIX path separators in components
	# Windows drive-letters are bad, too

	if {[regexp $Url(fsSep) $part]} {
	    error "URL components cannot include $Url(fsSep)"
	}
	switch -- $part {
	    .  { }
	    .. {
		set len [llength $pathlist]
		if {[incr len -1] < 0} {
		    error "URL out of range"
		}
		set pathlist [lrange $pathlist 0 [incr len -1]]
	    }
	    default {
		lappend pathlist $part
	    }
	}
    }
    return $pathlist
}

proc Url_PostHook {sock length} {
    global Url

    # Backdoor hack for Url_DecodeQuery compatibility
    # We remember the current connection so that Url_DecodeQuery
    # can read the post data if it has not already been read by
    # the time it is called.

    set Url(sock) $sock
    set Url(postlength) $length
}

# convert a x-www-urlencoded string into a list of name/value pairs

proc Url_DecodeQuery {query args} {
    global Url

    if {[info exist Url(sock)]} {
	Url_ReadPost $Url(sock) query
    }
    Url_DecodeQueryOnly $query {*}$args
}

# Url_QuerySetup --
#
#	Grab any query data and pass it to the ncgi:: module.
#
# Arguments:
# 	sock	The socket back to the client.
#
# Results:
#	None
#
# Side effects:
#	ncgi::reset, ncgi::parse, ncgi::urlstup

proc Url_QuerySetup {sock} {
    upvar #0 Httpd$sock data

    set valuelist {}

    # search for comma separeted pair of numbers
    # as generated from server side map
    #      e.g 190,202
    # Bjorn Ruff.

    if { [regexp {^([0-9]+),([0-9]+)$} $data(query) match x y]} {
	set data(query) x=$x&y=$y
    }

    # Honor content type of the query data
    # Some browsers leave junk Content-Type lines in
    # non-post requests as a side effect of keep alive.

    if {[info exist data(mime,content-type)] &&
	    ("$data(proto)" != "GET")} {
	set type $data(mime,content-type)
    } else {
	set type application/x-www-urlencoded
    }

    # Grab POST data, if any, and initialize the ncgi:: interface

    Url_ReadPost $sock data(query)
    ncgi::reset $data(query) $type
    ncgi::parse
    ncgi::urlStub $data(url)
    return
}

proc Url_ReadPost {sock varname} {
    upvar 1 $varname query
    global Url

    append query ""
    if {[info exist Url(postlength)] && ($Url(postlength) > 0)} {
	
	# For compatibility with older versions of the Httpd module
	# that used to read all the post data for us, we read it now
	# if it hasn't already been read

	set result $Url(postlength)
	if {[string length $query]} {
	    # This merges query data from the GET/POST URL
	    append query &
	}
	while {$Url(postlength) > 0} {
	    set Url(postlength) [Httpd_GetPostData $sock query]
	}
	unset Url(postlength)
	return $result
    } else {
	return 0
    }
}

proc Url_DecodeQueryOnly {query args} {

    array set options {-type application/x-www-urlencoded -qualifiers {}}
    catch {array set options $args}
    if {[string length [info command Url_DecodeQuery_$options(-type)]] == 0} {
	set options(-type) application/x-www-urlencoded
    }
    return [Url_DecodeQuery_$options(-type) $query $options(-qualifiers)]
}

proc Url_DecodeQuery_application/x-www-urlencoded {query qualifiers} {

    # These foreach loops are structured this way to ensure there are matched
    # name/value pairs.  Sometimes query data gets garbled.

    set result {}
    foreach pair [split $query "&"] {
	foreach {name value} [split $pair "="] {
	    lappend result [Url_Decode $name] [Url_Decode $value]
	}
    }
    return $result
}
proc Url_Decode {data} {
    regsub -all {\+} $data " " data
    regsub -all {([][$\\])} $data {\\\1} data
    regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data  {[format %c 0x\1]} data
    return [subst $data]
}
if 0 {
    proc UrlDecodeData {data} {
	regsub -all {([][$\\])} $data {\\\1} data
	regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data  {[format %c 0x\1]} data
	return [subst $data]
    }
}


# Sharing procedure bodies doesn't work with compiled procs,
# so these call each other instead of doing
# proc xprime [info args x] [info body x]

proc Url_DecodeQuery_application/x-www-form-urlencoded {query qualifiers} {
    Url_DecodeQuery_application/x-www-urlencoded $query $qualifiers
}

# steve: 5/8/98: This is a very crude start at parsing MIME documents
# Return filename/content pairs
proc Url_DecodeQuery_multipart/form-data {query qualifiers} {

    array set options {}
    catch {array set options $qualifiers}
    if {![info exists options(boundary)]} {
	return -code error "no boundary given for multipart document"
    }

    # Filter query into a list
    # Protect Tcl special characters
    # regsub -all {([\\{}])} $query {\\\\\\1} query
    regsub -all {(\\)}  $query {\\\\\\001} query
    regsub -all {(\{)}  $query {\\\\\\002} query
    regsub -all {(\})}  $query {\\\\\\003} query
    regsub -all -- "(\r?\n?--)?$options(boundary)\r?\n?" $query "\} \{" data
    set data [subst -nocommands -novariables "\{$data\}"]

    # Remove first and last list elements, which will be empty
    set data [lrange [lreplace $data end end] 1 end]

    set result {}
    foreach element $data {

	# Get the headers from the element.  Look for the first empty line.
	set headers {}
	set elementData {}
	# Protect Tcl special characters
	# regsub -all {([\\{}])} $element {\\\\\\1} element
	regsub -all {(\\)}  $element {\\\\\\001} element
	regsub -all {(\{)}  $element {\\\\\\002} element
	regsub -all {(\})}  $element {\\\\\\003} element
	regsub \r?\n\r?\n $element "\} \{" element

	foreach {headers elementData} [subst -nocommands -novariables "\{$element\}"] break

	set headerList {}
	set parameterName {}
	regsub -all \r $headers {} headers
	foreach hdr [split $headers \n] {

	    if {[string length $hdr]} {

		set headerName {}
		set headerData {}
		if {![regexp {[ 	]*([^: 	]+)[ 	]*:[ 	]*(.*)} $hdr discard headerName headerData]} {
		    return -code error "malformed MIME header \"$hdr\""
		}

		set headerName [string tolower $headerName]
		foreach {major minor quals} [Url_DecodeMIMEField $headerData] break
		# restore Tcl special characters
	    regsub -all {(\\\001\001)} $quals {\\} quals
	    regsub -all {(\\\001\002)} $quals {\{} quals
	    regsub -all {(\\\001\003)} $quals {\}} quals

		switch -glob -- [string compare content-disposition $headerName],[string compare form-data $major] {

		    0,0 {

			# This is the name for this query parameter

			catch {unset param}
			array set param $quals
			set parameterName $param(name)

			# Include the remaining parameters, if any
			unset param(name)
			if {[llength [array names param]]} {
			    lappend headerList [list $headerName $major [array get param]]
			}

		    }

		    default {

			lappend headerList [list $headerName $major/$minor $quals]

		    }

		}

	    } else {
		break
	    }
	}
	# restore Tcl special characters
	regsub -all {(\\\001\001)} $elementData {\\} elementData
	regsub -all {(\\\001\002)} $elementData "{" elementData
	regsub -all {(\\\001\003)} $elementData "}" elementData
	lappend result $parameterName [list $headerList $elementData]
    }

    return $result
}

# Decode a MIME type
# This could possibly move into the MIME module

proc Url_DecodeMIMEField type {
    set qualList {}
    if {[regexp {([^;]+)[ 	]*;[ 	]*(.+)} $type discard type qualifiers]} {
	foreach qualifier [split $qualifiers \;] {
	    if {[regexp {[ 	]*([^=]+)="([^"]*)"} $qualifier discard name value]} {
	    } elseif {[regexp {[ 	]*([^=]+)='([^']*)'} $qualifier discard name value]} {
	    } elseif {[regexp {[ 	]*([^=]+)=([^ 	]*)} $qualifier discard name value]} {
	    } else {
		continue
	    }
	    lappend qualList $name $value
	}
    }
    foreach {major minor} [split $type /] break
    return [list [string trim $major] [string trim $minor] $qualList]
}

# do x-www-urlencoded character mapping
# The spec says: "non-alphanumeric characters are replaced by '%HH'"
 
for {set i 1} {$i <= 256} {incr i} {
    set c [format %c $i]
    if {![string match \[a-zA-Z0-9\] $c]} {
        set UrlEncodeMap($c) %[format %.2x $i]
    }
}
 
# These are handled specially
array set UrlEncodeMap {
    " " +   \n %0d%0a
}
 
# 1 leave alphanumerics characters alone
# 2 Convert every other character to an array lookup
# 3 Escape constructs that are "special" to the tcl parser
# 4 "subst" the result, doing all the array substitutions
 
proc Url_Encode {string} {
    global UrlEncodeMap 
    regsub -all \[^a-zA-Z0-9\] $string {$UrlEncodeMap(&)} string
    regsub -all \n $string {\\n} string
    regsub -all \t $string {\\t} string
    regsub -all {[][{})\\]\)} $string {\\&} string
    return [subst $string]
}
 
# Url_IsLinkToSelf
#	Compare the link to the URL of the current page.
#	If they seem to be the same thing, return 1
#
# Arguments:
#	url	The URL to compare with.
#
# Results:
#	1 if the input URL seems to be equivalent to the page's URL.
#
# Side Effects:
#	None

proc Url_IsLinkToSelf {url} {
    global page
    return [expr {[string compare $url $page(url)] == 0}]
}

Added modules/httpd/utils.tcl.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
# utils.tcl
#
# Brent Welch (c) 1998-2000 Ajuba Solutions
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: utils.tcl,v 1.14 2004/10/22 03:43:06 coldstore Exp $

package provide httpd::utils 1.0

package require httpd::log	;# Log_SetFile

# Stderr - print to standard error

proc Stderr {string} {
    catch {puts stderr $string}
}

# iscommand - returns true if the command is defined  or lives in auto_index.

proc iscommand {name} {
    expr {([string length [info command $name]] > 0) || [auto_load $name]}
}

# lappendOnce - add to a list if not already there

proc lappendOnce {listName value} {
    upvar $listName list
    if {![info exists list]} {
	lappend list $value
    } else {
	set ix [lsearch $list $value]
	if {$ix < 0} {
	    lappend list $value
	}
    }
}

# setmax - set the variable to the maximum of its current value
# or the value of the second argument
# return 1 if the variable's value was changed.

proc setmax {varName value} {
    upvar $varName var
    if {![info exists var] || ($value > $var)} {
	set var $value
	return 1
    } 
    return 0
}

# setmin - set the variable to the minimum of its current value
# or the value of the second argument
# return 1 if the variable's value was changed.

proc setmin {varName value} {
    upvar $varName var
    if {![info exists var] || ($value < $var)} {
	set var $value
	return 1
    } 
    return 0
}

# Incr - version of incr that handles undefined variables.

proc Incr {varName {value 1}} {
    upvar $varName var
    if {![info exists var]} {
	set var $value
    }  else {
	set var [expr $var + $value]
    }
}

# Delete a list item by value.  Returns 1 if the item was present, else 0

proc ldelete {varList value} {
    upvar $varList list
    if {![info exist list]} {
	return 0
    }
    set ix [lsearch $list $value]
    if {$ix >= 0} {
	set list [lreplace $list $ix $ix]
	return 1
    } else {
	return 0
    }
}

# see if an option matches a list of options
# return full option name if it does, otherwise ""
#  option:  the name of the option (or unique prefix)
#  list:    the list of valid options (e.g. -foo -bar ...)

proc matchOption {option list} {
    if {![regexp -- {-[a-zA-Z0-9:_-]+} $option]} {
    	error "Invalid option: \"$option\""
    }
    if {[regsub -all -- "$option\[^ \]*" $list {} {}] == 1} {
    	regexp -- "$option\[^ \]*" $list result
    	return $result
    } else {
    	return ""
    }
}

# Set local variables based on defaults - passed in as an array, and
# a set of name value pairs.  The "params" always override the current setting
# of the local variables; the defaults only get set if no vars exist.
#   array: name of the array (with default values)
#   params:  The "-name value" pairs to set

proc optionSet {array params} {
    upvar $array options
    set list [array names options -*]
    foreach {option value} $params {
	set realoption [matchOption $option $list]
	if {$realoption != ""} {
	    regexp -- {-(.*)} $realoption {} var
	    uplevel [list set $var $value]
	}
    }

    foreach {name value} [array get options -*] {
	regexp -- {-(.*)} $name {} var
	upvar $var set
	if {![info exists set]} {
	    uplevel [list set $var $value]
	}
    }
}

# "configure" for options in an array
#   name:  The name of the array containing the options
#   args:  The name value pairs

proc optionConfigure {name args} {
    upvar $name data

    set len [llength $args]
    set list [array names data -*]
    if {$len > 1 && ($len % 2) == 1} {
    	return -code error "optionConfigure Must have 1 or even number of arguments"
    }
    set result ""

    # return entire configuration list

    if {$len == 0} {
    	foreach option [lsort $list] {
	    lappend result $option $data($option)
	}

    # return a single configuration value

    } elseif {$len == 1} {
    	set option [matchOption $args $list]
    	if {$option == ""} {
	    return -code error "$args is an invalid option, should be one of: [join $list ", "]."
	}
	set result $data($option)

    # Set a bunch of options

    } else {
    	foreach {option value} $args {
	    set realoption [matchOption $option $list]
	    if {$realoption == ""} {
		return -code error "$option is an invalid option, should be one of: [join $list ", "]."
	    }
	    if {[info exists data(validate$realoption)]} {
	    	eval $data(validate$realoption) {data $realoption $value}
	    } else {
		set data($realoption) $value
	    }
	}
    }
    return $result
}


# print an import array 

proc poptions {array args} {
    upvar $array data
    puts "*** $array *** $args"
    foreach name [array names data] {
    	regexp -- {-(.*)} $name {} var
    	upvar $var value
    	if {[info exists value]} {
	    puts "${array}($var) = $value"
    	} else {
	    puts "${array}($var) = <unset>"
    	}
    }
}
# simple random number generator snagged from the net

set RNseed [pid]
proc randomx {} {
    global RNseed
    set RNseed [expr 30903*($RNseed&65535)+($RNseed>>16)]
    return [format %.4x [expr int(32767*($RNseed & 65535)/65535.0)]]
} 

# escape html characters (simple version)

proc protect_text {text} {
    array set Map { < lt   > gt   & amp   \" quot}
    regsub -all {[\\$]} $text {\\&} text
    regsub -all {[><&"]} $text {\&$Map(&);} text
    subst -nocommands $text
}

# File_Reset - hack to close files after a leak has sprung

proc File_Reset {} {
    for {set i 5} {$i <= 1025} {incr i} {
	if {! [catch {close file$i}]} {
	    append result file$i\n
	}
    }
    for {set i 10} {$i <= 1025} {incr i} {
	if {! [catch {close sock$i}]} {
	    append result sock$i\n
	}
    }
    Log_SetFile
    return $result
}

# File_List - report which files are open.

proc File_List {} {
    global OpenFiles
    for {set i 1} {$i <= 1025} {incr i} {
	if {! [catch {fconfigure file$i} conf]} {
	    append result "file$i $conf\n"
	    if {[info exist OpenFiles(file$i)]} {
		append result "file$i: $OpenFiles(file$i)\n"
	    }
	}
	if {! [catch {fconfigure sock$i} conf]} {
	    array set c {-peername {} -sockname {}}
	    array set c $conf
	    append result "sock$i $c(-peername) $c(-sockname)\n"
	}
    }
    return $result
}

# parray - version of parray that returns the result instead
# of printing it out.

proc parray {aname {pat *}} {
    upvar $aname a
    foreach name [array names a $pat] {
	setmax max [string length $name]
    }
    if {![info exists max]} {
	return {}
    }
    incr max [string length $aname]
    incr max 2
    set result {}
    foreach name [lsort [array names a $pat]] {
	append result [list set ${aname}($name) $a($name)]
	append result \n
    }
    return $result
}

#
# Example 27-3
# Listbox with optional scrollbars.
#

proc Scrolled_Listbox { f args } {
	frame $f
	listbox $f.list \
		-xscrollcommand [list Scroll_Set $f.xscroll \
			[list grid $f.xscroll -row 1 -column 0 -sticky we]] \
		-yscrollcommand [list Scroll_Set $f.yscroll \
			[list grid $f.yscroll -row 0 -column 1 -sticky ns]]
	$f.list configure {*}$args
	scrollbar $f.xscroll -orient horizontal \
		-command [list $f.list xview]
	scrollbar $f.yscroll -orient vertical \
		-command [list $f.list yview]
	grid $f.list $f.yscroll -sticky news
	grid $f.xscroll -sticky news
	grid rowconfigure $f 0 -weight 1
	grid columnconfigure $f 0 -weight 1
	return $f.list
}


#
# Example 27-1
# A text widget and two scrollbars.
#

proc Scrolled_Text { f args } {
	frame $f
	eval {text $f.text \
		-xscrollcommand [list $f.xscroll set] \
		-yscrollcommand [list $f.yscroll set]} $args
	scrollbar $f.xscroll -orient horizontal \
		-command [list $f.text xview]
	scrollbar $f.yscroll -orient vertical \
		-command [list $f.text yview]
	grid $f.text $f.yscroll -sticky news
	grid $f.xscroll -sticky news
	grid rowconfigure $f 0 -weight 1
	grid columnconfigure $f 0 -weight 1
	return $f.text
}

#
# Example 27-2
# Scroll_Set manages optional scrollbars.
#

proc Scroll_Set {scrollbar geoCmd offset size} {
	if {$offset != 0.0 || $size != 1.0} {
		eval $geoCmd					;# Make sure it is visible
		$scrollbar set $offset $size
	} else {
		set manager [lindex $geoCmd 0]
		$manager forget $scrollbar								;# hide it
	}
}

#
# Example 31-1
# A large scrolling canvas.
#

proc Scrolled_Canvas { c args } {
	frame $c
	eval {canvas $c.canvas \
		-xscrollcommand [list $c.xscroll set] \
		-yscrollcommand [list $c.yscroll set] \
		-highlightthickness 0 \
		-borderwidth 0} $args
	scrollbar $c.xscroll -orient horizontal \
		-command [list $c.canvas xview]
	scrollbar $c.yscroll -orient vertical \
		-command [list $c.canvas yview]
	grid $c.canvas $c.yscroll -sticky news
	grid $c.xscroll -sticky ew
	grid rowconfigure $c 0 -weight 1
	grid columnconfigure $c 0 -weight 1
	return $c.canvas
}


proc ChopLine {line {limit 72}} {
    regsub -all " *\n" $line " " line
    set new {}
    while {[string length $line] > $limit} {
	set hit 0
	for {set c $limit} {$c >= 0} {incr c -1} {
	    set char [string index $line $c]
	    if {[regexp \[\ \t\n>/\] $char]} {
		set hit 1
		break
	    }
	}
	if !$hit {
	    set c $limit
	}
	append new [string trimright [string range $line 0 $c]]\n
	incr c
	set line [string range $line $c end]
    }
    append new "$line"
    return $new
}

# boolean --
#
#	Convert boolean values to 0/1
#
# Arguments:
#	value	boolean value: true/false, on/off, yes/no, etc
#
# Results:
#	Returns 0 or 1.

proc boolean value {
    if {!([regsub -nocase {^(1|yes|true|on)$} $value 1 value] || \
	  [regsub -nocase {^(0|no|false|off)$} $value 0 value])} {
	error "boolean value expected"
    }
    return $value
}


# file_latest --
#
#	Return the newest file from the list.
#
# Arguments:
#	files	A list of filenames.
#
# Results:
#	None
#
# Side Effects:
#	The name of the newest file.

proc file_latest {files} {
    set newest {}
    foreach file $files {
	if {[file readable $file]} {
	    set m [file mtime $file]
	    if {![info exist mtime] || ($m > $mtime)} {
		set mtime $m
		set newest $file
	    }
	}
    }
    return $newest
}

if {([package vcompare [package provide Tcl] 7.6] < 0)
    && [string match unix $tcl_platform(platform)]} {

    # The subcommands copy, delete, rename, and mkdir were added to
    # the Tcl command 'file' in Tcl version 7.6.  The following command
    # approximates them on Unix platforms.  It may not agree with
    # the Tcl 7.6+ command 'file' in all of its functionality (notably
    # the way it reports errors).  Further refinements should be made as
    # needed.
    rename file Tcl7.5_file
    proc file {option args} {
        switch -glob -- $option {
            c* {
                if {[string first $option copy] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                # Translate -force into -f
                if {[string match -force [lindex $args 0]]} {
                    set args [lreplace $args 0 0 -f]
                }
                uplevel exec cp $args
            }
            de* {
                if {[string first $option delete] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                if {[string match -force [lindex $args 0]]} {
                    set args [lreplace $args 0 0 -f]
                }
                catch {uplevel exec rm $args}
            }
            mk* {
                if {[string first $option mkdir] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                uplevel exec mkdir $args
            }
            ren* {
                if {[string first $option rename] != 0} {
                    return [uplevel [list Tcl7.5_file $option] $args]
                }
                if {[string match -force [lindex $args 0]]} {
                    set args [lreplace $args 0 0 -f]
                }
                uplevel exec mv $args
            }
            default {
                uplevel [list Tcl7.5_file $option] $args
            }
        }
    }
}

if {[package vcompare [package provide Tcl] 8] < 0} {
    
    # The subcommands nativename and attributes were added to
    # the Tcl command 'file' in Tcl version 8.0.  Here is an approximation
    # for earlier Tcl versions:
    rename file Tcl7.6_file
    ;proc file {option args} {
        switch -glob -- $option {
            att* {
                if {[string first $option attributes] != 0} {
                    uplevel [list Tcl7.6_file $option] $args
                }
                return -code error "Tcl [package provide Tcl] does not support\
			\[file attributes\].\n\tUpgrade to Tcl 8.0 to use it."
            }
            n* {
                if {[string first $option nativename] != 0} {
                    uplevel [list Tcl7.6_file $option] $args
                }
                if {![llength $args]} {
                    return -code error "wrong # args: should be\
                	    \"file nativename name ?arg ...?\""
                }
                set fcomps [file split [lindex $args 0]]
                # Take care of tilde substitution
                set first [lindex $fcomps 0]
                if {[string match ~* $first]} {
                    set first [file join [file dirname $first] [file tail $first]]
                }
                set result [eval file join [list $first] [lrange $fcomps 1 end]]
                global tcl_platform
                if {[string match windows $tcl_platform(platform)]} {
                    regsub -all -- / $result \\ result
                }
                return $result
            }
            default {
                uplevel [list Tcl7.6_file $option] $args
            }
        }
    }
}

if {[package vcompare [package provide Tcl] 8.4] < 0} {
    # The subcommands nativename and attributes were added to
    # the Tcl command 'file' in Tcl version 8.0.  Here is an approximation
    # for earlier Tcl versions:
    rename file Tcl8.0_file
    ;proc file {option args} {
        switch -glob -- $option {
	    norm* {
		set sp [file split [lindex $args 0]]
		if {[file pathtype [lindex $sp 0]] == "relative"} {
		    set sp [file split [eval [list file join [pwd]] $sp]]
		}
		set np {}
		foreach ele $sp {
		    if {$ele != ".."} {
			if {$ele != "."} { lappend np $ele }
		    } elseif {[llength $np]> 1} {
			set np [lrange $np 0 [expr {[llength $np] - 2}]]
		    }
		}
		if {[llength $np] > 0} { return [eval file join $np] }
	    }
	    default {
		uplevel [list Tcl8.0_file $option] $args
	    }
	}
    }
}

# see http://mini.net/tcl/lambda
proc K {a b} {set a}
proc lambda {argl body} {K [info level 0] [proc [info level 0] $argl $body]}

Added modules/httpd/version.tcl.











>
>
>
>
>
1
2
3
4
5
package provide httpd::version 4.0
proc Httpd_Version {} {
    global Httpd
    set Httpd(version)	"4.0.0 FOS"
}

Added modules/jshash/js/md5-min.js.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */
var hexcase=0;function hex_md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(c%32))&255)}return a}function binl_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g<p.length;g+=16){var j=o;var h=n;var f=m;var e=l;o=md5_ff(o,n,m,l,p[g+0],7,-680876936);l=md5_ff(l,o,n,m,p[g+1],12,-389564586);m=md5_ff(m,l,o,n,p[g+2],17,606105819);n=md5_ff(n,m,l,o,p[g+3],22,-1044525330);o=md5_ff(o,n,m,l,p[g+4],7,-176418897);l=md5_ff(l,o,n,m,p[g+5],12,1200080426);m=md5_ff(m,l,o,n,p[g+6],17,-1473231341);n=md5_ff(n,m,l,o,p[g+7],22,-45705983);o=md5_ff(o,n,m,l,p[g+8],7,1770035416);l=md5_ff(l,o,n,m,p[g+9],12,-1958414417);m=md5_ff(m,l,o,n,p[g+10],17,-42063);n=md5_ff(n,m,l,o,p[g+11],22,-1990404162);o=md5_ff(o,n,m,l,p[g+12],7,1804603682);l=md5_ff(l,o,n,m,p[g+13],12,-40341101);m=md5_ff(m,l,o,n,p[g+14],17,-1502002290);n=md5_ff(n,m,l,o,p[g+15],22,1236535329);o=md5_gg(o,n,m,l,p[g+1],5,-165796510);l=md5_gg(l,o,n,m,p[g+6],9,-1069501632);m=md5_gg(m,l,o,n,p[g+11],14,643717713);n=md5_gg(n,m,l,o,p[g+0],20,-373897302);o=md5_gg(o,n,m,l,p[g+5],5,-701558691);l=md5_gg(l,o,n,m,p[g+10],9,38016083);m=md5_gg(m,l,o,n,p[g+15],14,-660478335);n=md5_gg(n,m,l,o,p[g+4],20,-405537848);o=md5_gg(o,n,m,l,p[g+9],5,568446438);l=md5_gg(l,o,n,m,p[g+14],9,-1019803690);m=md5_gg(m,l,o,n,p[g+3],14,-187363961);n=md5_gg(n,m,l,o,p[g+8],20,1163531501);o=md5_gg(o,n,m,l,p[g+13],5,-1444681467);l=md5_gg(l,o,n,m,p[g+2],9,-51403784);m=md5_gg(m,l,o,n,p[g+7],14,1735328473);n=md5_gg(n,m,l,o,p[g+12],20,-1926607734);o=md5_hh(o,n,m,l,p[g+5],4,-378558);l=md5_hh(l,o,n,m,p[g+8],11,-2022574463);m=md5_hh(m,l,o,n,p[g+11],16,1839030562);n=md5_hh(n,m,l,o,p[g+14],23,-35309556);o=md5_hh(o,n,m,l,p[g+1],4,-1530992060);l=md5_hh(l,o,n,m,p[g+4],11,1272893353);m=md5_hh(m,l,o,n,p[g+7],16,-155497632);n=md5_hh(n,m,l,o,p[g+10],23,-1094730640);o=md5_hh(o,n,m,l,p[g+13],4,681279174);l=md5_hh(l,o,n,m,p[g+0],11,-358537222);m=md5_hh(m,l,o,n,p[g+3],16,-722521979);n=md5_hh(n,m,l,o,p[g+6],23,76029189);o=md5_hh(o,n,m,l,p[g+9],4,-640364487);l=md5_hh(l,o,n,m,p[g+12],11,-421815835);m=md5_hh(m,l,o,n,p[g+15],16,530742520);n=md5_hh(n,m,l,o,p[g+2],23,-995338651);o=md5_ii(o,n,m,l,p[g+0],6,-198630844);l=md5_ii(l,o,n,m,p[g+7],10,1126891415);m=md5_ii(m,l,o,n,p[g+14],15,-1416354905);n=md5_ii(n,m,l,o,p[g+5],21,-57434055);o=md5_ii(o,n,m,l,p[g+12],6,1700485571);l=md5_ii(l,o,n,m,p[g+3],10,-1894986606);m=md5_ii(m,l,o,n,p[g+10],15,-1051523);n=md5_ii(n,m,l,o,p[g+1],21,-2054922799);o=md5_ii(o,n,m,l,p[g+8],6,1873313359);l=md5_ii(l,o,n,m,p[g+15],10,-30611744);m=md5_ii(m,l,o,n,p[g+6],15,-1560198380);n=md5_ii(n,m,l,o,p[g+13],21,1309151649);o=md5_ii(o,n,m,l,p[g+4],6,-145523070);l=md5_ii(l,o,n,m,p[g+11],10,-1120210379);m=md5_ii(m,l,o,n,p[g+2],15,718787259);n=md5_ii(n,m,l,o,p[g+9],21,-343485551);o=safe_add(o,j);n=safe_add(n,h);m=safe_add(m,f);l=safe_add(l,e)}return Array(o,n,m,l)}function md5_cmn(h,e,d,c,g,f){return safe_add(bit_rol(safe_add(safe_add(e,h),safe_add(c,f)),g),d)}function md5_ff(g,f,k,j,e,i,h){return md5_cmn((f&k)|((~f)&j),g,f,e,i,h)}function md5_gg(g,f,k,j,e,i,h){return md5_cmn((f&j)|(k&(~j)),g,f,e,i,h)}function md5_hh(g,f,k,j,e,i,h){return md5_cmn(f^k^j,g,f,e,i,h)}function md5_ii(g,f,k,j,e,i,h){return md5_cmn(k^(f|(~j)),g,f,e,i,h)}function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))};

Added modules/jshash/js/md5.js.























































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;   /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = "";  /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s)    { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
function b64_md5(s)    { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
function hex_hmac_md5(k, d)
  { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_md5(k, d)
  { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_md5(k, d, e)
  { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of a raw string
 */
function rstr_md5(s)
{
  return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}

/*
 * Calculate the HMAC-MD5, of a key and some data (raw strings)
 */
function rstr_hmac_md5(key, data)
{
  var bkey = rstr2binl(key);
  if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
  return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  try { hexcase } catch(e) { hexcase=0; }
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  try { b64pad } catch(e) { b64pad=''; }
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var i, j, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(Math.ceil(input.length / 2));
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. All remainders are stored for later
   * use.
   */
  var full_length = Math.ceil(input.length * 8 /
                                    (Math.log(encoding.length) / Math.log(2)));
  var remainders = Array(full_length);
  for(j = 0; j < full_length; j++)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[j] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of little-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binl(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
  return output;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
  return output;
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length.
 */
function binl_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);
}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

Added modules/jshash/js/ripemd160-min.js.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
/*
 * A JavaScript implementation of the RIPEMD-160 Algorithm
 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 * Also http://www.esat.kuleuven.ac.be/~cosicart/pdf/AB-9601/
 */
var hexcase=0;function hex_rmd160(a){return rstr2hex(rstr_rmd160(str2rstr_utf8(a)))}function hex_hmac_rmd160(a,b){return rstr2hex(rstr_hmac_rmd160(str2rstr_utf8(a),str2rstr_utf8(b)))}function rmd160_vm_test(){return hex_rmd160("abc").toLowerCase()=="8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"}function rstr_rmd160(a){return binl2rstr(binl_rmd160(rstr2binl(a),a.length*8))}function rstr_hmac_rmd160(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_rmd160(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_rmd160(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_rmd160(d.concat(g),512+160))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(c%32))&255)}return a}function binl_rmd160(q,v){q[v>>5]|=128<<(v%32);q[(((v+64)>>>9)<<4)+14]=v;var l=1732584193;var k=4023233417;var h=2562383102;var g=271733878;var f=3285377520;for(var u=0;u<q.length;u+=16){var e;var c=l,o=k,t=h,d=g,p=f;var a=l,m=k,s=h,b=g,n=f;for(var r=0;r<=79;++r){e=safe_add(c,rmd160_f(r,o,t,d));e=safe_add(e,q[u+rmd160_r1[r]]);e=safe_add(e,rmd160_K1(r));e=safe_add(bit_rol(e,rmd160_s1[r]),p);c=p;p=d;d=bit_rol(t,10);t=o;o=e;e=safe_add(a,rmd160_f(79-r,m,s,b));e=safe_add(e,q[u+rmd160_r2[r]]);e=safe_add(e,rmd160_K2(r));e=safe_add(bit_rol(e,rmd160_s2[r]),n);a=n;n=b;b=bit_rol(s,10);s=m;m=e}e=safe_add(k,safe_add(t,b));k=safe_add(h,safe_add(d,n));h=safe_add(g,safe_add(p,a));g=safe_add(f,safe_add(c,m));f=safe_add(l,safe_add(o,s));l=e}return[l,k,h,g,f]}function rmd160_f(b,a,d,c){return(0<=b&&b<=15)?(a^d^c):(16<=b&&b<=31)?(a&d)|(~a&c):(32<=b&&b<=47)?(a|~d)^c:(48<=b&&b<=63)?(a&c)|(d&~c):(64<=b&&b<=79)?a^(d|~c):"rmd160_f: j out of range"}function rmd160_K1(a){return(0<=a&&a<=15)?0:(16<=a&&a<=31)?1518500249:(32<=a&&a<=47)?1859775393:(48<=a&&a<=63)?2400959708:(64<=a&&a<=79)?2840853838:"rmd160_K1: j out of range"}function rmd160_K2(a){return(0<=a&&a<=15)?1352829926:(16<=a&&a<=31)?1548603684:(32<=a&&a<=47)?1836072691:(48<=a&&a<=63)?2053994217:(64<=a&&a<=79)?0:"rmd160_K2: j out of range"}var rmd160_r1=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13];var rmd160_r2=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11];var rmd160_s1=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6];var rmd160_s2=[8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11];function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))};

Added modules/jshash/js/ripemd160.js.















































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
/*
 * A JavaScript implementation of the RIPEMD-160 Algorithm
 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_rmd160(s)    { return rstr2hex(rstr_rmd160(str2rstr_utf8(s))); }
function b64_rmd160(s)    { return rstr2b64(rstr_rmd160(str2rstr_utf8(s))); }
function any_rmd160(s, e) { return rstr2any(rstr_rmd160(str2rstr_utf8(s)), e); }
function hex_hmac_rmd160(k, d)
  { return rstr2hex(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_rmd160(k, d)
  { return rstr2b64(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_rmd160(k, d, e)
  { return rstr2any(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function rmd160_vm_test()
{
  return hex_rmd160("abc").toLowerCase() == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc";
}

/*
 * Calculate the rmd160 of a raw string
 */
function rstr_rmd160(s)
{
  return binl2rstr(binl_rmd160(rstr2binl(s), s.length * 8));
}

/*
 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
 */
function rstr_hmac_rmd160(key, data)
{
  var bkey = rstr2binl(key);
  if(bkey.length > 16) bkey = binl_rmd160(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binl_rmd160(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
  return binl2rstr(binl_rmd160(opad.concat(hash), 512 + 160));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  try { hexcase } catch(e) { hexcase=0; }
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  try { b64pad } catch(e) { b64pad=''; }
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var remainders = Array();
  var i, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(Math.ceil(input.length / 2));
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. We stop when the dividend is zero.
   * All remainders are stored for later use.
   */
  while(dividend.length > 0)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[remainders.length] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  /* Append leading zero equivalents */
  var full_length = Math.ceil(input.length * 8 /
                                    (Math.log(encoding.length) / Math.log(2)))
  for(i = output.length; i < full_length; i++)
    output = encoding[0] + output;

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of little-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binl(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
  return output;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
  return output;
}

/*
 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
 */
function binl_rmd160(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << (len % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var h0 = 0x67452301;
  var h1 = 0xefcdab89;
  var h2 = 0x98badcfe;
  var h3 = 0x10325476;
  var h4 = 0xc3d2e1f0;

  for (var i = 0; i < x.length; i += 16) {
    var T;
    var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
    var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
    for (var j = 0; j <= 79; ++j) {
      T = safe_add(A1, rmd160_f(j, B1, C1, D1));
      T = safe_add(T, x[i + rmd160_r1[j]]);
      T = safe_add(T, rmd160_K1(j));
      T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
      A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
      T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
      T = safe_add(T, x[i + rmd160_r2[j]]);
      T = safe_add(T, rmd160_K2(j));
      T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
      A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
    }
    T = safe_add(h1, safe_add(C1, D2));
    h1 = safe_add(h2, safe_add(D1, E2));
    h2 = safe_add(h3, safe_add(E1, A2));
    h3 = safe_add(h4, safe_add(A1, B2));
    h4 = safe_add(h0, safe_add(B1, C2));
    h0 = T;
  }
  return [h0, h1, h2, h3, h4];
}

function rmd160_f(j, x, y, z)
{
  return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
         (16 <= j && j <= 31) ? (x & y) | (~x & z) :
         (32 <= j && j <= 47) ? (x | ~y) ^ z :
         (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
         (64 <= j && j <= 79) ? x ^ (y | ~z) :
         "rmd160_f: j out of range";
}
function rmd160_K1(j)
{
  return ( 0 <= j && j <= 15) ? 0x00000000 :
         (16 <= j && j <= 31) ? 0x5a827999 :
         (32 <= j && j <= 47) ? 0x6ed9eba1 :
         (48 <= j && j <= 63) ? 0x8f1bbcdc :
         (64 <= j && j <= 79) ? 0xa953fd4e :
         "rmd160_K1: j out of range";
}
function rmd160_K2(j)
{
  return ( 0 <= j && j <= 15) ? 0x50a28be6 :
         (16 <= j && j <= 31) ? 0x5c4dd124 :
         (32 <= j && j <= 47) ? 0x6d703ef3 :
         (48 <= j && j <= 63) ? 0x7a6d76e9 :
         (64 <= j && j <= 79) ? 0x00000000 :
         "rmd160_K2: j out of range";
}
var rmd160_r1 = [
   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
   7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
   3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
   1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
   4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13
];
var rmd160_r2 = [
   5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
   6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
  15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
   8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
  12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11
];
var rmd160_s1 = [
  11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
   7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
  11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
  11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
   9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6
];
var rmd160_s2 = [
   8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
   9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
   9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
  15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
   8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11
];

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

Added modules/jshash/js/sha1-min.js.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS 180-1
 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */
var hexcase=0;var b64pad="";function hex_sha1(a){return rstr2hex(rstr_sha1(str2rstr_utf8(a)))}function hex_hmac_sha1(a,b){return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(a),str2rstr_utf8(b)))}function sha1_vm_test(){return hex_sha1("abc").toLowerCase()=="a9993e364706816aba3e25717850c26c9cd0d89d"}function rstr_sha1(a){return binb2rstr(binb_sha1(rstr2binb(a),a.length*8))}function rstr_hmac_sha1(c,f){var e=rstr2binb(c);if(e.length>16){e=binb_sha1(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binb_sha1(a.concat(rstr2binb(f)),512+f.length*8);return binb2rstr(binb_sha1(d.concat(g),512+160))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binb(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(24-c%32)}return a}function binb2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(24-c%32))&255)}return a}function binb_sha1(v,o){v[o>>5]|=128<<(24-o%32);v[((o+64>>9)<<4)+15]=o;var y=Array(80);var u=1732584193;var s=-271733879;var r=-1732584194;var q=271733878;var p=-1009589776;for(var l=0;l<v.length;l+=16){var n=u;var m=s;var k=r;var h=q;var f=p;for(var g=0;g<80;g++){if(g<16){y[g]=v[l+g]}else{y[g]=bit_rol(y[g-3]^y[g-8]^y[g-14]^y[g-16],1)}var z=safe_add(safe_add(bit_rol(u,5),sha1_ft(g,s,r,q)),safe_add(safe_add(p,y[g]),sha1_kt(g)));p=q;q=r;r=bit_rol(s,30);s=u;u=z}u=safe_add(u,n);s=safe_add(s,m);r=safe_add(r,k);q=safe_add(q,h);p=safe_add(p,f)}return Array(u,s,r,q,p)}function sha1_ft(e,a,g,f){if(e<20){return(a&g)|((~a)&f)}if(e<40){return a^g^f}if(e<60){return(a&g)|(a&f)|(g&f)}return a^g^f}function sha1_kt(a){return(a<20)?1518500249:(a<40)?1859775393:(a<60)?-1894007588:-899497514}function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))};

Added modules/jshash/js/sha1.js.





















































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS 180-1
 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_sha1(s)    { return rstr2hex(rstr_sha1(str2rstr_utf8(s))); }
function b64_sha1(s)    { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
function hex_hmac_sha1(k, d)
  { return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_sha1(k, d)
  { return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_sha1(k, d, e)
  { return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function sha1_vm_test()
{
  return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
}

/*
 * Calculate the SHA1 of a raw string
 */
function rstr_sha1(s)
{
  return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
}

/*
 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
 */
function rstr_hmac_sha1(key, data)
{
  var bkey = rstr2binb(key);
  if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
  return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  try { hexcase } catch(e) { hexcase=0; }
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  try { b64pad } catch(e) { b64pad=''; }
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var remainders = Array();
  var i, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(Math.ceil(input.length / 2));
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. We stop when the dividend is zero.
   * All remainders are stored for later use.
   */
  while(dividend.length > 0)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[remainders.length] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  /* Append leading zero equivalents */
  var full_length = Math.ceil(input.length * 8 /
                                    (Math.log(encoding.length) / Math.log(2)))
  for(i = output.length; i < full_length; i++)
    output = encoding[0] + output;

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of big-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binb(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
  return output;
}

/*
 * Convert an array of big-endian words to a string
 */
function binb2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
  return output;
}

/*
 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 */
function binb_sha1(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << (24 - len % 32);
  x[((len + 64 >> 9) << 4) + 15] = len;

  var w = Array(80);
  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;
  var e = -1009589776;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;
    var olde = e;

    for(var j = 0; j < 80; j++)
    {
      if(j < 16) w[j] = x[i + j];
      else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
      var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
      e = d;
      d = c;
      c = bit_rol(b, 30);
      b = a;
      a = t;
    }

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    e = safe_add(e, olde);
  }
  return Array(a, b, c, d, e);

}

/*
 * Perform the appropriate triplet combination function for the current
 * iteration
 */
function sha1_ft(t, b, c, d)
{
  if(t < 20) return (b & c) | ((~b) & d);
  if(t < 40) return b ^ c ^ d;
  if(t < 60) return (b & c) | (b & d) | (c & d);
  return b ^ c ^ d;
}

/*
 * Determine the appropriate additive constant for the current iteration
 */
function sha1_kt(t)
{
  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
         (t < 60) ? -1894007588 : -899497514;
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

Added modules/jshash/js/sha256-min.js.





















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
 * in FIPS 180-2
 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 * Also http://anmar.eu.org/projects/jssha2/
 */
var hexcase=0;function hex_sha256(a){return rstr2hex(rstr_sha256(str2rstr_utf8(a)))}function hex_hmac_sha256(a,b){return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(a),str2rstr_utf8(b)))}function sha256_vm_test(){return hex_sha256("abc").toLowerCase()=="ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"}function rstr_sha256(a){return binb2rstr(binb_sha256(rstr2binb(a),a.length*8))}function rstr_hmac_sha256(c,f){var e=rstr2binb(c);if(e.length>16){e=binb_sha256(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binb_sha256(a.concat(rstr2binb(f)),512+f.length*8);return binb2rstr(binb_sha256(d.concat(g),512+256))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binb(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(24-c%32)}return a}function binb2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(24-c%32))&255)}return a}function sha256_S(b,a){return(b>>>a)|(b<<(32-a))}function sha256_R(b,a){return(b>>>a)}function sha256_Ch(a,c,b){return((a&c)^((~a)&b))}function sha256_Maj(a,c,b){return((a&c)^(a&b)^(c&b))}function sha256_Sigma0256(a){return(sha256_S(a,2)^sha256_S(a,13)^sha256_S(a,22))}function sha256_Sigma1256(a){return(sha256_S(a,6)^sha256_S(a,11)^sha256_S(a,25))}function sha256_Gamma0256(a){return(sha256_S(a,7)^sha256_S(a,18)^sha256_R(a,3))}function sha256_Gamma1256(a){return(sha256_S(a,17)^sha256_S(a,19)^sha256_R(a,10))}function sha256_Sigma0512(a){return(sha256_S(a,28)^sha256_S(a,34)^sha256_S(a,39))}function sha256_Sigma1512(a){return(sha256_S(a,14)^sha256_S(a,18)^sha256_S(a,41))}function sha256_Gamma0512(a){return(sha256_S(a,1)^sha256_S(a,8)^sha256_R(a,7))}function sha256_Gamma1512(a){return(sha256_S(a,19)^sha256_S(a,61)^sha256_R(a,6))}var sha256_K=new Array(1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998);function binb_sha256(n,o){var p=new Array(1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225);var k=new Array(64);var B,A,z,y,w,u,t,s;var r,q,x,v;n[o>>5]|=128<<(24-o%32);n[((o+64>>9)<<4)+15]=o;for(r=0;r<n.length;r+=16){B=p[0];A=p[1];z=p[2];y=p[3];w=p[4];u=p[5];t=p[6];s=p[7];for(q=0;q<64;q++){if(q<16){k[q]=n[q+r]}else{k[q]=safe_add(safe_add(safe_add(sha256_Gamma1256(k[q-2]),k[q-7]),sha256_Gamma0256(k[q-15])),k[q-16])}x=safe_add(safe_add(safe_add(safe_add(s,sha256_Sigma1256(w)),sha256_Ch(w,u,t)),sha256_K[q]),k[q]);v=safe_add(sha256_Sigma0256(B),sha256_Maj(B,A,z));s=t;t=u;u=w;w=safe_add(y,x);y=z;z=A;A=B;B=safe_add(x,v)}p[0]=safe_add(B,p[0]);p[1]=safe_add(A,p[1]);p[2]=safe_add(z,p[2]);p[3]=safe_add(y,p[3]);p[4]=safe_add(w,p[4]);p[5]=safe_add(u,p[5]);p[6]=safe_add(t,p[6]);p[7]=safe_add(s,p[7])}return p}function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)};

Added modules/jshash/js/sha256.js.



































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
 * in FIPS 180-2
 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 * Also http://anmar.eu.org/projects/jssha2/
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_sha256(s)    { return rstr2hex(rstr_sha256(str2rstr_utf8(s))); }
function b64_sha256(s)    { return rstr2b64(rstr_sha256(str2rstr_utf8(s))); }
function any_sha256(s, e) { return rstr2any(rstr_sha256(str2rstr_utf8(s)), e); }
function hex_hmac_sha256(k, d)
  { return rstr2hex(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_sha256(k, d)
  { return rstr2b64(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_sha256(k, d, e)
  { return rstr2any(rstr_hmac_sha256(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function sha256_vm_test()
{
  return hex_sha256("abc").toLowerCase() ==
            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
}

/*
 * Calculate the sha256 of a raw string
 */
function rstr_sha256(s)
{
  return binb2rstr(binb_sha256(rstr2binb(s), s.length * 8));
}

/*
 * Calculate the HMAC-sha256 of a key and some data (raw strings)
 */
function rstr_hmac_sha256(key, data)
{
  var bkey = rstr2binb(key);
  if(bkey.length > 16) bkey = binb_sha256(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binb_sha256(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
  return binb2rstr(binb_sha256(opad.concat(hash), 512 + 256));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  try { hexcase } catch(e) { hexcase=0; }
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  try { b64pad } catch(e) { b64pad=''; }
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var remainders = Array();
  var i, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(Math.ceil(input.length / 2));
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. We stop when the dividend is zero.
   * All remainders are stored for later use.
   */
  while(dividend.length > 0)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[remainders.length] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  /* Append leading zero equivalents */
  var full_length = Math.ceil(input.length * 8 /
                                    (Math.log(encoding.length) / Math.log(2)))
  for(i = output.length; i < full_length; i++)
    output = encoding[0] + output;

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of big-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binb(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
  return output;
}

/*
 * Convert an array of big-endian words to a string
 */
function binb2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
  return output;
}

/*
 * Main sha256 function, with its support functions
 */
function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
function sha256_R (X, n) {return ( X >>> n );}
function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
function sha256_Gamma0512(x) {return (sha256_S(x, 1)  ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}

var sha256_K = new Array
(
  1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
  -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
  1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
  264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
  -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
  113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
  1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
  -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
  430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
  1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
  -1866530822, -1538233109, -1090935817, -965641998
);

function binb_sha256(m, l)
{
  var HASH = new Array(1779033703, -1150833019, 1013904242, -1521486534,
                       1359893119, -1694144372, 528734635, 1541459225);
  var W = new Array(64);
  var a, b, c, d, e, f, g, h;
  var i, j, T1, T2;

  /* append padding */
  m[l >> 5] |= 0x80 << (24 - l % 32);
  m[((l + 64 >> 9) << 4) + 15] = l;

  for(i = 0; i < m.length; i += 16)
  {
    a = HASH[0];
    b = HASH[1];
    c = HASH[2];
    d = HASH[3];
    e = HASH[4];
    f = HASH[5];
    g = HASH[6];
    h = HASH[7];

    for(j = 0; j < 64; j++)
    {
      if (j < 16) W[j] = m[j + i];
      else W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
                                            sha256_Gamma0256(W[j - 15])), W[j - 16]);

      T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
                                                          sha256_K[j]), W[j]);
      T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
      h = g;
      g = f;
      f = e;
      e = safe_add(d, T1);
      d = c;
      c = b;
      b = a;
      a = safe_add(T1, T2);
    }

    HASH[0] = safe_add(a, HASH[0]);
    HASH[1] = safe_add(b, HASH[1]);
    HASH[2] = safe_add(c, HASH[2]);
    HASH[3] = safe_add(d, HASH[3]);
    HASH[4] = safe_add(e, HASH[4]);
    HASH[5] = safe_add(f, HASH[5]);
    HASH[6] = safe_add(g, HASH[6]);
    HASH[7] = safe_add(h, HASH[7]);
  }
  return HASH;
}

function safe_add (x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

Added modules/jshash/js/sha512-min.js.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
 * in FIPS 180-2
 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */
var hexcase=0;function hex_sha512(a){return rstr2hex(rstr_sha512(str2rstr_utf8(a)))}function hex_hmac_sha512(a,b){return rstr2hex(rstr_hmac_sha512(str2rstr_utf8(a),str2rstr_utf8(b)))}function sha512_vm_test(){return hex_sha512("abc").toLowerCase()=="ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"}function rstr_sha512(a){return binb2rstr(binb_sha512(rstr2binb(a),a.length*8))}function rstr_hmac_sha512(c,f){var e=rstr2binb(c);if(e.length>32){e=binb_sha512(e,c.length*8)}var a=Array(32),d=Array(32);for(var b=0;b<32;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binb_sha512(a.concat(rstr2binb(f)),1024+f.length*8);return binb2rstr(binb_sha512(d.concat(g),1024+512))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binb(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(24-c%32)}return a}function binb2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(24-c%32))&255)}return a}var sha512_k;function binb_sha512(p,A){if(sha512_k==undefined){sha512_k=new Array(new int64(1116352408,-685199838),new int64(1899447441,602891725),new int64(-1245643825,-330482897),new int64(-373957723,-2121671748),new int64(961987163,-213338824),new int64(1508970993,-1241133031),new int64(-1841331548,-1357295717),new int64(-1424204075,-630357736),new int64(-670586216,-1560083902),new int64(310598401,1164996542),new int64(607225278,1323610764),new int64(1426881987,-704662302),new int64(1925078388,-226784913),new int64(-2132889090,991336113),new int64(-1680079193,633803317),new int64(-1046744716,-815192428),new int64(-459576895,-1628353838),new int64(-272742522,944711139),new int64(264347078,-1953704523),new int64(604807628,2007800933),new int64(770255983,1495990901),new int64(1249150122,1856431235),new int64(1555081692,-1119749164),new int64(1996064986,-2096016459),new int64(-1740746414,-295247957),new int64(-1473132947,766784016),new int64(-1341970488,-1728372417),new int64(-1084653625,-1091629340),new int64(-958395405,1034457026),new int64(-710438585,-1828018395),new int64(113926993,-536640913),new int64(338241895,168717936),new int64(666307205,1188179964),new int64(773529912,1546045734),new int64(1294757372,1522805485),new int64(1396182291,-1651133473),new int64(1695183700,-1951439906),new int64(1986661051,1014477480),new int64(-2117940946,1206759142),new int64(-1838011259,344077627),new int64(-1564481375,1290863460),new int64(-1474664885,-1136513023),new int64(-1035236496,-789014639),new int64(-949202525,106217008),new int64(-778901479,-688958952),new int64(-694614492,1432725776),new int64(-200395387,1467031594),new int64(275423344,851169720),new int64(430227734,-1194143544),new int64(506948616,1363258195),new int64(659060556,-544281703),new int64(883997877,-509917016),new int64(958139571,-976659869),new int64(1322822218,-482243893),new int64(1537002063,2003034995),new int64(1747873779,-692930397),new int64(1955562222,1575990012),new int64(2024104815,1125592928),new int64(-2067236844,-1578062990),new int64(-1933114872,442776044),new int64(-1866530822,593698344),new int64(-1538233109,-561857047),new int64(-1090935817,-1295615723),new int64(-965641998,-479046869),new int64(-903397682,-366583396),new int64(-779700025,566280711),new int64(-354779690,-840897762),new int64(-176337025,-294727304),new int64(116418474,1914138554),new int64(174292421,-1563912026),new int64(289380356,-1090974290),new int64(460393269,320620315),new int64(685471733,587496836),new int64(852142971,1086792851),new int64(1017036298,365543100),new int64(1126000580,-1676669620),new int64(1288033470,-885112138),new int64(1501505948,-60457430),new int64(1607167915,987167468),new int64(1816402316,1246189591))}var q=new Array(new int64(1779033703,-205731576),new int64(-1150833019,-2067093701),new int64(1013904242,-23791573),new int64(-1521486534,1595750129),new int64(1359893119,-1377402159),new int64(-1694144372,725511199),new int64(528734635,-79577749),new int64(1541459225,327033209));var s=new int64(0,0),r=new int64(0,0),J=new int64(0,0),I=new int64(0,0),G=new int64(0,0),F=new int64(0,0),E=new int64(0,0),D=new int64(0,0),C=new int64(0,0),B=new int64(0,0),m=new int64(0,0),l=new int64(0,0),t=new int64(0,0),o=new int64(0,0),z=new int64(0,0),w=new int64(0,0),u=new int64(0,0);var v,y;var n=new Array(80);for(y=0;y<80;y++){n[y]=new int64(0,0)}p[A>>5]|=128<<(24-(A&31));p[((A+128>>10)<<5)+31]=A;for(y=0;y<p.length;y+=32){int64copy(J,q[0]);int64copy(I,q[1]);int64copy(G,q[2]);int64copy(F,q[3]);int64copy(E,q[4]);int64copy(D,q[5]);int64copy(C,q[6]);int64copy(B,q[7]);for(v=0;v<16;v++){n[v].h=p[y+2*v];n[v].l=p[y+2*v+1]}for(v=16;v<80;v++){int64rrot(z,n[v-2],19);int64revrrot(w,n[v-2],29);int64shr(u,n[v-2],6);l.l=z.l^w.l^u.l;l.h=z.h^w.h^u.h;int64rrot(z,n[v-15],1);int64rrot(w,n[v-15],8);int64shr(u,n[v-15],7);m.l=z.l^w.l^u.l;m.h=z.h^w.h^u.h;int64add4(n[v],l,n[v-7],m,n[v-16])}for(v=0;v<80;v++){t.l=(E.l&D.l)^(~E.l&C.l);t.h=(E.h&D.h)^(~E.h&C.h);int64rrot(z,E,14);int64rrot(w,E,18);int64revrrot(u,E,9);l.l=z.l^w.l^u.l;l.h=z.h^w.h^u.h;int64rrot(z,J,28);int64revrrot(w,J,2);int64revrrot(u,J,7);m.l=z.l^w.l^u.l;m.h=z.h^w.h^u.h;o.l=(J.l&I.l)^(J.l&G.l)^(I.l&G.l);o.h=(J.h&I.h)^(J.h&G.h)^(I.h&G.h);int64add5(s,B,l,t,sha512_k[v],n[v]);int64add(r,m,o);int64copy(B,C);int64copy(C,D);int64copy(D,E);int64add(E,F,s);int64copy(F,G);int64copy(G,I);int64copy(I,J);int64add(J,s,r)}int64add(q[0],q[0],J);int64add(q[1],q[1],I);int64add(q[2],q[2],G);int64add(q[3],q[3],F);int64add(q[4],q[4],E);int64add(q[5],q[5],D);int64add(q[6],q[6],C);int64add(q[7],q[7],B)}var k=new Array(16);for(y=0;y<8;y++){k[2*y]=q[y].h;k[2*y+1]=q[y].l}return k}function int64(b,a){this.h=b;this.l=a}function int64copy(b,a){b.h=a.h;b.l=a.l}function int64rrot(c,a,b){c.l=(a.l>>>b)|(a.h<<(32-b));c.h=(a.h>>>b)|(a.l<<(32-b))}function int64revrrot(c,a,b){c.l=(a.h>>>b)|(a.l<<(32-b));c.h=(a.l>>>b)|(a.h<<(32-b))}function int64shr(c,a,b){c.l=(a.l>>>b)|(a.h<<(32-b));c.h=(a.h>>>b)}function int64add(g,b,f){var d=(b.l&65535)+(f.l&65535);var c=(b.l>>>16)+(f.l>>>16)+(d>>>16);var a=(b.h&65535)+(f.h&65535)+(c>>>16);var e=(b.h>>>16)+(f.h>>>16)+(a>>>16);g.l=(d&65535)|(c<<16);g.h=(a&65535)|(e<<16)}function int64add4(j,m,l,k,i){var h=(m.l&65535)+(l.l&65535)+(k.l&65535)+(i.l&65535);var g=(m.l>>>16)+(l.l>>>16)+(k.l>>>16)+(i.l>>>16)+(h>>>16);var f=(m.h&65535)+(l.h&65535)+(k.h&65535)+(i.h&65535)+(g>>>16);var e=(m.h>>>16)+(l.h>>>16)+(k.h>>>16)+(i.h>>>16)+(f>>>16);j.l=(h&65535)|(g<<16);j.h=(f&65535)|(e<<16)}function int64add5(l,o,n,m,k,j){var i=(o.l&65535)+(n.l&65535)+(m.l&65535)+(k.l&65535)+(j.l&65535);var h=(o.l>>>16)+(n.l>>>16)+(m.l>>>16)+(k.l>>>16)+(j.l>>>16)+(i>>>16);var g=(o.h&65535)+(n.h&65535)+(m.h&65535)+(k.h&65535)+(j.h&65535)+(h>>>16);var f=(o.h>>>16)+(n.h>>>16)+(m.h>>>16)+(k.h>>>16)+(j.h>>>16)+(g>>>16);l.l=(i&65535)|(h<<16);l.h=(g&65535)|(f<<16)};

Added modules/jshash/js/sha512.js.

































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined
 * in FIPS 180-2
 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_sha512(s)    { return rstr2hex(rstr_sha512(str2rstr_utf8(s))); }
function b64_sha512(s)    { return rstr2b64(rstr_sha512(str2rstr_utf8(s))); }
function any_sha512(s, e) { return rstr2any(rstr_sha512(str2rstr_utf8(s)), e);}
function hex_hmac_sha512(k, d)
  { return rstr2hex(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_sha512(k, d)
  { return rstr2b64(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_sha512(k, d, e)
  { return rstr2any(rstr_hmac_sha512(str2rstr_utf8(k), str2rstr_utf8(d)), e);}

/*
 * Perform a simple self-test to see if the VM is working
 */
function sha512_vm_test()
{
  return hex_sha512("abc").toLowerCase() ==
    "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
    "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
}

/*
 * Calculate the SHA-512 of a raw string
 */
function rstr_sha512(s)
{
  return binb2rstr(binb_sha512(rstr2binb(s), s.length * 8));
}

/*
 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
 */
function rstr_hmac_sha512(key, data)
{
  var bkey = rstr2binb(key);
  if(bkey.length > 32) bkey = binb_sha512(bkey, key.length * 8);

  var ipad = Array(32), opad = Array(32);
  for(var i = 0; i < 32; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binb_sha512(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
  return binb2rstr(binb_sha512(opad.concat(hash), 1024 + 512));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  try { hexcase } catch(e) { hexcase=0; }
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  try { b64pad } catch(e) { b64pad=''; }
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var i, j, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(Math.ceil(input.length / 2));
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. All remainders are stored for later
   * use.
   */
  var full_length = Math.ceil(input.length * 8 /
                                    (Math.log(encoding.length) / Math.log(2)));
  var remainders = Array(full_length);
  for(j = 0; j < full_length; j++)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[j] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of big-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binb(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
  return output;
}

/*
 * Convert an array of big-endian words to a string
 */
function binb2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
  return output;
}

/*
 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
 */
var sha512_k;
function binb_sha512(x, len)
{
  if(sha512_k == undefined)
  {
    //SHA512 constants
    sha512_k = new Array(
new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
new int64(-354779690, -840897762), new int64(-176337025, -294727304),
new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817));
  }

  //Initial hash values
  var H = new Array(
new int64(0x6a09e667, -205731576),
new int64(-1150833019, -2067093701),
new int64(0x3c6ef372, -23791573),
new int64(-1521486534, 0x5f1d36f1),
new int64(0x510e527f, -1377402159),
new int64(-1694144372, 0x2b3e6c1f),
new int64(0x1f83d9ab, -79577749),
new int64(0x5be0cd19, 0x137e2179));

  var T1 = new int64(0, 0),
    T2 = new int64(0, 0),
    a = new int64(0,0),
    b = new int64(0,0),
    c = new int64(0,0),
    d = new int64(0,0),
    e = new int64(0,0),
    f = new int64(0,0),
    g = new int64(0,0),
    h = new int64(0,0),
    //Temporary variables not specified by the document
    s0 = new int64(0, 0),
    s1 = new int64(0, 0),
    Ch = new int64(0, 0),
    Maj = new int64(0, 0),
    r1 = new int64(0, 0),
    r2 = new int64(0, 0),
    r3 = new int64(0, 0);
  var j, i;
  var W = new Array(80);
  for(i=0; i<80; i++)
    W[i] = new int64(0, 0);

  // append padding to the source string. The format is described in the FIPS.
  x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
  x[((len + 128 >> 10)<< 5) + 31] = len;

  for(i = 0; i<x.length; i+=32) //32 dwords is the block size
  {
    int64copy(a, H[0]);
    int64copy(b, H[1]);
    int64copy(c, H[2]);
    int64copy(d, H[3]);
    int64copy(e, H[4]);
    int64copy(f, H[5]);
    int64copy(g, H[6]);
    int64copy(h, H[7]);

    for(j=0; j<16; j++)
    {
        W[j].h = x[i + 2*j];
        W[j].l = x[i + 2*j + 1];
    }

    for(j=16; j<80; j++)
    {
      //sigma1
      int64rrot(r1, W[j-2], 19);
      int64revrrot(r2, W[j-2], 29);
      int64shr(r3, W[j-2], 6);
      s1.l = r1.l ^ r2.l ^ r3.l;
      s1.h = r1.h ^ r2.h ^ r3.h;
      //sigma0
      int64rrot(r1, W[j-15], 1);
      int64rrot(r2, W[j-15], 8);
      int64shr(r3, W[j-15], 7);
      s0.l = r1.l ^ r2.l ^ r3.l;
      s0.h = r1.h ^ r2.h ^ r3.h;

      int64add4(W[j], s1, W[j-7], s0, W[j-16]);
    }

    for(j = 0; j < 80; j++)
    {
      //Ch
      Ch.l = (e.l & f.l) ^ (~e.l & g.l);
      Ch.h = (e.h & f.h) ^ (~e.h & g.h);

      //Sigma1
      int64rrot(r1, e, 14);
      int64rrot(r2, e, 18);
      int64revrrot(r3, e, 9);
      s1.l = r1.l ^ r2.l ^ r3.l;
      s1.h = r1.h ^ r2.h ^ r3.h;

      //Sigma0
      int64rrot(r1, a, 28);
      int64revrrot(r2, a, 2);
      int64revrrot(r3, a, 7);
      s0.l = r1.l ^ r2.l ^ r3.l;
      s0.h = r1.h ^ r2.h ^ r3.h;

      //Maj
      Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
      Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);

      int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
      int64add(T2, s0, Maj);

      int64copy(h, g);
      int64copy(g, f);
      int64copy(f, e);
      int64add(e, d, T1);
      int64copy(d, c);
      int64copy(c, b);
      int64copy(b, a);
      int64add(a, T1, T2);
    }
    int64add(H[0], H[0], a);
    int64add(H[1], H[1], b);
    int64add(H[2], H[2], c);
    int64add(H[3], H[3], d);
    int64add(H[4], H[4], e);
    int64add(H[5], H[5], f);
    int64add(H[6], H[6], g);
    int64add(H[7], H[7], h);
  }

  //represent the hash as an array of 32-bit dwords
  var hash = new Array(16);
  for(i=0; i<8; i++)
  {
    hash[2*i] = H[i].h;
    hash[2*i + 1] = H[i].l;
  }
  return hash;
}

//A constructor for 64-bit numbers
function int64(h, l)
{
  this.h = h;
  this.l = l;
  //this.toString = int64toString;
}

//Copies src into dst, assuming both are 64-bit numbers
function int64copy(dst, src)
{
  dst.h = src.h;
  dst.l = src.l;
}

//Right-rotates a 64-bit number by shift
//Won't handle cases of shift>=32
//The function revrrot() is for that
function int64rrot(dst, x, shift)
{
    dst.l = (x.l >>> shift) | (x.h << (32-shift));
    dst.h = (x.h >>> shift) | (x.l << (32-shift));
}

//Reverses the dwords of the source and then rotates right by shift.
//This is equivalent to rotation by 32+shift
function int64revrrot(dst, x, shift)
{
    dst.l = (x.h >>> shift) | (x.l << (32-shift));
    dst.h = (x.l >>> shift) | (x.h << (32-shift));
}

//Bitwise-shifts right a 64-bit number by shift
//Won't handle shift>=32, but it's never needed in SHA512
function int64shr(dst, x, shift)
{
    dst.l = (x.l >>> shift) | (x.h << (32-shift));
    dst.h = (x.h >>> shift);
}

//Adds two 64-bit numbers
//Like the original implementation, does not rely on 32-bit operations
function int64add(dst, x, y)
{
   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
   dst.l = (w0 & 0xffff) | (w1 << 16);
   dst.h = (w2 & 0xffff) | (w3 << 16);
}

//Same, except with 4 addends. Works faster than adding them one by one.
function int64add4(dst, a, b, c, d)
{
   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
   dst.l = (w0 & 0xffff) | (w1 << 16);
   dst.h = (w2 & 0xffff) | (w3 << 16);
}

//Same, except with 5 addends
function int64add5(dst, a, b, c, d, e)
{
   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff);
   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16);
   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16);
   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
   dst.l = (w0 & 0xffff) | (w1 << 16);
   dst.h = (w2 & 0xffff) | (w3 << 16);
}

Added modules/jshash/js/test-min.py.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#--
# Script to test the JavaScript hash algorithms
# This produces an HTML file, that you load in a browser to run the tests
#--
import hashlib, base64, hmac

all_algs = ['md5', 'sha1', 'ripemd160', 'sha256', 'sha512']
short = {'ripemd160': 'rmd160'}
test_strings = ['hello', 'world', u'fred\u1234'.encode('utf-8'), 'this is a longer test message to confirm that multiple blocks are handled correctly by the hashing algorithm']

print """<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/></head><body>"""

for alg in all_algs:
    algs = short.get(alg, alg)

    print """<script src="%s-min.js"></script>
<script>
var pass = 0; fail = 0;
function check(a, b)
{
    if(a != b)
    {
        document.write('Test fail: ' + a + ' != ' + b + '<br/>');
        fail += 1;
    }
    else pass += 1;
}
document.write("Testing %s...<br/>");
""" % (alg, alg)

    for t in test_strings:
        h = hashlib.new(alg)
        h.update(t)
        print "check(hex_%s('%s'), '%s');" % (algs, t, h.hexdigest())
        h = hmac.new('key', t, lambda: hashlib.new(alg))
        print "check(hex_hmac_%s('key', '%s'), '%s');" % (algs, t, h.hexdigest())

    print """
document.write('Tests competed - ' + pass + ' passed; ' + fail + ' failed.<br/><br/>');
</script>
"""

print "</body></html>"

Added modules/jshash/js/test.py.



























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#--
# Script to test the JavaScript hash algorithms
# This produces an HTML file, that you load in a browser to run the tests
#--
import hashlib, base64, hmac

all_algs = ['md5', 'sha1', 'ripemd160', 'sha256', 'sha512']
short = {'ripemd160': 'rmd160'}
test_strings = ['hello', 'world', u'fred\u1234'.encode('utf-8'), 'this is a longer test message to confirm that multiple blocks are handled correctly by the hashing algorithm']

print """<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"/></head><body>"""

for alg in all_algs:
    algs = short.get(alg, alg)

    print """<script src="%s.js"></script>
<script>
var pass = 0; fail = 0;
function check(a, b)
{
    if(a != b)
    {
        document.write('Test fail: ' + a + ' != ' + b + '<br/>');
        fail += 1;
    }
    else pass += 1;
}
document.write("Testing %s...<br/>");
""" % (alg, alg)

    for t in test_strings:
        h = hashlib.new(alg)
        h.update(t)
        print "check(hex_%s('%s'), '%s');" % (algs, t, h.hexdigest())
        print "check(b64_%s('%s'), '%s');" % (algs, t, base64.b64encode(h.digest()).rstrip('='))
        h = hmac.new('key', t, lambda: hashlib.new(alg))
        print "check(hex_hmac_%s('key', '%s'), '%s');" % (algs, t, h.hexdigest())
        print "check(b64_hmac_%s('key', '%s'), '%s');" % (algs, t, base64.b64encode(h.digest()).rstrip('='))

    print """
document.write('Tests competed - ' + pass + ' passed; ' + fail + ' failed.<br/><br/>');
</script>
"""

print "</body></html>"

Added modules/jshash/jshash.md.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
A JavaScript implementation of the Secure Hash Algorithm

Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.

Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet

Distributed under the BSD License
See <http://pajhome.org.uk/crypt/md5> for details.

This package adds javascripts capable of performing md5 and
sha1 hashes, and makes them available at /jshash on the local
webserver.

To use them add the following block of code to your pages:

    <script type="text/javascript" src="/jshash/sha1.js"></script>  

Added modules/jshash/jshash.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
###
# Add hooks for jshash
###

package require httpd::doc	;# Httpd_Redirect Httpd_ReturnData

set PWD [file dirname [file normalize [info script]]]

Doc_AddRoot /jshash $PWD/js

package provide httpd::jshash 0.1

Added modules/jshash/pkgIndex.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd::jshash 0.1 [list source [file join $dir jshash.tcl]]

Added modules/markdown/markdown.tcl.







































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
#
# The MIT License (MIT)
#
# Copyright (c) 2014 Caius Project
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# 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 OR COPYRIGHT HOLDERS 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.
#

package require textutil

## \file
# \brief Functions for converting markdown to HTML.

##
# \brief Functions for converting markdown to HTML.
#
namespace eval Markdown {

    namespace export convert

    ##
    #
    # Converts text written in markdown to HTML.
    #
    # @param markdown  currently takes as a single argument the text in markdown
    #
    # The output of this function is only a fragment, not a complete HTML
    # document. The format of the output is generic XHTML.
    #
    proc convert {markdown} {
        set markdown [regsub {\r\n?} $markdown {\n}]
        set markdown [::textutil::untabify2 $markdown 4]
        set markdown [string trimright $markdown]

        # COLLECT REFERENCES
        array unset ::Markdown::_references
        array set ::Markdown::_references [collect_references markdown]

        # PROCESS
        return [apply_templates markdown]
    }

    ## \private
    proc collect_references {markdown_var} {
        upvar $markdown_var markdown

        set lines [split $markdown \n]
        set no_lines [llength $lines]
        set index 0

        array set references {}

        while {$index < $no_lines} {
            set line [lindex $lines $index]

            if {[regexp \
                {^[ ]{0,3}\[((?:[^\]]|\[[^\]]*?\])+)\]:\s*(\S+)(?:\s+(([\"\']).*\4|\(.*\))\s*$)?} \
                $line match ref link title]} \
            {
                set title [string trim [string range $title 1 end-1]]
                if {$title eq {}} {
                    set next_line [lindex $lines [expr $index + 1]]

                    if {[regexp \
                        {^(?:\s+(?:([\"\']).*\1|\(.*\))\s*$)} \
                        $next_line]} \
                    {
                        set title [string range [string trim $next_line] 1 end-1]
                        incr index
                    }
                }
                set ref [string tolower $ref]
                set link [string trim $link {<>}]
                set references($ref) [list $link $title]
            }

            incr index
        }

        return [array get references]
    }

    ## \private
    proc apply_templates {markdown_var {parent {}}} {
        upvar $markdown_var markdown

        set lines    [split $markdown \n]
        set no_lines [llength $lines]
        set index    0
        set result   {}

        set ul_match {^[ ]{0,3}(?:\*(?!\s*\*\s*\*\s*$)|-(?!\s*-\s*-\s*$)|\+) }
        set ol_match {^[ ]{0,3}\d+\. }

        # PROCESS MARKDOWN
        while {$index < $no_lines} {
            set line [lindex $lines $index]

            switch -regexp $line {
                {^\s*$} {
                    # EMPTY LINES
                    if {![regexp {^\s*$} [lindex $lines [expr $index - 1]]]} {
                        append result "\n\n"
                    }
                    incr index
                }
                {^[ ]{0,3}\[(?:[^\]]|\[[^\]]*?\])+\]:\s*\S+(?:\s+(?:([\"\']).*\1|\(.*\))\s*$)?} {
                    # SKIP REFERENCES
                    set next_line [lindex $lines [expr $index + 1]]

                    if {[regexp \
                        {^(?:\s+(?:([\"\']).*\1|\(.*\))\s*$)} \
                        $next_line]} \
                    {
                        incr index
                    }

                    incr index
                }
                {^[ ]{0,3}-[ ]*-[ ]*-[- ]*$} -
                {^[ ]{0,3}_[ ]*_[ ]*_[_ ]*$} -
                {^[ ]{0,3}\*[ ]*\*[ ]*\*[\* ]*$} {
                    # HORIZONTAL RULES
                    append result "<hr/>"
                    incr index
                }
                {^[ ]{0,3}#{1,6}} {
                    # ATX STYLE HEADINGS
                    set h_level 0
                    set h_result {}

                    while {$index < $no_lines && ![is_empty_line $line]} {
                        incr index

                        if {!$h_level} {
                            regexp {^\s*#+} $line m
                            set h_level [string length [string trim $m]]
                        }

                        lappend h_result $line

                        set line [lindex $lines $index]
                    }

                    set h_result [\
                        parse_inline [\
                            regsub -all {^\s*#+\s*|\s*#+\s*$} [join $h_result \n] {} \
                        ]\
                    ]

                    append result "<h$h_level>$h_result</h$h_level>"
                }
                {^[ ]{0,3}\>} {
                    # BLOCK QUOTES
                    set bq_result {}

                    while {$index < $no_lines} {
                        incr index

                        lappend bq_result [regsub {^[ ]{0,3}\>[ ]?} $line {}]

                        if {[is_empty_line [lindex $lines $index]]} {
                            set eoq 0

                            for {set peek $index} {$peek < $no_lines} {incr peek} {
                                set line [lindex $lines $peek]

                                if {![is_empty_line $line]} {
                                    if {![regexp {^[ ]{0,3}\>} $line]} {
                                        set eoq 1
                                    }
                                    break
                                }
                            }

                            if {$eoq} { break }
                        }

                        set line [lindex $lines $index]
                    }
                    set bq_result [string trim [join $bq_result \n]]

                    append result <blockquote>\n \
                                    [apply_templates bq_result] \
                                  \n</blockquote>
                }
                {^\s{4,}\S+} {
                    # CODE BLOCKS
                    set code_result {}

                    while {$index < $no_lines} {
                        incr index

                        lappend code_result [html_escape [\
                            regsub {^    } $line {}]\
                        ]

                        set eoc 0
                        for {set peek $index} {$peek < $no_lines} {incr peek} {
                            set line [lindex $lines $peek]

                            if {![is_empty_line $line]} {
                                if {![regexp {^\s{4,}} $line]} {
                                    set eoc 1
                                }
                                break
                            }
                        }

                        if {$eoc} { break }

                        set line [lindex $lines $index]
                    }
                    set code_result [join $code_result \n]

                    append result <pre><code> $code_result \n </code></pre>
                }
                {^(?:(?:`{3,})|(?:~{3,}))(?:\{?\S+\}?)?\s*$} {
                    # FENCED CODE BLOCKS
                    set code_result {}

                    if {[string index $line 0] eq {`}} {
                        set end_match {^`{3,}\s*$}
                    } else {
                        set end_match {^~{3,}\s*$}
                    }

                    while {$index < $no_lines} {
                        incr index

                        set line [lindex $lines $index]

                        if {[regexp $end_match $line]} {
                            incr index
                            break
                        }

                        lappend code_result [html_escape $line]
                    }
                    set code_result [join $code_result \n]

                    append result <pre><code> $code_result </code></pre>
                }
                {^[ ]{0,3}(?:\*|-|\+) |^[ ]{0,3}\d+\. } {
                    # LISTS
                    set list_result {}

                    # continue matching same list type
                    if {[regexp $ol_match $line]} {
                        set list_type ol
                        set list_match $ol_match
                    } else {
                        set list_type ul
                        set list_match $ul_match
                    }

                    set last_line AAA

                    while {$index < $no_lines} \
                    {
                        if {![regexp $list_match [lindex $lines $index]]} {
                            break
                        }

                        set item_result {}
                        set in_p 1
                        set p_count 1

                        if {[is_empty_line $last_line]} {
                            incr p_count
                        }

                        set last_line $line
                        set line [regsub "$list_match\\s*" $line {}]

                        # prevent recursion on same line
                        set line [regsub {\A(\d+)\.(\s+)}   $line {\1\\.\2}]
                        set line [regsub {\A(\*|\+|-)(\s+)} $line {\\\1\2}]

                        lappend item_result $line

                        for {set peek [expr $index + 1]} {$peek < $no_lines} {incr peek} {
                            set line [lindex $lines $peek]

                            if {[is_empty_line $line]} {
                                set in_p 0
                            }\
                            elseif {[regexp {^    } $line]} {
                                if {!$in_p} {
                                    incr p_count
                                }
                                set in_p 1
                            }\
                            elseif {[regexp $list_match $line]} {
                                if {!$in_p} {
                                    incr p_count
                                }
                                break
                            }\
                            elseif {!$in_p} {
                                break
                            }

                            set last_line $line
                            lappend item_result [regsub {^    } $line {}]
                        }

                        set item_result [join $item_result \n]

                        if {$p_count > 1} {
                            set item_result [apply_templates item_result li]
                        } else {
                            if {[regexp -lineanchor \
                                {(\A.*?)((?:^[ ]{0,3}(?:\*|-|\+) |^[ ]{0,3}\d+\. ).*\Z)} \
                                $item_result \
                                match para rest]} \
                            {
                                set item_result [parse_inline $para]
                                append item_result [apply_templates rest]
                            } else {
                                set item_result [parse_inline $item_result]
                            }
                        }

                        lappend list_result "<li>$item_result</li>"
                        set index $peek
                    }

                    append result <$list_type>\n \
                                    [join $list_result \n] \
                                </$list_type>\n\n
                }
                {^<(?:p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)} {
                    # HTML BLOCKS
                    set re_htmltag {<(/?)(\w+)(?:\s+\w+=(?:\"[^\"]+\"|'[^']+'))*\s*>}
                    set buffer {}

                    while {$index < $no_lines} \
                    {
                        while {$index < $no_lines} \
                        {
                            incr index

                            append buffer $line \n

                            if {[is_empty_line $line]} {
                                break
                            }

                            set line [lindex $lines $index]
                        }

                        set tags [regexp -inline -all $re_htmltag  $buffer]
                        set stack_count 0

                        foreach {match type name} $tags {
                            if {$type eq {}} {
                                incr stack_count +1
                            } else {
                                incr stack_count -1
                            }
                        }

                        if {$stack_count == 0} { break }
                    }

                    append result $buffer
                }
                {(?:^\s{0,3}|[^\\]+)\|} {
                    # SIMPLE TABLES
                    set cell_align {}
                    set row_count 0

                    while {$index < $no_lines} \
                    {
                        # insert a space between || to handle empty cells
                        set row_cols [regexp -inline -all {(?:[^|]|\\\|)+} \
                            [regsub -all {\|(?=\|)} [string trim $line] {| }] \
                        ]

                        if {$row_count == 0} \
                        {
                            set sep_cols [lindex $lines [expr $index + 1]]

                            # check if we have a separator row
                            if {[regexp {^\s{0,3}\|?(?:\s*:?-+:?(?:\s*$|\s*\|))+} $sep_cols]} \
                            {
                                set sep_cols [regexp -inline -all {(?:[^|]|\\\|)+} \
                                    [string trim $sep_cols]]

                                foreach {cell_data} $sep_cols \
                                {
                                    switch -regexp $cell_data {
                                        {:-*:} {
                                            lappend cell_align center
                                        }
                                        {:-+} {
                                            lappend cell_align left
                                        }
                                        {-+:} {
                                            lappend cell_align right
                                        }
                                        default {
                                            lappend cell_align {}
                                        }
                                    }
                                }

                                incr index
                            }

                            append result "<table class=\"table\">\n"
                            append result "<thead>\n"
                            append result "  <tr>\n"

                            if {$cell_align ne {}} {
                                set num_cols [llength $cell_align]
                            } else {
                                set num_cols [llength $row_cols]
                            }

                            for {set i 0} {$i < $num_cols} {incr i} \
                            {
                                if {[set align [lindex $cell_align $i]] ne {}} {
                                    append result "    <th style=\"text-align: $align\">"
                                } else {
                                    append result "    <th>"
                                }

                                append result [parse_inline [string trim \
                                    [lindex $row_cols $i]]] </th> "\n"
                            }

                            append result "  </tr>\n"
                            append result "</thead>\n"
                        } else {
                            if {$row_count == 1} {
                                append result "<tbody>\n"
                            }

                            append result "  <tr>\n"

                            if {$cell_align ne {}} {
                                set num_cols [llength $cell_align]
                            } else {
                                set num_cols [llength $row_cols]
                            }

                            for {set i 0} {$i < $num_cols} {incr i} \
                            {
                                if {[set align [lindex $cell_align $i]] ne {}} {
                                    append result "    <td style=\"text-align: $align\">"
                                } else {
                                    append result "    <td>"
                                }

                                append result [parse_inline [string trim \
                                    [lindex $row_cols $i]]] </td> "\n"
                            }

                            append result "  </tr>\n"
                        }

                        incr row_count

                        set line [lindex $lines [incr index]]

                        if {![regexp {(?:^\s{0,3}|[^\\]+)\|} $line]} {
                            switch $row_count {
                                1 {
                                    append result "</table>\n"
                                }
                                default {
                                    append result "</tbody>\n"
                                    append result "</table>\n"
                                }
                            }

                            break
                        }
                    }
                }
                default {
                    # PARAGRAPHS AND SETTEXT STYLE HEADERS
                    set p_type p
                    set p_result {}

                    while {($index < $no_lines) && ![is_empty_line $line]} \
                    {
                        incr index

                        switch -regexp $line {
                            {^[ ]{0,3}=+$} {
                                set p_type h1
                                break
                            }
                            {^[ ]{0,3}-+$} {
                                set p_type h2
                                break
                            }
                            {^[ ]{0,3}(?:\*|-|\+) |^[ ]{0,3}\d+\. } {
                                if {$parent eq {li}} {
                                    incr index -1
                                    break
                                } else {
                                    lappend p_result $line
                                }
                            }
                            {^[ ]{0,3}-[ ]*-[ ]*-[- ]*$} -
                            {^[ ]{0,3}_[ ]*_[ ]*_[_ ]*$} -
                            {^[ ]{0,3}\*[ ]*\*[ ]*\*[\* ]*$} -
                            {^[ ]{0,3}#{1,6}} \
                            {
                                incr index -1
                                break
                            }
                            default {
                                lappend p_result $line
                            }
                        }

                        set line [lindex $lines $index]
                    }

                    set p_result [\
                        parse_inline [\
                            string trim [join $p_result \n]\
                        ]\
                    ]

                    if {[is_empty_line [regsub -all {<!--.*?-->} $p_result {}]]} {
                        # Do not make a new paragraph for just comments.
                        append result $p_result
                    } else {
                        append result "<$p_type>$p_result</$p_type>"
                    }
                }
            }
        }

        return $result
    }

    ## \private
    proc parse_inline {text} {
        set text [regsub -all -lineanchor {[ ]{2,}$} $text <br/>]

        set index 0
        set result {}

        set re_backticks   {\A`+}
        set re_whitespace  {\s}
        set re_inlinelink  {\A\!?\[((?:[^\]]|\[[^\]]*?\])+)\]\s*\(\s*((?:[^\s\)]+|\([^\s\)]+\))+)?(\s+([\"'])(.*)?\4)?\s*\)}
        set re_reflink     {\A\!?\[((?:[^\]]|\[[^\]]*?\])+)\](?:\s*\[((?:[^\]]|\[[^\]]*?\])*)\])?}
        set re_htmltag     {\A</?\w+\s*>|\A<\w+(?:\s+\w+=(?:\"[^\"]+\"|\'[^\']+\'))*\s*/?>}
        set re_autolink    {\A<(?:(\S+@\S+)|(\S+://\S+))>}
        set re_comment     {\A<!--.*?-->}
        set re_entity      {\A\&\S+;}

        while {[set chr [string index $text $index]] ne {}} {
            switch $chr {
                "\\" {
                    # ESCAPES
                    set next_chr [string index $text [expr $index + 1]]

                    if {[string first $next_chr {\`*_\{\}[]()#+-.!>|}] != -1} {
                        set chr $next_chr
                        incr index
                    }
                }
                {_} -
                {*} {
                    # EMPHASIS
                    if {[regexp $re_whitespace [string index $result end]] &&
                        [regexp $re_whitespace [string index $text [expr $index + 1]]]} \
                    {
                        #do nothing
                    } \
                    elseif {[regexp -start $index \
                        "\\A(\\$chr{1,3})((?:\[^\\$chr\\\\]|\\\\\\$chr)*)\\1" \
                        $text m del sub]} \
                    {
                        switch [string length $del] {
                            1 {
                                append result "<em>[parse_inline $sub]</em>"
                            }
                            2 {
                                append result "<strong>[parse_inline $sub]</strong>"
                            }
                            3 {
                                append result "<strong><em>[parse_inline $sub]</em></strong>"
                            }
                        }

                        incr index [string length $m]
                        continue
                    }
                }
                {`} {
                    # CODE
                    regexp -start $index $re_backticks $text m
                    set start [expr $index + [string length $m]]

                    if {[regexp -start $start -indices $m $text m]} {
                        set stop [expr [lindex $m 0] - 1]

                        set sub [string trim [string range $text $start $stop]]

                        append result "<code>[html_escape $sub]</code>"
                        set index [expr [lindex $m 1] + 1]
                        continue
                    }
                }
                {!} -
                {[} {
                    # LINKS AND IMAGES
                    if {$chr eq {!}} {
                        set ref_type img
                    } else {
                        set ref_type link
                    }

                    set match_found 0

                    if {[regexp -start $index $re_inlinelink $text m txt url ign del title]} {
                        # INLINE
                        incr index [string length $m]

                        set url [html_escape [string trim $url {<> }]]
                        set txt [parse_inline $txt]
                        set title [parse_inline $title]

                        set match_found 1
                    } elseif {[regexp -start $index $re_reflink $text m txt lbl]} {
                        if {$lbl eq {}} {
                            set lbl [regsub -all {\s+} $txt { }]
                        }

                        set lbl [string tolower $lbl]

                        if {[info exists ::Markdown::_references($lbl)]} {
                            lassign $::Markdown::_references($lbl) url title

                            set url [html_escape [string trim $url {<> }]]
                            set txt [parse_inline $txt]
                            set title [parse_inline $title]

                            # REFERENCED
                            incr index [string length $m]
                            set match_found 1
                        }
                    }

                    # PRINT IMG, A TAG
                    if {$match_found} {
                        if {$ref_type eq {link}} {
                            if {$title ne {}} {
                                append result "<a href=\"$url\" title=\"$title\">$txt</a>"
                            } else {
                                append result "<a href=\"$url\">$txt</a>"
                            }
                        } else {
                            if {$title ne {}} {
                                append result "<img src=\"$url\" alt=\"$txt\" title=\"$title\"/>"
                            } else {
                                append result "<img src=\"$url\" alt=\"$txt\"/>"
                            }
                        }

                        continue
                    }
                }
                {<} {
                    # HTML TAGS, COMMENTS AND AUTOLINKS
                    if {[regexp -start $index $re_comment $text m]} {
                        append result $m
                        incr index [string length $m]
                        continue
                    } elseif {[regexp -start $index $re_autolink $text m email link]} {
                        if {$link ne {}} {
                            set link [html_escape $link]
                            append result "<a href=\"$link\">$link</a>"
                        } else {
                            set mailto_prefix "mailto:"
                            if {![regexp "^${mailto_prefix}(.*)" $email mailto email]} {
                                # $email does not contain the prefix "mailto:".
                                set mailto "mailto:$email"
                            }
                            append result "<a href=\"$mailto\">$email</a>"
                        }
                        incr index [string length $m]
                        continue
                    } elseif {[regexp -start $index $re_htmltag $text m]} {
                        append result $m
                        incr index [string length $m]
                        continue
                    }

                    set chr [html_escape $chr]
                }
                {&} {
                    # ENTITIES
                    if {[regexp -start $index $re_entity $text m]} {
                        append result $m
                        incr index [string length $m]
                        continue
                    }

                    set chr [html_escape $chr]
                }
                {>} -
                {'} -
                "\"" {
                    # OTHER SPECIAL CHARACTERS
                    set chr [html_escape $chr]
                }
                default {}
            }

            append result $chr
            incr index
        }

        return $result
    }

    ## \private
    proc is_empty_line {line} {
        return [regexp {^\s*$} $line]
    }

    ## \private
    proc html_escape {text} {
        return [string map {& &amp; < &lt; > &gt; \" &quot;} $text]
    }
}

package provide Markdown 1.0

Added modules/markdown/pkgIndex.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded Markdown 1.0 [list source [file join $dir markdown.tcl]]

Added modules/pkgIndex.tcl.















>
>
>
>
>
>
>
1
2
3
4
5
6
7
set PWD $dir
foreach subpath [glob -nocomplain $PWD/*] {
  if {[file exists $subpath/pkgIndex.tcl]} {
    set dir $subpath
    source $subpath/pkgIndex.tcl
  }
}

Added modules/qwiki/pkgIndex.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd::qwiki 0.1 [list source [file join $dir qwiki.tcl]]

Added modules/qwiki/qwiki.md.

Added modules/qwiki/qwiki.tcl.





























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
###
# Implements a barebone wiki in a community object
###

package require httpd::community

tao::class qwiki.layer.wiki {
  superclass community.layer

  property module user
  property schema version 1.0  
  property schema table qwiki
  property schema primary_key entryid
  
  property schema create_sql {
    create table if not exists qwiki (
      qwikid uuid default (uuid_generate()),
      indexed integer default 0,
      parent uuid references qwiki (qwikid) ON UPDATE CASCADE ON DELETE SET NULL,
      acl_name  string references acl (acl_name) ON UPDATE CASCADE ON DELETE SET NULL,
      class string,
      format string,
      title string,
      body text,
      ctime unixtime default now(),
      mtime unixtime default now(),
      primary key (qwikid)
    );

    create table if not exists qwiki_property (
      qwikid    string references qwiki (qwikid) ON UPDATE CASCADE ON DELETE CASCADE,
      field      string,
      value      string,
      primary key (qwikid,field)
    );

    create table if not exists qwiki_link (
      linktype string,
      qwiki integer references qwiki (qwikid) ON UPDATE CASCADE ON DELETE CASCADE,
      refqwiki integer references qwiki (qwikid)  ON UPDATE CASCADE ON DELETE CASCADE
    );
    
    -- Generate initial content
    insert into qwiki(qwikid,title,class,format,page) VALUES (local.homepage,'Home','page','markdown','Welcome to Qwiki!');
    -- Generate a FTS
    CREATE VIRTUAL TABLE qwiki_search USING fts4(title, body);
  }

  
}

tao::class httpd.qwiki {
  superclass httpd.community

  constructor {virtual {localopts {}} args} {
    my configurelist [list virtual $virtual threadargs $args {*}$localopts]
    ::Url_PrefixInstall $virtual [namespace code {my httpdDirect}] {*}$args
    my initialize
  }

  method active_layers {} {
    return {
      user    {prefix uid class community.layer.user}
      group   {prefix gid class community.layer.group}
      session {prefix sesid class community.layer.session}
      acl     {prefix acl class community.layer.acl}
      wiki    {prefix wiki class qwiki.layer.wiki}
    }
  }
  
  method /html args {
    my layer wiki /html local.homepage
  }


}

package provide httpd::qwiki 0.1

Added modules/tao-sqlite/connection.tcl.































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
###
# topic: 1f4bc558d601dd0621d4f441fcf94b07
# title: High level database container
# description:
#    A taodb::connection
#    <p>
#    This object is assumed to be a nexus of an sqlite connector
#    and several subject objects to manage the individual tables
#    accessed by this application.
###
tao::class taodb::connection {
  superclass tao.onion
  property docentry {}

  ###
  # topic: 124b0e5697a3e0a179a5bc044c735a54
  ###
  method active_layers {} {
    # Return a mapping of tables to their handler classes
    return {}
  }

  ###
  # topic: ad8b51dd1884240d87d7a99ee2a8b862
  ###
  method Database_Create {} {
  }

  ###
  # topic: 7cb96867401c18478a3dfb74b4cd37d8
  ###
  method Database_Functions {} {
  }

  ###
  # topic: 62f531b6d83adc8a10d15b27ec17b675
  ###
  method schema::create_sql {} {
    set result [my property schema create_sql]
    foreach {layer obj} [my layers] {
      set table [$obj property schema table]
      append result "-- BEGIN $table" \n
      append result [$obj property schema create_sql] \n
      append result "-- END $table" \n
    }
    return $result
  }

  ###
  # topic: fb34f12af081276e36172acfbbea52cf
  ###
  method schema::tables {} {
    set result {}
    foreach {layer obj} [my layers] {
      set table [$obj property schema table]
      lappend result $table
    }
    return $result
  }
}

###
# topic: eaf5daa1dd0baa5e8501e97af3224656
# title: High level database container
# description: A taodb::connection implemented for sqlite
###
tao::class taodb::connection.sqlite {
  superclass taodb::connection tao::onion
  aliases moac.sqliteDb


  option filename {
    widget filename
    extensions {.sqlite {Sqlite Database}}
  }

  option read-only {
    default 0
    widget boolean
  }
  
  option timeout {
    default 30000
    type integer
  }

  ###
  # topic: f71dcb5b2e2312180e379356f3263ff9
  ###
  method attach_sqlite_methods sqlchan {
    my graft db $sqlchan
foreach func {
authorizer
backup
busy
cache
changes
close
collate
collation_needed
commit_hook
complete
copy
enable_load_extension
errorcode
eval
exists
function
incrblob
last_insert
last_insert_rowid
nullvalue
one
onecolumn
profile
progress
restore
rollback_hook
status
timeout
total_changes
trace
transaction
unlock_notify
update_hook
version
    } {
        my forward $func $sqlchan $func
    }
  }

  ###
  # topic: 93c3c991254fd21abc02add7babe5b51
  # title: Evaluate an SQL expression that alters the database
  # description:
  #    This method is a wrapper around "eval" that will catch
  #    "not authorized" messages and give the user some notice that
  #    they should rename the file before altering it.
  ###
  method change args {
    if {[my cget read-only]} {
      my message readOnlyDatabase
      return
    }
    uplevel 1 [list [self] eval {*}$args]
  }

  ###
  # topic: 8a8ecce021e1fcbf8fc25be3ce4cd1d5
  ###
  method Database {submethod args} {
    return [my Database_$submethod {*}$args]
  }

  ###
  # topic: ba1114cdc19c7835f848f9c6ce2f21c7
  ###
  method Database_Attach filename {
    set alias db
    if { $filename in {:memory: {}}} {
      set exists 0
    } else {
      set exists [file exists $filename]
    }
    my put filename $filename
    set objname [my SubObject $alias]
    sqlite3 $objname $filename
    ###
    # Register our busy method
    ###
    $objname busy [namespace code {my Database_Busy}]
    ###
    # Wait up to 2 seconds for
    # a busy database
    ###
    $objname timeout [my cget timeout]
    my graft $alias $objname
    my Database_Functions
    my attach_sqlite_methods $objname
    if {!$exists} {
      my Database_Create
    }
  }
  
  ###
  # Perform a daily backup of the database
  ###
  method Database_Backup {} {
    set filename [my cget filename]
    set now [clock seconds]
    set today [clock format $now -format "%Y-%m-%d-%H"]
    set path [file join [file dirname $filename] backups]
    if {![file exists $path]} {
      file mkdir $path
    }
    set bkuplink [file join $path [file rootname $filename].latest.sqlite]
    file delete $bkuplink
    set bkupfile [file join $path [file tail [file rootname $filename]].$today.sqlite]
    my <db> backup $bkupfile
    file link $bkuplink $bkupfile
    
    ###
    # Keep:
    # * one backup per hour for the past day
    # * one backup per day for the past week
    # * one per week for the past 2 months
    # * one per month for the past year
    # * one every 6 months for years beyond
    ###
    set day [expr {3600*24}]
    set week [expr {$day*7}]
    set month [expr {$week*4}]
    set year [expr {$month*12}]
    set halfyear [expr {$month*6}]    

    
    foreach file [glob -nocomplain [file join $path *.sqlite]] {
      set age [expr {$now - [file mtime $file]}]
      if { $age < $day } continue
      if { $age < $week } {
        lappend daily([expr {$age/$day}]) $age $file
        continue
      }
      if { $age < ($month*2) } {
        lappend weekly([expr {$age/$week}]) $age $file
        continue
      }
      if { $age < ($halfyear*2) } {
        lappend monthly([expr {$age/$month}]) $age $file
        continue
      }
      lappend halfyearly([expr {$age/$halfyear}]) $age $file
    }

    foreach {bin backups} [array get daily] {
      foreach {mtime file} [lrange [lsort -stride 2 -integer $backups] 2 end] {
        file delete $file
      }
    }
    foreach {bin backups} [array get weekly] {
      foreach {mtime file} [lrange [lsort -stride 2 -integer $backups] 2 end] {
        file delete $file
      }
    }
    foreach {bin backups} [array get monthly] {
      foreach {mtime file} [lrange [lsort -stride 2 -integer $backups] 2 end] {
        file delete $file
      }
    }
    foreach {bin backups} [array get halfyearly] {
      foreach {mtime file} [lrange [lsort -stride 2 -integer $backups] 2 end] {
        file delete $file
      }
    }
  }
  
  ###
  # topic: 6319133f765170f9949de3e3329bf07f
  # description:
  #    Action to perform when database is busy
  #    return "1" to cause action to fail,
  #    0 to allow Sqlite to wait and try again
  ###
  method Database_Busy {} {
    after 1
    return 0
  }

  ###
  # topic: 4251a1e7abd66d20c66f9dcd25bb1e54
  # description:
  #    Deep wizardry
  #    Disable journaling and disk syncronization
  #    If the app crashes, we really don't give a
  #    rat's ass about the output, anyway
  ###
  method journal_mode onoff {
    # Store temporary tables in memory
    if {[string is false $onoff]} {
      my <db> eval {
PRAGMA synchronous=0;
PRAGMA journal_mode=MEMORY;
PRAGMA temp_store=2;
      }
    } else {
      my <db> eval {
PRAGMA synchronous=2;
PRAGMA journal_mode=DELETE;
PRAGMA temp_store=0;
      }
    }
  }

  ###
  # topic: 9363820d1352dc0b02d8b433be02a5b7
  ###
  method message::readonly {} {
    error "Database is read-only"
  }

  ###
  # topic: 29d3a99d20a7f3aaa7911b2666bdf17e
  ###
  method native::table_info table {
    set info {}
    my one {select type,sql from sqlite_master where tbl_name=$table} {
      foreach {type field value} [::schema::createsql_to_dict $sql] {
        dict set info $type $field $value
      }
    }
    return $info
  }

  ###
  # topic: df7ff05563eae14512f945ac80b18ea6
  ###
  method native::tables {} {
      return [my eval {SELECT name FROM sqlite_master WHERE type ='table'}]
  }

  ###
  # topic: 4e2dc71f459beab3d31cd49f012340fb
  ###
  method Option_set::filename filename {
    my Database_Attach $filename
  }

  ###
  # topic: d5591c09b59c6a8d50001af79d108e13
  ###
  method SubObject::db {} {
    return [namespace current]::Sqlite_db
  }
}

Added modules/tao-sqlite/index.tcl.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package provide tao-sqlite 0.3

package require tao
package require sqlite3
package require sha1 2
::tao::module push tao-sqlite

::namespace eval ::taodb {}

::tao::load_path [::tao::script_path] {
  procs.tcl connection.tcl oosqlite.tcl module.tcl
}
::tao::module pop

Added modules/tao-sqlite/module.tcl.

















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
###
# topic: d3e536874747b4e5a6b879e6f2422cd4
# description: Modules are objects that wrap around sqlite connections
###
tao::class taodb::module.sqlite {
  superclass taodb::connection.sqlite
  
  constructor filename {
    package require sqlite3
    
    if [catch {
      my Database_Attach $filename
      ###
      # Allow up to 2 seconds of
      # slack time for another process to
      # write to the database
      ###
      my <db> timeout 2000
    }] {
      puts "Falling back to temporary storage"
      my Database_Attach {}
    }
    return 0
  }

  ###
  # topic: 6292ac0c78dbb91c7aaa629f48a301a3
  ###
  method Database_Create {} {
    my <db> eval [my property schema create_sql]
  }

  ###
  # topic: 582bb8d10136f632866e73a6b72a9c32
  ###
  method Database_Functions {} {
    my <db> function uuid_generate ::tao::uuid_generate
  }
}

Added modules/tao-sqlite/oosqlite.tcl.



































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
###
# topic: 4f78c3dbc3f04099f8388b0aaf87df97
# description:
#    This class abstracts the normal operations undertaken
#    my containers and nodes that write to a single data table
###
tao::class taodb::table {
  aliases moac.sqliteTable
  superclass

  # Properties that need to be set:
  # table - SQL Table
  # primary_key - Primary key for the sql table
  # default_record - Key/value list of defaults
  

  ###
  # topic: 6283f1ecde341c8b7dc0199226cfad86
  # title: Delete a record from the database backend
  ###
  method db_record_delete nodeid {
    set table [my property schema table]
    set primary_key [my property schema primary_key]
    my <db> change "delete from $table where $primary_key=:nodeid"
  }

  ###
  # topic: d4c5e9cfea2fa029e80ac21e3173a702
  ###
  method db_record_exists nodeid {
    set table [my property schema table]
    set primary_key [my property schema primary_key]
    return [my <db> exists "select $primary_key from $table where $primary_key=:nodeid"]
  }

  ###
  # topic: e1e4bb66d9cfc158ec9dfb8e13cfe0ce
  # title: Detect record key
  # description: The nodeid of this table from a key/value list of table contents
  ###
  method db_record_key record {
    set primary_key [my property schema primary_key]
    if {[dict exists $record $primary_key]} {
      return [dict get $record $primary_key]
    }
    if {[dict exists $record rowid]} {
      return [dict get $record rowid]
    }
    error "Could not locate the primary key"
  }

  ###
  # topic: 505661a4862772908e986e255ffe1f79
  # description: Read a record from the database
  ###
  method db_record_load {nodeid {arrayvar {}}} {
    if { $arrayvar ne {} } {
      upvar 1 $arrayvar R
    }
    set table [my property schema table]
    if {$nodeid eq {}} {
      return {}
    }
    my <db> eval "select * from $table where rowid=:nodeid" R {}
    unset -nocomplain R(*)
    return [array get R]
  }

  ###
  # topic: 37e78a4cf9ab491f9894c28a128922e4
  # title: Return a record number for a new entry
  ###
  method db_record_nextid {} {
    set primary_key [my property schema primary_key]
    set maxid [my <db> one "select max($primary_key) from [my property schema table]"]
    if { ![string is integer -strict $maxid]} {
      return 1
    } else {
      return [expr {$maxid + 1}]
    }
  }

  ###
  # topic: 0960b530335749a9315d8d05af8c02c2
  # description:
  #    Write a record to the database. If nodeid is negative,
  #    create a new record and return its ID.
  #    This action will also perform any container specific prepwork
  #    to stitch the node into the model, as well as re-read the node
  #    from the database and into memory for use by the gui
  ###
  method db_record_save {nodeid record} {
    appmain signal  dbchange

    set table [my property schema table]
    set primary_key [my property schema primary_key]
    
    set now [clock seconds]
    if { $nodeid < 1 || $nodeid eq {} } {
      set nodeid [my db_record_nextid]
    }
    if {![my <db> exists "select $primary_key from $table where rowid=:nodeid"]} {
      my <db> change "INSERT INTO $table ($primary_key) VALUES (:nodeid)"
      foreach {var val} [my property default_record] {
        if {![dict exists $record $var]} {
          dict set record $var $val
        }
      }
    }
    set oldrec [my db_record_load $nodeid]
    set fields {}
    set values {}
    set stmt "UPDATE $table SET "
    set stmtl {}
    set columns [dict keys $oldrec]
    
    foreach {field value} $record {
        if { $field in [list $primary_key mtime uuid] } continue
        if { $field ni $columns } continue
        if {[dict exists $oldrec $field]} {
            # Screen out values that have not changed
            if {[dict get $oldrec $field] eq $value } continue
        }
        lappend stmtl "$field=\$rec_${field}"
        set rec_${field} $value
    }
    if { $stmtl == {} } {
        return 0
    }
    if { "mtime" in $columns } {
      lappend stmtl "mtime=now()"
    }
    append stmt [join $stmtl ,]
    append stmt " WHERE $primary_key=:nodeid"
    my <db> change $stmt
    return $nodeid
  }
}

###
# topic: 9032e81e051b67fa089f1326da6081f1
# description:
#    Managing records for tables that consist of a primary
#    key and a blob field that contains a key/value list
#    that represents the record
###
tao::class taodb::table.blob {
  aliases moac.sqliteTable.blob
  superclass

  ###
  # topic: 24d95fd922c7d9d188b60b35b382b8dd
  ###
  method db_record_delete nodeid {
    set table        [my property schema table]
    set primary_key  [my property schema primary_key]
    my <db> one "delete from $table where $primary_key=:nodeid"
  }

  ###
  # topic: c4c57639b09ab0f1bd81700cabd6ab88
  ###
  method db_record_load {nodeid {arrayvar {}}} {
    set table  [my property schema table]
    set vfield [my property field_value]
    set primary_key [my property schema primary_key]
    
    if { $arrayvar ne {} } {
      upvar 1 $arrayvar R
      array set R [my <db> one "select $vfield from $table where $primary_key=:nodeid"]
      return [array get R]
    } else {
      return  [my <db> one "select $vfield from $table where $primary_key=:nodeid"]
    }
  }

  ###
  # topic: 268efa2a6aac3451f3e5e525013ec091
  ###
  method db_record_save {nodeid record} {
    set table  [my property schema table]
    set vfield [my property field_value]
    set primary_key [my property schema primary_key]
    
    set result [my property default_record]
    foreach {var val} [my <db> one "select $vfield from $table where $primary_key=:nodeid"] {
      dict set result $var $val
    }
    foreach {var val} $record {
      dict set result $var $val
    }
    my <db> eval "update $table set $vfield=:result where $primary_key=:nodeid"
  }
}

###
# topic: df933b39a39e106c1c0b3f8651d4b5b7
# description:
#    Managing records for tables that consist of a primary
#    key a column representing a "field" and another
#    column representing a "value"
###
tao::class taodb::table.keyvalue {
  aliases moac.sqliteTable.keyvalue
  superclass

  ###
  # topic: c32d751f91d518b47ad400ef04e4f719
  ###
  method db_record_delete nodeid {
    set table        [my property schema table]
    set primary_key  [my property schema primary_key]
    my <db> one "delete from $table where $primary_key=:nodeid"
  }

  ###
  # topic: 34b5a0fefa9a9655a3f8184c3eb640a9
  ###
  method db_record_load nodeid {
    set table  [my property schema table]
    set ffield [my property field_name]
    set vfield [my property field_value]
    set primary_key [my property schema primary_key]

    set result [my property default_record]
    my <db> eval "select $ffield as field,$vfield as value from $table where $primary_key=:nodeid" {
      dict set result $field $value
    }
    return $result
  }

  ###
  # topic: 176679ea4e972f4eac12d4325979369e
  ###
  method db_record_save {nodeid record} {
    set table  [my property schema table]
    set ffield [my property field_name]
    set vfield [my property field_value]
    set primary_key [my property schema primary_key]
    
    set oldrecord [my db_record_load $nodeid]
    foreach {var val} $record {
      if {[dict exists $oldrecord $var]} {
        if {[dict get $oldrecord $var] eq $val } continue
      }
      dict set outrecord $var $val
    }
    if {![llength $outrecord]} return
    
    my <db> transaction {
      foreach {var val} $outrecord {
        my <db> change "insert or replace into $table ($primary_key,$ffield,$vfield) VALUES (:nodeid,$var,$val)"
      }
    }
  }
}

Added modules/tao-sqlite/pkgIndex.tcl.

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded ::tao::helpdoc 0.1 [list source [file join $dir yggdrasil.tcl]]
package ifneeded tao-sqlite 0.3 [list source [file join $dir index.tcl]]

Added modules/tao-sqlite/prefdb.tcl.









































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
###
# topic: a499aa36ee878a743ac8a269bfd3a1e3
# description: Sqlite based storage for application settings
###
tao::class taodb::prefdb {
  superclass taodb::module.sqlite

  property create_sql {
create table prefs (
  field string,
  value string,
  mtime integer,
  primary key (field)
);
create table history (
  field string,
  value string,
  mtime integer,
  primary key (field,value) on conflict replace
);
create index historyMtime on history (mtime);
}

  ###
  # topic: bd83ad1abbfc4516fd6adc5d6ddfd553
  ###
  method create_temp_tables {} {
create table property (
  node  string,
  field string,
  value string,
  primary key (node,field) on conflict replace
);
  }
}

Added modules/tao-sqlite/procs.tcl.

































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
::namespace eval ::tao {}

###
# topic: 0a19b0bfb98162a8a37c1d3bbfb8bc3d
# description:
#    Because the tcllib version of uuid generate requires
#    network port access (which can be slow), here's a fast
#    and dirty rendition
###
proc ::tao::uuid_generate args {
  if {![llength $args]} {
    set block [list [incr ::tao::nextuuid] {*}$::tao::UUID_Seed]
  } else {
    set block $args
  }
  return [::sha1::sha1 -hex [join $block ""]]
}

###
# topic: ee3ec43cc2cc2c7d6cf9a4ef1c345c19
###
proc ::tao::uuid_short args {
  if {![llength $args]} {
    set block [list [incr ::tao::nextuuid] {*}$::tao::UUID_Seed]
  } else {
    set block $args
  }
  return [string range [::sha1::sha1 -hex [join $block ""]] 0 16]
}

###
# topic: b14c505537274904578340ec1bc12af1
# description:
#    Implementation the uses a compiled in ::md5 implementation
#    commonly used by embedded application developers
###
namespace eval ::tao {
  namespace export *

  ###
  # Cache the bits of the UUID seed that aren't likely to change
  # once the software is loaded, but which can be expensive to
  # generate
  ###
  variable ::tao::UUID_Seed [list [info hostname] [get env(USER)] [get env(user)] [clock format [clock seconds]]]
}


Added modules/tao-sqlite/record.tcl.





















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
###
# topic: 49fee6ecf96ef7b3d3ecd7565a047b20
# title: Generic class to process database records
###
tao::class taodb::record {
  superclass
  
  option layer {
    class organ
    description {Object which abstracts access to the underlying storage}
  }
  property variable nodeid {default -1}
  property variable unit   {default {}}  
  property array db_record {}
  property array db_specs  {}

  ###
  # topic: b5cf9de15d1e7c7fead7b5794acb59db
  ###
  method action::delete {} {
    set objid [my objid]
    # Note: we are counting on the layer's node_edit_delete
    # method to call our destructor and/or destroy our window
    my layer db_record_delete $objid
  }

  ###
  # topic: 1d8ca0d3c3b915fadae5f1edb4343833
  ###
  method action::destroy {} {}

  ###
  # topic: fa3fbe68c3a633950547bbe096dd762d
  ###
  method action::save {
    my variable db_record
    set pkey [my <layer> db_record_key [array get db_record]]
    set savedata [array get db_record]
    my <layer> db_record_
  }
}

Added modules/tao-sqlite/tao-sqlite.md.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Back to [tao](../tao.md)

tao-sqlite is a module of related classes which act as ambassadors to **sqlte** database connections.

# Sub-Modules

[yggdrasil](yggdrasil.md)

# Core Classes

## class taodb::connection

Implements a generic wrapper around a database connection. (Note: at this
point only sqlite has been developed.)

Ancestors: [tao.onion](../tao/onions.md)

### Methods

#### method active_layers

Return a list of database layers to act as ambassodors for various
collections of tables. See [onions](../tao/onions.md)

#### method Database_Create

Commands to invoke when the interface attempts to connect to a virgin
database. This method should build the database schema and populate any
starter data.

#### method Database_Functions

Inject functions into the database interface. For sqlite, this method
invokes the interface's native *function* method to map an sqlite function
to a Tcl command.

#### Ensemble schema

Ensemble to manage database schemas.

##### method schema create_sql

Return fully formed SQL code to implement the schema

The default implementation
is to interrogate the object layers for a *schema create_sql* property.

##### method schema tables

Return a list of tables specified by the schema. The default implementation
is to interrogate the object layers for a *schema table* property.


Added modules/tao-sqlite/yggdrasil.md.

Added modules/tao-sqlite/yggdrasil.tcl.





















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
###
# Structure that manages an interactive help system
###
package provide ::tao::helpdoc 0.1

###
# topic: f5641520f17f23259b96facbe936c875
###
tao::class taodb::yggdrasil {
  aliases tao.yggdrasil
  superclass taodb::module.sqlite
  
  property schema create_sql {
    CREATE TABLE if not exists config(
      name TEXT PRIMARY KEY,
      value ANY
    );
    create table if not exists entry (
      entryid string default (uuid_generate()),
      indexed integer default 0,
      parent integer references entry (entryid),
      class string,
      name string,
      mtime integer,
      primary key (entryid)
    );
    create table if not exists property (
      entryid    string references entry (entryid),
      field      string,
      value      string,
      primary key (entryid,field)
    );
    create table if not exists link (
      linktype string,
      entry integer references entry (entryid),
      refentry integer references entry (entryid)
    );
    create table if not exists idset (
      class string,
      id    integer,
      name  string,
      primary key (class,id)
    );
    create table if not exists aliases (
      class string,
      alias string,
      cname string references entry (name),
      primary key (class,alias)
    );
    create table if not exists repository (
      handle string,
      localpath string,
      primary key (handle)
    );
    create table if not exists file (
      fileid         string default (uuid_generate()),
      repo           string references repository (handle),
      path           string,  --path relative to repo
      localpath      string,  --cached path to local file
      filename       string,  --filename
      content_type   string,  --Content/Type of file
      package        string,  --Name of any packages provided,
      size           integer, --File size in bytes
      mtime          integer, --mtime in unix time
      hash           string,   --md5 hash of file
      primary key (fileid)
    );
    create table if not exists filelink (
      linktype string,
      entryid integer references entry (entryid),
      fileid integer references file   (fileid)
    );
  }
  
  
  property create_index_sql {
    create index if not exists nameidx on entry (entryid,name);
    create index if not exists parentidx on entry (parent,entryid);    
  }
  

  ###
  # topic: ce057acc3716a2d568a7031702a08db6
  ###
  method alias_list class {
    return [my <db> eval {select alias,cname from aliases where class=:class order by cname,alias}]
  }

  ###
  # topic: 181987917bb442b19b20c6a381b68e65
  ###
  method canonical {class name} {
    set name [string tolower $name]
    if { $class in {{} * any}} {
      return [my <db> eval {select distinct class from aliases order by class}]
    }
    if { $name in {{} * any}} {
      return [my <db> eval {select alias,cname from aliases where class=:class order by cname,alias}]
    }
    set rows [my <db> eval {select entryid from entry where class=:class and name=:name}]
    if {[llength $rows] == 1} {
      return $name
    }
    if {[my <db> exists {select cname from aliases where class=:class and (alias=:name or cname=:name)}]} {
      return [my <db> one {select cname from aliases where class=:class and (alias=:name or cname=:name) limit 1}]
    }
  }

  ###
  # topic: e1fb31429cfba5b9c8939b3089d7dccf
  ###
  method canonical_aliases {class name} {
    set name [string tolower $name]
    return [my <db> eval {select distinct alias from aliases where class=:class and cname=:name and alias!=:name}]
  }

  ###
  # topic: 9892395f48e5568923ee0516ca23313a
  ###
  method canonical_id {class name} {
    return [my <db> eval {select id from idset where class=:class and name=:name}]
  }

  ###
  # topic: 0e2b411c94df5cdc082f6d909045f44c
  ###
  method canonical_set {type name cname} {
    set class [string tolower $type]
    set name [string tolower $name]
    set cname [string tolower $cname] 
    variable canonical_name
    dict set canonical_name $class $name $cname
    set address $type/$name
    my <db> eval {replace into aliases (class,alias,cname) VALUES ($class,$name,$cname)}
  }

  ###
  # topic: a3ee1a620e5659107eea8b3f9ef38b0d
  ###
  method class_list class {
    return [lsort -dictionary [my <db> eval {select name from entry where class=:class}]]
  }

  ###
  # topic: 7e5caa43f37e38328ca83784db16face
  ###
  method class_nodes class {
    set result {}
    foreach {entryid name} [my <db> eval {select entryid,name from entry where class=:class order by name}] {
      lappend result $name [my node_properties $entryid]
    }
    return $result
  }

  ###
  # topic: 85fa5fdaecfbc8a8236d726b37adc8b8
  ###
  method enum_dump class {
    return [my <db> eval {select id,name from idset where class=:class order by id}]
  }

  ###
  # topic: 54b27245e29c98708a964c0739583737
  ###
  method enum_id {class name} {
    set arr ::irm::${class}_name_to_idx
    if {![info exists $arr]} {
      my <db> eval {select name as aname,id as aid from idset where class=:class} {
        set ${arr}($aname) $aid
      }
    }
    set cname [my canonical $class $name]
    if {![info exists ${arr}($cname)]} {
      error "Invalid $class $name"
    }
    return [set ${arr}($cname)]
  }

  ###
  # topic: 944e9861c8d04a693896c7a093bcb641
  ###
  method enum_name {class id} {
    return [my <db> one {select name from idset where class=:class and id=:id}]
  }

  ###
  # topic: ff79f9268801cbdbf06bee1d0827a8ed
  ###
  method enum_set {class name id} {
    set class [string tolower $class]
    set name [string tolower $name]
    set ::irm::${class}_name_to_idx($name) $id
    set ::irm::${class}_idx_to_name($id) $name
    my <db> eval {insert or replace into idset (class,id,name) VALUES ($class,$id,$name)}
  }

  ###
  # topic: 848689c2e58328b9da8b97afee687e52
  ###
  method file_hash {rawfileid {newhash {}}} {
    set fileid [my file_id $rawfileid]
    if {$fileid ne {}} {
      return [my <db> one {select hash from file where fileid=:fileid}]
    }
    return {}
  }

  ###
  # topic: 438f616e49033a8d7215330112d314ad
  ###
  method file_id {addr {create 0}} {
    if {[my <db> exists {select fileid from file where fileid=:addr}]} {
      return $addr
    }
    if {[my <db> exists {select fileid from file where hash=:addr}]} {
      return [my <db> one {select fileid from file where hash=:addr}]
    }
    if {[llength $addr]==2} {
      set repo [lindex $addr 0]
      set path [lindex $addr 1]
      if {[my <db> exists {select fileid from file where repo=:repo and path=:path}]} {
        return [my <db> one {select fileid from file where repo=:repo and path=:path}]
      }
    }
    if {[my <db> exists {select fileid from file where path=:addr}]} {
      return [my <db> one {select fileid from file where path=:addr}]
    }
    if {[my <db> exists {select fileid from file where localpath=:addr}]} {
      return [my <db> one {select fileid from file where localpath=:addr}]
    }
    if {$create} {
      set newuuid [my <db> one {select uuid_generate()}]
      if {[llength $addr]==2} {
        set repo [lindex $addr 0]
        set path [lindex $addr 1]
        my <db> eval {insert into file (fileid,repo,path) VALUES (:newuuid,:repo,:path);}
      } else {
        my <db> eval {insert into file (fileid,path) VALUES (:newuuid,:path);}
      }
      return $newuuid
    }
    return {}
  }

  ###
  # topic: c2cab41e44bb7cdcca831e05aa5ef902
  ###
  method file_restore {nodeid info} {
    set stmtl {}
    dict with info {}
    set fileid [my file_id $nodeid 1]
    set stmt "UPDATE file SET "
    set stmtl {}
    foreach {field value} $info {
      switch $field {
        repo -
        path -
        localpath -
        filename -
        content_type -
        package -
        size -
        mtime -
        hash {
          if { $value ne {} } {
            set _$field $value
            lappend stmtl "$field=:_${field}"
          }
        }
      }
    }
    if {![llength $stmt]} return
    append stmt "[join $stmtl ,]"
    append stmt " where fileid=:fileid"
    my <db> eval $stmt
  }

  ###
  # topic: fba89244d9f7fba909fb01dc7a25535a
  ###
  method file_serialize nodeid {
    set result {}
    my <db> eval {
      select * from file
      where fileid=$nodeid
    } record {
      set fileid $record(fileid)
      append result "[list [self] file_restore [list $record(repo) $record(path)]] \{" \n
      
      foreach {field value} [array get record] {
        if { $field in {* fileid indexed export} } continue
        append result "  [list $field $value]" \n
      }
      append result "\}"
    }
    return $result
  }

  ###
  # topic: f8abb1cd4c82172741704b789371c706
  # title: Build a full text index
  ###
  method full_text_index {{force 0}} {
    my <db> eval {
    CREATE TABLE if not exists config(
      name TEXT PRIMARY KEY,
      value ANY
    );
    }
    if {!$force && [my <db> exists {select * from config where name='fts_indexed' and value='1'}]} {
      return
    }
    
    my <db> eval {
DROP TABLE IF EXISTS search;
CREATE VIRTUAL TABLE search USING fts4(uuid,class,title,body);
insert into search (uuid,class,title,body)
  SELECT entry.entryid,entry.class,entry.name,property.value
  FROM entry,property where entry.entryid=property.entryid and field='description';

INSERT OR REPLACE INTO config(name,value) VALUES ('fts_indexed',1);
    }
  }

  ###
  # topic: 6892a2438c56b5e207888f6683d684cc
  ###
  method link_create {entryid to {type {}}} {
    if { $type eq {} } {
      set exists [my one {select count(entry) from link where entry=$entryid and refentry=$to}]
      if {!$exists} {
        my <db> eval {insert or replace into link (entry,refentry) VALUES ($entryid,$to)}
      }
    } else {
      set exists [my one {select count(entry) from link where entry=$entryid and refentry=$to and linktype=$type}]
      if {!$exists} {
        my <db> eval {insert or replace into link (entry,refentry,linktype) VALUES ($entryid,$to,$type)}
      } 
    }
  }

  ###
  # topic: bebaa55db9d00f615f4c3e589b9f5cca
  ###
  method link_detect_address args {
    set args [string tolower $args]
    if {[my node_exists $args entryid]} {
      return [my <db> eval {select entryid from entry where entryid=$entryid}]
    }
    ###
    # If the link contains a / we know it is a hard
    # path
    ###
    if {[my node_exists $args entryid]} {
      return $entryid
    }
    if {[llength $args] > 1} {
      set rootentries [my <db> eval {select name from entry where class='section'}]
      
      if {[lindex $args 0] in $rootentries} {
        set type [lindex $args 0]
        set name [my canonical $type [lindex $args 1]]
        if {[my node_exists [list $type $name] entryid]} {
          return $entryid
        }
      }
      if {[lindex $args 1] in $rootentries} {
        set type [lindex $args 1]
        set name [my canonical $type [lindex $args 0]]
        if {[my node_exists [list $type $name] entryid]} {
          return $entryid
        }
      }
    }
    set addr [lindex $args 0]
    set cnames [my <db> eval {select class,cname from aliases where alias=$addr}]
  
    if {[llength $cnames] == 2} {
      if {[my node_exists $cnames entryid]} {
        return $entryid
      }
    }
    #if {[string first / $addr] > 0 } {
    #  return $addr
    #}
    set candidates [my <db> eval {select entryid,name from entry where name like '%$addr%'}]
    foreach address $candidates {
      if {[regexp simnode $address]} {
        return $address
      }
    }
    #puts [list CAN'T RESOLVE $args]
    return $args
  }

  ###
  # topic: 4be4c2c74388621448494e1ced97fccb
  # description:
  #    Return a list of all children of node,
  #    Filter is a key/value list that understands
  #    the following:
  #    type - Limit children to type
  #    dump - Output the contents of the child node, not their id
  ###
  method node_children {nodeid class} {
    set dump 1
    set entryid [my node_id $nodeid]
    if { $class eq {} } {
      set nodes [my <db> eval {select name,entryid from entry where parent=$entryid}]
    } else {
      set nodes [my <db> eval {select name,entryid from entry where parent=$entryid and class=$class}]
    }
    if {!$dump} {
      return $nodes
    }
    set result {}
    foreach {cname cid} $nodes {
      dict set result $cname [my <db> eval {select field,value from property where entryid=$cid order by field}]
    }
    return $result
  }

  ###
  # topic: 1ddcdaedcca9f6bf1d17564fc2b80dbe
  ###
  method node_define {class name info {nodeidvar {}}} {
    if {$nodeidvar ne {}} {
      upvar 1 $nodeidvar nodeid
    }
    set class [string tolower $class]
    set name  [string tolower $name]
    if { $class eq {} || $class eq "section" } {
      set nodeid $name
    } else {
      set nodeid {}
      if {[dict exists $info topic]} {
        set nodeid [dict get $info topic]
        dict unset info topic
      }
    }    
    if { $nodeid eq {} } {
      if {![my node_exists [list $class $name] nodeid]} {
        set nodeid [helpdoc node_id [list $class $name] 1]
        foreach {var val} [my node_empty $class] {
          my node_property_set $nodeid $var $val        
        }
      }
    } elseif {![my node_exists $nodeid]} {
      my canonical_set $class $name $name
      my <db> eval {insert into entry (entryid,class,name) VALUES (:nodeid,:class,:name)}
      foreach {var val} [my node_empty $class] {
        my node_property_set $nodeid $var $val        
      }
    }
  
    foreach {var val} $info {
      my node_property_set $nodeid $var $val
    }
  }

  ###
  # topic: 5cf8420243fb46472b33a18cb340f8cf
  ###
  method node_define_child {parent class name info {nodeidvar {}}} {
    if {$nodeidvar ne {}} {
      upvar 1 $nodeidvar nodeid
    }
    ###
    # Return an already registered node with this address
    ###
    if {[my <db> exists {select entryid from entry where parent=:parent and class=:class and name=:name}]} {
      set nodeid [my <db> one {select entryid from entry where parent=:parent and class=:class and name=:name}]
    } else {
      set nodeid {}
  
      if {[dict exists $info topic]} {
        set topicid [dict get $info topic]
        dict unset info topic
        if {![my <db> exists {select entryid from entry where entryid=:topicid}]} {
          # If we are recycling an unused UUID re-create the entry in the table
          my <db> eval {insert or replace into entry (entryid,parent,class,name) VALUES (:topicid,:parent,:class,:name)}
          set nodeid $topicid
        }
      }
      if { $nodeid eq {} } {
        set nodeid [::tao::uuid_generate $parent $class $name]
      }
      if {[my <db> exists {select entryid from entry where entryid=:nodeid and class=:class and name=:name}]} {
        ###
        # Correct a misfiled node
        ###
        my <db> eval {update entry set parent=:parent where entryid=:nodeid}
      } else {
        my <db> eval {insert or replace into entry (entryid,parent,class,name) VALUES (:nodeid,:parent,:class,:name)}
      }
      foreach {var val} [my node_empty $class] {
        if {![dict exists $info $var]} {
          dict set info $var $val
        }
      }
    }
    foreach {var val} $info {
      my node_property_set $nodeid $var $val        
    }
    return $nodeid
  }

  ###
  # topic: 1ce63e18b2072f0218695df90c83b5e6
  ###
  method node_empty class {
    set id [my <db> one {select entryid from entry where name=:class and class='section'}]
    return [my <db> one {select value from property where entryid=:id and field='template'}]
  }

  ###
  # topic: 8a70c9ed461c3728787f2e5385f8be66
  ###
  method node_exists {node {resultvar {}}} {
    set parent 0
    if { $resultvar != {} } {
      upvar 1 $resultvar row
    }
    if {[llength $node]==1} {
      set name [lindex $node 0]
      if {[my <db> exists {select entryid from entry where name=:name or entryid=:name}]} {
        set row [my <db> one {select entryid from entry where name=:name or entryid=:name}]
        return 1
      }
    } elseif {[llength $node]==2} {
      set class [lindex $node 0]
      set name [lindex $node 1]
      if {[my <db> exists {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]} {
        set row [my <db> one {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]
        return 1
      }
    }
    set class [lindex $node 0]
    set name [lindex $node 1]
    if {[my <db> exists {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]} {
      set parent [my <db> one {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]
    } else {
      return 0
    }
    foreach {eclass ename} [lrange $node 2 end] {
      set row {}
      if {$eclass eq {}} {
        if {[my <db> exists {select entryid from entry where parent=:parent and (entryid=:ename or name=:ename)}]} {
          set row [my <db> one {select entryid from entry where parent=:parent and (entryid=:ename or name=:ename)}]
        }
      } else {
        if {[my <db> exists {select entryid from entry where parent=:parent and class=:eclass and (entryid=:ename or name=:ename)}]} {
          set row [my <db> one {select entryid from entry where parent=:parent and class=:eclass and (entryid=:ename or name=:ename)}]
        }
      }
      if { $row eq {} } {
        return 0
      }
      set parent $row
    }
    return 1
  }

  ###
  # topic: 6c3e041a03a5b2bcf5c6fdab1721d7b6
  ###
  method node_get {nodeid {field {}}} {
    set result {}
    if {[my node_exists $nodeid entryid]} {
      set result [helpdoc node_properties $entryid]
    } else {
      if {[llength $nodeid] > 1} {
        set type [lindex $nodeid 0]
        set result [my node_empty $type]
      }
    }
    if { $field eq {} } {
      return $result    
    }
    return [dict getnull $result $field]
  }

  ###
  # topic: bdeb89732bc42953dedf39bce57ab75b
  ###
  method node_id {node {create 0}} {
    if {[my <db> exists {select entryid from entry where entryid=:node;}]} {
      return [my <db> one {select entryid from entry where entryid=:node;}]
    }
    if {[llength $node]==1} {
      set name [lindex $node 0]
      if {[my <db> exists {select entryid from entry where name=:name or entryid=:name}]} {
        return [my <db> one {select entryid from entry where name=:name or entryid=:name}]
      }
      if { $create } {
        my <db> eval {insert into entry (class,name) VALUES ('section',:name)}
        return $name
      } else {
        error "Node $node does not exist"
      }
    } elseif {[llength $node]==2} {
      set class [lindex $node 0]
      set name [lindex $node 1]

      if {[my <db> exists {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]} {
        set row [my <db> one {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]
        return $row
      }
    }
    set class [lindex $node 0]
    set name [lindex $node 1]
    if {[my <db> exists {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]} {
      set parent [my <db> one {select entryid from entry where (class=:class or parent=:class) and (name=:name or entryid=:name)}]
    } else {
      if {!$create} {
        error "Node $node does not exist"
      }

      ###
      # If the name contains no spaces, dots, slashes, or ::
      ###
      set row [::tao::uuid_generate $class $name]
      my <db> eval {insert into entry (entryid,class,name) VALUES (:row,:class,:name)}
      set parent $row
    }
    if { $create } {
      set classes [my <db> eval {select distinct class from entry}]
    }
    set eclass {}
    foreach token [lrange $node 2 end] {
      set ename $token
      set row {}
      if {$eclass eq {}} {
        if {[my <db> exists {select entryid from entry where parent=:parent and (entryid=:ename or name=:ename)}]} {
          set row [my <db> one {select entryid from entry where parent=:parent and (entryid=:ename or name=:ename)}]
        }
      } else {
        if {[my <db> exists {select entryid from entry where parent=:parent and class=:eclass and (entryid=:ename or name=:ename)}]} {
          set row [my <db> one {select entryid from entry where parent=:parent and class=:eclass and (entryid=:ename or name=:ename)}]
        }
      }
      if { $row eq {} } {
        if { $create } {
          if { $ename in $classes } {
            set eclass $token
            continue            
          } else {
            set eclass {}
            my node_define_child $parent $eclass $ename {} row
          }          
        } else {
          error "Node $node does not exist"
        }
      }
      set parent $row
    }
    return $row
  }

  ###
  # topic: 6f5dc7fcf3eb6204800a7b910d283483
  ###
  method node_properties entryid {
    return [my <db> eval {select field,value from property where entryid=$entryid}]
  }

  ###
  # topic: 51611e18a49da769364ef583f439e8a2
  ###
  method node_property_append {nodeid field text} {
    set buffer [my one {select value from property where entryid=:nodeid and field=:field}]
    append buffer " " [string trim $text]
    my <db> eval {insert or replace into property (entryid,field,value) VALUES (:nodeid,:field,:buffer)}
  }

  ###
  # topic: 79b939dca06915d886b2d6c0a393e803
  ###
  method node_property_get {nodeid field} {
    return [my <db> one {select value from property where entryid=:nodeid and field=:field}]
  }

  ###
  # topic: cecb9e2416c9fec272e7beb9d4c183df
  # description: nodeid is any value acceptable to [lb]my node_alloc[rb]
  ###
  method node_property_lappend {entryid field args} {
    if {![llength $args]} return
    set dbvalue [my <db> eval {select value from property where entryid=$entryid and field=$field}]
    foreach value $args {
      if { $value eq {} } continue
      ::ladd dbvalue $value
    }
    my <db> eval {update property set value=$dbvalue where entryid=$entryid and field=$field}
  }

  ###
  # topic: 3f633c4bdd0fe22bb94870976e2e3aa8
  ###
  method node_property_set {entryid args} {
    my variable property_info property_cname
    if {[llength $args]==1} {
      set arglist [lindex $args 0]
    } else {
      set arglist $args
    }
    foreach {field value} $arglist {
      if {[info exists property_cname($field)]} {
        set cname $property_cname($field)
        set rawvalue $value
        eval [dict getnull $property_info $cname script]
      } else {
        set cname $field
      }
      if {![my <db> exists {select value from property where entryid=:entryid and field=:cname and value=:value}]} {
        my <db> eval {insert or replace into property (entryid,field,value) VALUES (:entryid,:cname,:value)}
      }
    }
  }

  ###
  # topic: 7a941df07b5299ec365d98e284ca4442
  ###
  method node_restore {nodeid info} {
    set stmtl {}
    dict with info {}
    set fields entryid
    set _entryid $nodeid
    set values "\$_entryid"
    
    foreach {field value} $info {
      switch $field {
        properties {
          foreach {var val} $value {
            my node_property_set $_entryid $var $val
          }
        }
        references {
          foreach {refid reftype} $references {
            my link_create $_entryid $refid $reftype
          }
        }
        enumid {
          my enum_set [lindex $value 0] [dict get $info name] [lindex $value 1]
        }
        aliases {
          foreach a $value {
            my canonical_set $_class $a $_name
          }
        }
        parent {
          if {![string is integer $value]} {
            set value [my node_id $value 1]
          }
          lappend fields $field
          lappend values "\$_$field"
          set _$field $value            
        }
        class -
        address -
        name {
          if { $value ne {} } {
            lappend fields $field
            lappend values "\$_$field"
            set _$field $value
          }
        }
      }
    }
    my <db> eval "insert or replace into entry ([join $fields ,]) VALUES ([join $values ,]);"
  }

  ###
  # topic: 399c322eb03e90aacbc10ae171557cfd
  ###
  method node_serialize nodeid {
    set result {}
    my <db> eval {
      select * from entry
      where entryid=$nodeid
    } record {
      set entryid $record(entryid)
      append result "[list [self] node_restore $entryid] \{" \n
      
      foreach {field value} [array get record] {
        if { $field in {* entryid indexed export} } continue
        append result "  [list $field $value]" \n
      }
      set class $record(class)
  
      set id [my canonical_id $class $record(name)]
      if { $id ne {} } {
          append result "  [list enumid [list $class $id]]" \n
      }
      
      append result "  properties \{" \n
      set info [my node_empty $record(class)]
      foreach {var val} [my node_properties $entryid] {
        dict set info $var $val
      }

      foreach {var} [lsort -dictionary [dict keys $info]] {
        if { $var in {aliases field method fields methods references id} } continue
        append result "    [list $var [string trim [dict get $info $var]]]" \n
      }
      
      append result "  \}" \n
      set references [my <db> eval {select refentry,linktype from link where entry=$entryid}]
      if {[llength $references]} {
        append result "  [list references $references]" \n
      }
      set aliases [my canonical_aliases $record(class) $record(name)]
      if {[llength $aliases]} {
        append result "  [list aliases $aliases]" \n
      }
      set attachments [my <db> eval {select file.hash,filelink.linktype from file,filelink where filelink.entryid=$entryid and filelink.fileid=file.fileid}]
      if {[llength $attachments]} {
        append result "  [list attachments $attachments]" \n
      }
      append result "\}"
    }
    return $result
  }

  ###
  # topic: 841e0e684d5dd1035ed56316e3a075b2
  ###
  method property_define {property info} {
    my variable property_info property_cname
    foreach {f v} $info {
      dict set property_info $property $f $v
    }
    foreach alias [dict getnull $property_info $property aliases] {
      set property_cname($alias) $property
    }
    set property_cname($property) $property
  }

  ###
  # topic: db9d2312731e0b51f1cf0ce4f597ecdb
  ###
  method reindex {} {
    my variable canonical_name
    my <db> eval {select class,alias,cname from aliases order by class,cname,alias} {
      dict set canonical_name $class $alias $cname
    }
  }

  ###
  # topic: 5b3aeab40382b22c6a5dda372de4faec
  ###
  method repository_restore {handle info} {
    set stmtl {}
    dict with info {}
    set fields handle
    set _handle $handle
    set values "\$_handle"
    foreach {field value} $info {
      switch $field {
        localpath {
          if { $value ne {} } {
            lappend fields $field
            lappend values "\$_$field"
            set _$field $value
          }
        }
      }
    }
    my <db> eval "insert or replace into repository ([join $fields ,]) VALUES ([join $values ,]);"
  }
}

interp alias {} tao.yggdrasil {} ::taodb::yggdrasil

Added modules/tao/db.tcl.



























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
###
# topic: 62313463-3530-3535-3337-3237343930343
###

foreach varname {
  ::tao::info::class
  ::tao::info::object
} {
  if {![info exists $varname]} {
    set $varname {}
  }
}


if {[info command ::tao::db] eq {}} {
  package require sqlite3
  sqlite3 ::tao::db :memory:
  # Build the schema
  ::tao::db function string_match {string match}
  
  ::tao::db eval {
create table class (
  name string primary key,
  package string,
  superclass list default '::tao::moac',
  regenerate integer default 0
);

create table class_property (
  class string references class,
  type  string default const,
  property string,
  dict text,
  primary key (class,type,property) on conflict replace
);

create table class_ensemble (
  class string references class,
  ensemble string,
  method string,
  arglist string,
  body text,
  primary key (class,ensemble,method) on conflict replace
);

create table class_typemethod (
  class string references class,
  method string,
  arglist string,
  body text,
  primary key (class,method) on conflict replace
);

create table class_alias (
  cname string references class,
  alias string references class
);

create table class_ancestor (
  class string references class,
  direct integer default 0,
  seq integer,
  ancestor string references class,
  primary key (class,ancestor) on conflict ignore
);

create table object (
  name string primary key,
  package string,
  regen integer default 0
);

create table object_alias (
  cname string references object,
  alias string references object
);

create table object_bind (
  object string references object,
  event  string,
  script blob,
  primary key (object,event) on conflict replace
);

create table object_schedule (
  object string references object,
  event  string,
  time   integer,
  eventorder  integer default 0,
  script string,
  primary key (object,event) on conflict replace
);

create table object_subscribers (
  sender   string references object,
  receiver string references object,
  event string,
  primary key (sender,receiver,event) on conflict ignore
);
  }
}

###
# topic: b14c505537274904578340ec1bc12af1
###
namespace eval ::tao {
  variable trace 0
}

Added modules/tao/diagram.tcl.



























































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
::namespace eval ::tao {}

###
# topic: 9f2e173840e3307fb6bd47e72e3d2451
# title: Generate a graphviz diagram of the current object hierarchy
###
proc ::tao::diagram {base filename {ignorefunct ::tao::diagram_ignore}} {
  set fout [open $filename w]
  puts $fout {
/*
* @command = dot
*
*/
  }
  puts $fout "digraph g \{"
  puts $fout {
rankdir = LR;
compound=true;

  }
#layout = dot
#compound = true  
#  
  set direct 1
  set classlist {}
  if { $base in {* all}} {
    ::tao::db eval {select name from class order by name} {
      if {[$ignorefunct $name]} continue
      lappend classlist $name
    }
  } else {
    foreach b $base {
      ::tao::db eval {select name from class where package=:b order by name} {
        if {[$ignorefunct $name]} continue
        lappend classlist $name
        ::tao::db eval {select class from class_ancestor where ancestor=:name and direct=1} {
          if { $class in $classlist } continue
          lappend classlist $class
        }
      }
    }
  }
  ::tao::db eval "select * from class where name in ('[join $classlist ',']')" {
    ladd modules($package) $name
    dict set classinfo $name display [diagram_name $name]
    dict set classinfo $name module  $package
    dict set classinfo $name connections [::tao::db eval "select ancestor from class_ancestor where (class=:name and direct=1) order by seq desc;"]
  }
  set graphid 0
  foreach {module mclasses} [lsort -dictionary -stride 2 [array get modules]] {
    puts $fout "  subgraph \"module[incr graphid]\" \{"
    set includes {}
    foreach class $mclasses {
      if {[$ignorefunct $class]} continue
      lappend includes [diagram_name $class]
      set links [dict get $classinfo $class connections]
      foreach {link direct} $links {
        if { $link eq $class } continue
        if {[$ignorefunct $link]} continue
        if {[string is true -strict $direct] } {
          lappend indirect([diagram_name $link]) [diagram_name $class]           
        } elseif { $link in $mclasses } {
          puts $fout "  [diagram_name $link]->[diagram_name $class]\;"
        } else {
          lappend extlinks([diagram_name $link]) [diagram_name $class] 
        }
      }
    }
    #puts $fout "    rank=same; [join $includes \;]"
    puts $fout "    [join $includes \;]"
    puts $fout "    label = \"Module $module\"\;"
    puts $fout "    color=lightgrey;"
    puts $fout "\}"
  }
  
  foreach {class links} [lsort -dictionary -stride 2 [array get extlinks]] {
    foreach link $links {
      puts $fout "  $class->$link\;"
    }
  }

  foreach {class info} [get classinfo] {
    dict with info {}
    puts $fout "$display \[shape = box\; label=\"[string trimleft $class :]\"\]\;"
  }

  puts $fout "\}"
  close $fout
}

###
# topic: c4dd91d51fb5ab26ec90c39ed4dbd306
###
proc ::tao::diagram_class {base filename {show_indirect 0} {ignorefunct ::tao::diagram_ignore}} {

#layout = dot
#compound = true  
#  
  set direct 1
  set classlist {}

  set direct 0
  set classlist $base
  foreach bclass $base {
    ::tao::db eval {select class from class_ancestor where ancestor=:bclass} {
      if { $class in $classlist } continue
      lappend classlist $class
    }
    ::tao::db eval {select ancestor from class_ancestor where class=:bclass} {
      if { $ancestor in $classlist } continue
      lappend classlist $ancestor
    }
  }

  
  ::tao::db eval "select * from class where name in ('[join $classlist ',']')" {
    ladd modules($package) $name
    dict set classinfo $name display [diagram_name $name]
    dict set classinfo $name module  $package
    ::tao::db eval "select ancestor,direct from class_ancestor where (class=:name and ancestor in ('[join $classlist ',']')) order by seq desc;" {
      if {[$ignorefunct $ancestor]} continue
      if { $ancestor eq $name } continue
      if { !$direct } {
        lappend indirect([diagram_name $ancestor]) [diagram_name $name]
      } else {
        lappend extlinks([diagram_name $ancestor]) [diagram_name $name] 
      }
    }
  }
  if {[info exists classinfo]} return

  set fout [open $filename w]
  puts $fout {
/*
* @command = dot
*
*/
  }
  puts $fout "digraph g \{"
  puts $fout {
rankdir = LR;
compound=true;

  }
  foreach {class links} [lsort -dictionary -stride 2 [array get extlinks]] {
    foreach link $links {
      puts $fout "  $class->$link\;"
    }
  }
  if { $show_indirect } {
    puts $fout "  edge \[color=red\]\;"
    foreach {class links} [lsort -dictionary -stride 2 [array get indirect]] {
      foreach link $links {
        puts $fout "  $class->$link\; "
      }
    }
  }
  foreach {class info} $classinfo {
    dict with info {}
    puts $fout "$display \[shape = box\; label=\"[string trimleft $class :]\"\]\;"
  }

  puts $fout "\}"
  close $fout
}

###
# topic: f1b91f039c8be1c604563a6624af84fe
###
proc ::tao::diagram_ignore class {
  if { $class in {::tao::moac ::oo::class ::oo::object} } {
    return 1
  }
  return 0
}

###
# topic: c7e2d0be0393921331e4476ff0a77e5a
###
proc ::tao::diagram_name name {
  set result {}
  foreach i [split $name :] {
    if { $i ne {} } {
      lappend result [join [split $i .] _]
    }
  }
  return [join $result _]
}

Added modules/tao/event.tcl.

























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
###
# This file implements the Tao event manager
###

::namespace eval ::tao {}

::namespace eval ::tao::event {}

###
# topic: 2097c1149d50b67b94ea09f0bcad9e5c
# description: Subscribe an object to events of type <b>event</b>
###
proc ::tao::event::bind {self event args} {
  if {![llength $args]} {
    return [::tao::db one {select script from object_bind where object=:self and event=:event}]
  }
  set script [lindex $args 0]
  if { $script eq {} } {
    ::tao::db eval {delete from object_bind where object=:self and event=:event}
  } else {
    ::tao::db eval {
insert or ignore into object(name) VALUES (:self);
insert or replace into object_bind (object,event,script) VALUES (:self,:event,:script);
}
  }
}

###
# topic: f2853d380a732845610e40375bcdbe0f
# description: Cancel a scheduled event
###
proc ::tao::event::cancel {self {task *}} {
  variable timer_event
  foreach {id event} [array get timer_event $self:$task] {
    ::after cancel $event
    set timer_event($id) {}
  }
}

###
# topic: 8ec32f6b6ba78eaf980524f8dec55b49
# description:
#    Generate an event
#    Adds a subscription mechanism for objects
#    to see who has recieved this event and prevent
#    spamming or infinite recursion
###
proc ::tao::event::generate {self event args} {
  set dictargs [::tao::args_to_options {*}$args]

  set info $dictargs
  set strict 0
  set debug 0
  set sender $self
  dict with dictargs {}
  dict set info id     [::tao::event::nextid]
  dict set info origin $self
  dict set info sender $sender
  dict set info rcpt   {}
  
  
  foreach who [Notification_list $self $event] {
    catch {::tao::event::notify $who $self $event $info}
  }
}

###
# topic: 891289a24b8cc52b6c228f6edb169959
# title: Return a unique event handle
###
proc ::tao::event::nextid {} {
  return "event#[format %0.8x [incr ::tao::event_count]]"
}

###
# topic: 1e53e8405b4631aec17f98b3e8a5d6a4
# description:
#    Called recursively to produce a list of
#    who recieves notifications
###
proc ::tao::event::Notification_list {self event {stackvar {}}} {
  if { $stackvar ne {} } {
    upvar 1 $stackvar stack
  } else {
    set stack {}
  }
  if {$self in $stack} {
    return {}
  }
  lappend stack $self

  ::tao::db eval {select receiver from object_subscribers where string_match(sender,:self) and string_match(event,:event)} {
    ::tao::db eval {select name as rcpt from object where string_match(name,:receiver)} {
      Notification_list $rcpt $event stack
    }
  }
  return $stack
}

###
# topic: b4b12f6aed69f74529be10966afd81da
###
proc ::tao::event::notify {rcpt sender event eventinfo} {
  if {$::tao::trace} {
    puts [list event notify rcpt $rcpt sender $sender event $event info $eventinfo]
  }
  $rcpt notify $event $sender $eventinfo
}

###
# topic: 829c89bda736aed1c16bb0c570037088
###
proc ::tao::event::process {self handle script} {
  variable timer_event
  array unset timer_event $self:$handle
  set err [catch {uplevel #0 $script} result]
  if $err {
    puts "BGError: $self $handle $script
ERR: $result"
  }
}

###
# topic: a6e4eebefcd2cec57ee4f0d8c10c92c0
###
proc ::tao::event::publish {self who event} {
  ::tao::db eval {
insert or ignore into object(name) VALUES (:self);
insert or replace into object_subscribers (sender,receiver,event) VALUES (:self,:who,:event);
}
}

###
# topic: eba686cffe18cd141ac9b4accfc634bb
# description: Schedule an event to occur later
###
proc ::tao::event::schedule {self handle interval script} {
  variable timer_event

  if {$::tao::trace} {
    puts [list $self schedule $handle $interval]
  }
  if {[info exists timer_event($self:$handle)]} {
    ::after cancel $timer_event($self:$handle)
  }
  set timer_event($self:$handle) [::after $interval [list ::tao::event::process $self $handle $script]]
}

###
# topic: 63d680db51c1a3a04c2a038b8f9747d0
###
proc ::tao::event::signal {self event} {
  
}

###
# topic: e64cff024027ee93403edddd5dd9fdde
###
proc ::tao::event::subscribe {self who event} {
  ::tao::db eval {
insert or ignore into object(name) VALUES (:self);
insert or replace into object_subscribers (receiver,sender,event) VALUES (:self,:who,:event);
}
}

###
# topic: 177acc5c440c615437dd02cba0ab778c
###
proc ::tao::event::unpublish {self args} {
  switch {[llength $args]} {
    0 {
      ::tao::db eval {delete from object_subscribers where sender=:self}
    }
    1 {
      set event [lindex $args 0]
      ::tao::db eval {delete from object_subscribers where sender=:self and string_match(event,:event)=1}
    }
  }
}

###
# topic: 5f74cfd01735fb1a90705a5f74f6cd8f
###
proc ::tao::event::unsubscribe {self args} {
  switch {[llength $args]} {
    0 {
      ::tao::db eval {delete from object_subscribers where receiver=:self}
    }
    1 {
      set event [lindex $args 0]
      ::tao::db eval {delete from object_subscribers where receiver=:self and string_match(event,:event)=1}
    }
  }
}

###
# topic: 37e7bd0be3ca7297996da2abdf5a85c7
# description: The event manager for Tao
###
namespace eval ::tao::event {
  variable nextevent {}
  variable nexteventtime 0
}

Added modules/tao/events.md.

Added modules/tao/index.tcl.















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package provide tao 9.4.4
package require sqlite3
package require TclOO
package require listutil 1.7

::namespace eval ::tao {}

###
# topic: f796a2dcb22de645fb365e07d39fce07
###
proc ::tao::load_path {path {ordered_files {}}} {
  if {$::tcl_platform(platform) eq "windows"} {
    if {[string index $path 1] eq ":"} {
      set path [string range $path 2 end]
    }
  }
  lappend loaded index.tcl pkgIndex.tcl
  if {[file exists [file join $path baseclass.tcl]]} {
    lappend loaded baseclass.tcl
    uplevel #0 [list source [file join $path baseclass.tcl]]
  }
  foreach file $ordered_files {
    lappend loaded $file
    uplevel #0 [list source [file join $path $file]]
  }
  foreach file [glob -nocomplain [file join $path *.tcl]] {
    if {[file tail $file] in $loaded} continue
    lappend loaded [file tail $file]
    uplevel #0 [list source $file]
  }
}

###
# topic: b8897eebb90a62e0bac262762116b6b5
###
proc ::tao::script_path {} {
  set path [file dirname [file normalize [info script]]]
  return $path

}

set ::tao::root [::tao::script_path]
::tao::load_path $::tao::root {
  event.tcl
  parser.tcl
  ootools.tcl
  module.tcl
  db.tcl
  moac.tcl
  onion.tcl
  mvc.tcl
}

tao::module pop

Added modules/tao/license.terms.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
TAO - Tcl Architecture of Objects

Copyright (c) 2012, Sean Woods
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Sean Woods, Etoyoc Heavy Industries,
      Test and Evaluation Solutions, nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY SEAN WOODS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL SEAN WOODS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added modules/tao/lutils.tcl.























































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
### BEGIN COPYRIGHT BLURB
#   
#   TAO - Tcl Architecture of Objects
#   Copyright (C) 2003 Sean Woods
#   
#   See the file "license.terms" for information on usage and redistribution
#   of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#   
### END COPYRIGHT BLURB

package provide listutil 1.7

proc ::tcl::mathfunc::pi {} [list return [expr 4.0*atan(1.0)]]
proc ::tcl::mathfunc::pio2 {} [list return [expr 2.0*atan(1.0)]]
proc ::tcl::mathfunc::sqrt2 {} [list return [expr sqrt(2)]]
proc ::tcl::mathfunc::e {} [list return [expr exp(1)]]

# [dict getnull] is like [dict get] but returns empty string for missing keys.
proc ::tcl::dict::getnull {dictionary args} {
  if {[exists $dictionary {*}$args]} {
    get $dictionary {*}$args
  }
}

namespace ensemble configure dict -map [dict replace\
    [namespace ensemble configure dict -map] getnull ::tcl::dict::getnull]

if 0 {
proc ::string::capitalize word {
    # Return $word with its first letter capitalized
    # Needed because sometimes [string totitle] plays games with us
    return [string toupper [string index $word 0]][string range $word 1 end]
}
}

proc iscommand {name} {
    expr {([string length [info command $name]] > 0) || [auto_load $name]}
}

proc makeproc {name arglist body} {
  if {![iscommand $name]} {
    proc $name $arglist $body
  }
}

###
# Make a new md5 command that 
# behaves like the one in tobe
###
if {[info command irmmd5] != {} } {
  makeproc md5Hash string {
    return [irmmd5 $string]
  }
} else {
  package require md5 2.0
  makeproc md5Hash string {
    return [string tolower [::md5::md5 -hex $string]]
  }
}

###
# proc: ::is_zero value
# title: Returns 1 if the value is zero or null
###
makeproc is_zero value {
  if {[string is false $value]} {
    return 1
  }
  if { $value == 0.0 } {
    return 1
  }
  return 0
}

###
# proc: ::is_zero value
# title: Returns 1 if the value is zero or null
###
makeproc if_zero {value replace} {
  if {[string is false $value]} {
    return $replace
  }
  if { $value == 0.0 } {
    return $replace
  }
  return $value
}
###
# proc: ::is_zero value
# title: Returns 1 if the value is zero or null
###
makeproc if_null {value replace} {
  if {[string is false $value]} {
    return $replace
  }
  if { $value == 0.0 } {
    return $replace
  }
  return $value
}

###
# Print a dict to the screen
###
makeproc pdict value {
  puts ***
  foreach {var val} $value {
    puts "$var: [list $val]"
  }
  puts ***
}

##############################################################
# General use procedures
# proc:  unique
# title: Returns a unique number 
#
makeproc unique {{val 0}} {
  incr val
  makeproc unique "{val $val}" [info body unique]
  return $val
}

makeproc setIfHigher {varname value} {
  upvar 1 $varname var
  if { $var < $value } {
    set var $value
  }
}

makeproc now {} { 
    return [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S"]
}

makeproc dflt {varname i b} {
  upvar 1 $varname a
  if {![info exists a($i)] || $a($i)==""} {
    return $b
  }
  if {$a($i)<0.0} {
     return 0
  }
  return [expr {int($a($i))}]
}

makeproc setVarsFromDict {dictval varlist} {
    foreach var $varlist {
        upvar 1 $var $var
        if ![info exists $var] {
            set $var {}
        }
        if [dict exists $dictval $var] {
            set $var [dict get $dictval $var]
        }
    }
}

makeproc addAutoPath path {
    set path [file normalize $path]
    if ![file exists $path] return
    if { $path in $::auto_path } return
    foreach item $::auto_path {
        if { [file normalize $item] == $path } return
    }
    lappend ::auto_path $path
}

makeproc K {x y} { return $x }

makeproc combine args {
    foreach i $args {
        set c [llength $i]
        if { $c % 2 != 0 } {
            foreach {var val} $i {
                puts [list $var $val]
            }
            error [list Unbalanced Dict: $i $args]
        }
        lappend outstr $c
    }
    foreach {var val} [lindex $args 0] {
        dict set result $var $val
    }
    #set result [lindex $args 0]
    foreach item [lrange $args 1 end] {
        foreach {var val} $item {
            if { $val == {} } {
                if ![dict exists $result $var] {
                    dict set result $var $val
                    continue
                }
            }
            if { $val == "NULL" } {
                dict set result $var {}
                continue
            }
            dict set result $var $val
        }
    }
    return $result
}

makeproc dictGet {dict args} {
  if {[dict exists $dict {*}$args]} {
    return [dict get $dict {*}$args]
  }
  return {}
}


### Sets or unsets a flag value
makeproc flag {cmnd varname {val {}} {cd 0}} {
    upvar 1 $varname var
    if ![info exists var] {
        set var {}
    }
    if [regexp , $var] {
        set cd 1
        set var [split $var ,]
    }
    
    switch $cmnd {
        add {
            ladd var $val
        }
        remove {
            ldelete var $val
        }
        fix {
            set cd 1
        }
    }
    if $cd {
        set var [join $var ,]
    }
}

#
# A Pure Tcl implementation of the lutil command
#
makeproc lutil {command varname args} {
      
    upvar 1 $varname stack
    if ![info exists stack] {
        set stack {}
    }
    set result {}
    switch $command {
        pop {
            set result [lindex $stack 0]
            set stack [lrange $stack 1 end]
            
            set setvarn [lindex $args 0]
            if { $setvarn != {} } {
                upvar 1 $setvarn setvar
                set setvar $result
                update idletasks
                set result [expr [llength $stack] > 0]
            }
        }
        queue {
            lappend stack [lindex $args 0]
        }
        push {
            set stack [linsert [K $stack [set stack {}]] 0 [lindex $args 0]]
        }
        peek {
            set result [lindex $stack 0]
        }
    }
    return $result
}

makeproc ldelete {varname args} {
  upvar 1 $varname var
  if ![info exists var] {
      return
  }
  foreach item [lsort -unique $args] {
    while {[set i [lsearch $var $item]]>=0} {
      set var [lreplace $var $i $i]
    }
  }
}

makeproc ladd {varname args} {
  upvar 1 $varname var
  if ![info exists var] {
      set var {}
  }
  foreach item $args {
    if {$item in $var} continue
    lappend var $item
  }
  return $var
}

makeproc ladd_sorted {varname item} {
    upvar 1 $varname var
    lappend var $item
    set var [lsort -dictionary -unique $var]
    return $var
}

makeproc lset {varname fieldlist datalist} {
    upvar 1 $varname var
    set idx -1
    foreach field $fieldlist {
        set var($field) [lindex $datalist [incr idx]]
    }
}

makeproc listset {datalist varlist} {
    set idx -1
    foreach fieldVar $varlist {
        upvar 1 $fieldVar $fieldVar
        set $fieldVar [lindex $datalist [incr idx]]
    }
}

makeproc stripList arglist {
    set lastitem $arglist
    while { [llength $arglist] == 1 } {
       set lastitem $arglist
       set arglist [lindex $arglist 0]
    }
    if { [llength $arglist] == 0 } { 
       set arglist $lastitem
    }
    return $arglist
}

###
# Reverse the order of a list
###
makeproc lreverse {list} {	
    set result {}
    foreach item $list {
       set result [linsert [K $result [set result {}]] 0 $item]
    }
    return $result
}


makeproc lmerge {varname valuelist} {
    upvar 1 $varname var
    if ![info exists var] { 
        set var {}
    }
    set result {}
    foreach a $var {
        if { [lsearch $result $a] < 0 } {
            lappend result $a
        }
    }
    foreach a $valuelist {
        if { [lsearch $result $a] < 0 } {
            lappend result $a
        }
    }
    set var $result
    return $result
}


makeproc get varname {
    upvar 1 $varname var
    if [info exists var] {
        return [set var]
    }
}


makeproc dictget {dict field} {
    if [dict exists $dict $field] {
        return [dict get $dict $field]
    }
}

makeproc pop {stackvar resultvar} {
  upvar 1 $stackvar stack 
  upvar 1 $resultvar result
  if { [set len [llength $stack]] == 0 } { 
    set result {}
    return 0
  }
  set result [lindex $stack end]
  if { $len == 1 } { 
    set stack {}
  } else {
    set stack [lrange $stack 0 end-1]
  }
  return 1 
} 


makeproc peek {stackvar} { 
  upvar 1 $stackvar stack
  return [lindex $stack end]
}

makeproc push {stackvar value} {
  upvar 1 $stackvar stack
  lappend stack $value
}

makeproc queue {stackvar val} {
    upvar 1 $stackvar stack
    lappend stack $val
}

makeproc lintersect {list value} {
    foreach item $value {
        if {[lsearch $list $item] >= 0} {
            return true
        }
    }
    return false
}

makeproc cat filename {
  set fin [open $filename r]
  set dat [read $fin]
  close $fin
  return $dat
}

Added modules/tao/moac.md.















































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# Class tao::moac

All classes in the Tao framework decend from tao::moac.

# Concepts

Back to [tao](tao.md)

* [taodb](taodb.md)
* [events](events.md)
* [options](options.md)
* [parser](parser.md)
* [signals](signals.md)

# Options

* trace - When true, enable tracing information to stdout

# Properties

* options_strict - Default 0. When true, attempts to access an option through configure
or cget, which was not declared by the *option* keyword, or inherited from another class, will fail.

# Variables

* ActiveLocks - A list of active locks
* organs - A dict containing the mapping of stubs to objects

# Methods

## action::busy

Indicate to the user that the program is processing. (Empty method)

## action::idle

Commands to run when the system releases the gui. (Empty method)

## action::morph_enter

Commands to perform as an object enters this new class via the *morph* method. (Empty method)

## action::morph_leave

Commands to perform as an object exits the current class via the *morph* method. (Empty method)

## action::pipeline_busy

Commands to run when the system releases the locks. (Empty method)

** method cget *field* *?default?*

Return the value for an option, or of the option is null return *default*.
Dashes are stripped from the left of all fields.

** method code

Return \[namespace code {self}\]

## method configure *keyvaluelist*|*key* *value* ?*key* *value*...

Modify options. The command accepts either a single argument (a key value list), or
a series of keys. Dashes are stripped from the left of all fields.

Internally, *configure* normalizes the inputs, and passes them to *configurelist* and
*configurelist_triggers*.

## method configurelist *keyvaluelist*

Perform validation checks and modify the internal configuration of the
object. This method will not trigger modification events.

## method event cancel ?*pattern*?

Cancel a scheduled event. If *pattern* not specified, all scheduled tasks are
cancelled. If *pattern* given, all task handles that match *pattern* are cancelled.
Patterns are those used by *array get*.

(Note: this method is actually a forward to ::tao::event::cancel)

## method event generate *event* *args...*

Generate an event of type *event* which will be passed to the *notify* method
of all objects subscribed to *event*.

(Note: this method is actually a forward to ::tao::event::generate)

## method event nextid

Return a unique name for an event.

## method event Notification_list *pattern*

Called recursively to produce a list of who recieves notifications of pattern *pattern*.

(Note: this method is actually a forward to ::tao::event::Notification\_list)

## method event publish *object_pattern* *event_pattern*

Create a subscription for objects specified by *object_pattern* to events specified by *event_pattern*.
Patterns should be any pattern suitiable for \[string match\]

## method event schedule *handle* *interval* *script*

Arrange for *script* to be called after *interval*. Interval is any value acceptable to
\[after\]. A successive call to *handle* will cancel the prior event and schedule a new one.

## method event subscribe *object_pattern* *event_pattern*

Create a subscription for the current object to events emitted by objects
specified by *object_pattern* to events specified by *event_pattern*.
Patterns should be any pattern suitiable for \[string match\]

## method event unpublish *?event_pattern?*

Remove any subscriptions to this object's events that match *event_pattern*. If *event_pattern*
not given, all subscriptions are removed.

## method event unsubscribe *?event_pattern?*

Remove any subscriptions this object has made to events that match *event_pattern*. If *event_pattern*
not given, all subscriptions are removed.

## method forward *method* *?args...?*

Forward *method* to the command specified by *args*. Internally this is just a
wrapper around \[oo::objdefine forward\]

## method graft *stub* *object* ?*stub* *object*...?

Calles to \<*stub*\> for this object will now forward to the *object* (or ensemble)
specified. A mapping of stub->object is stored internally as a dict in the *organs* variable.

## method initialize

Called during the constructor to
set up all local variables and data
structures. It is a seperate method
to ensure inheritence chains predictably
and also to keep us from having to pass
along the constructor's arguments.

## method InitializePublic

Provide a default value for all options and
publically declared variables, and locks the
pipeline mutex to prevent signal processing
while the contructor is still running. A call to
this method is automatically injected into the constructor
by the Tao preprocessor's *constructor* keyword.

Note, by default a Tao object will ignore
signals until a later call to *my lock remove pipeline*

## method lock active

Return a list of active locks.

## method lock create *lock* ?*lock*...?

Add all arguments as locks if they are not already in the list of locks.

## method lock peek *lock* ?*lock*...?

Returns true if any of the locks specified is active.

## method lock remove *lock* ?*lock*...?

Remove the locks specified. If the last lock has been removed, a call to
*lock remove_all* is made.

## method lock remove_all

Removes all locks and makes a call to *Signal_pipeline*

## method message error *error* *errorInfo*

Process a background error

## method morph *newclass*

Have this object transition to *newclass* (if it isn't already that class).

The following snippet describes the steps:

      # CALLED AS THE PRESENT CLASS
      my action morph_leave
      oo::objdefine [self] class ::${newclass}
      # CALLED AS THE NEW CLASS
      my variable config
      set savestate $config
      my InitializePublic
      my configurelist $savestate
      my action morph_enter
    
The InitializePublic call ensures that any internal variables and options
that are declared in the new class, but not present in the current class,
are initialized.

## method mutex down *flag*

Remove mutex *flag*. Return 1 if the mutex was active, 0 otherwise.

## method mutex peek *flag*

Return 1 if mutex *flag* is active, 0 otherwise.

## method mutex up *flag*

Attempt to establish a mutex *flag*. If mutex is already active, return 1.
If a new mutex was successfully established, return 0.

## Ensemble notify *eventtype* *info*

Process an incoming notification of *eventtime* immediately.

## Ensemble Option_set *field* *newvalue*

Called by *configurelist_triggers*

Process and incoming change to an option.

## method OptionsMirrored *stub*

Return a list of options which should be mirrored to an object attached as \<*stub*\>.

## method organ *?stub?*

Return the path to the object attached as \<*stub*\>. If stub not given, return a key/value
list of all stubs and objects.

## method Prefs_Load

Load persistant preferences for this object. (Empty method)

## method Prefs_Store dictargs

Store persistant preferences for this object. (Empty method)

## method private *method* ?*args...*?

Invoke a normally private method publically.

## method signal ?*signal* *signal...*?

Generate a signal, which will ultimately schedule a call to *Signal_pipeline*. The call
of one signal can trigger or suppress other signals. See [signals](signals.md)

Added modules/tao/moac.tcl.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763

if {[info command ::tao::metaclass] eq {}} {
  oo::class create ::tao::metaclass {
    superclass ::oo::class
    
    destructor {
      ::tao::class_destroy [self]
    }
  }
}

###
# topic: bb7bd8d93b61e5163b84e16341de3a35
# title: Mother of all Classes
# description:
#    Base class used to define a global
#    template of expected behaviors
###
tao::class tao::moac {
  aliases moac
  
  variable signals_pending {}
  variable signals_processed {}
  variable organs {}
  # Sets an active lock that will be
  # erased by a lock remove added to tail
  # of all tao constructors
  variable ActiveLocks constructor
  option trace {
    widget boolean
    default 0
  }
  option_class variable {
    widget entry
    set-command {my Variable_set %field% %value%}
    get-command {my Variable_get %field%}
  }
  option_class organ {
    widget label
    set-command {my Option_graft %field% %value%}
    get-command {my organ %field%}
  }
  option_class property {
    widget label
    default-command {my property %field%}
  }

  property options_strict 0

  constructor args {
    my configurelist [::tao::args_to_options {*}$args]
    my initialize
  }

  destructor {}

  ###
  # topic: fa52b5fa66bccb878ae6c4fe88f471a3
  # description: Indicate to the user that the program is processing
  ###
  method action::busy {}

  ###
  # topic: 97d5cd58316988a2733c7ac2ad19735b
  # description: Commands to run when the system releases the gui
  ###
  method action::idle {}

  ###
  # topic: 03e3b8c1558a8153bc307fc098696d14
  ###
  method action::morph_enter {} {}

  ###
  # topic: f54fc2f9dfcba2ff0e888469b3b3ba27
  ###
  method action::morph_leave {} {}

  ###
  # topic: 7097c7ae9136bef863f89edddc384f60
  ###
  method action::pipeline_busy {} {}

  ###
  # topic: d971de215cd4ce584813fdaa09ae6819
  # description: Commands to run when the system releases the locks
  ###
  method action::pipeline_idle {} {}

  ###
  # topic: 86a1b968cea8d439df87585afdbdaadb
  ###
  method cget {field {default {}}} {
    my variable config
    set field [string trimleft $field -]
    set dat [my property option dict]
  
    if {[my property options_strict] && ![dict exists $dat $field]} {
      error "Invalid option -$field. Valid: [dict keys $dat]"
    }
    set info [dict getnull $dat $field]    
    if {$default eq "default"} {
      set getcmd [dict getnull $info default-command]
      if {$getcmd ne {}} {
        return [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]]
      } else {
        return [dict getnull $info default]
      }
    }
    if {[dict exists $dat $field]} {
      set getcmd [dict getnull $info get-command]
      if {$getcmd ne {}} {
        return [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]]
      }
      if {![dict exists $config $field]} {
        set getcmd [dict getnull $info default-command]
        if {$getcmd ne {}} {
          dict set config $field [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]]
        } else {
          dict set config $field [dict getnull $info default]
        }
      }
      if {$default eq "varname"} {
        set varname [my varname visconfig]
        set ${varname}($field) [dict get $config $field]
        return "${varname}($field)"
      }
      return [dict get $config $field]
    }
    if {[dict exists $config $field]} {
      return [dict get $config $field]
    }
    return [my property $field]
  }

  ###
  # topic: 835853285c2acbbaaa3eb1abb5d1dbe9
  ###
  method code {} {
    return [namespace code {self}]
  }

  ###
  # topic: 73e2566466b836cc4535f1a437c391b0
  ###
  method configure args {
    # Will be removed at the end of "configurelist_triggers"
    set dictargs [::tao::args_to_options {*}$args]
    if {[llength $dictargs] == 1} {
      return [my cget [lindex $dictargs 0]]
    }
    my configurelist $dictargs
    my configurelist_triggers $dictargs
  }

  ###
  # topic: dc9fba12ec23a3ad000c66aea17135a5
  ###
  method configurelist dictargs {
    my variable config
    set dat [my property option dict]
    if {[my property options_strict]} {
      foreach {field val} $dictargs {
        if {![dict exists $dat $field]} {
          error "Invalid option $field. Valid: [dict keys $dat]"
        }
      }
    }
    ###
    # Validate all inputs
    ###
    foreach {field val} $dictargs {
      set script [dict getnull $dat $field validate-command]
      if {$script ne {}} {
        {*}[string map [list %field% [list $field] %value% [list $val] %self% [namespace which my]] $script]
      }
    }
    ###
    # Apply all inputs with special rules
    ###
    foreach {field val} $dictargs {
      set script [dict getnull $dat $field set-command]
      if {$script ne {}} {
        {*}[string map [list %field% [list $field] %value% [list $val] %self% [namespace which my]] $script]
      } else {
        dict set config $field $val
      }
    }
  }

  ###
  # topic: 543c936485189593f0b9ed79b5d5f2c0
  ###
  method configurelist_triggers dictargs {
    set dat [my property option dict]
    # Add a lock to prevent signals from
    # spawning signals
    my lock create configure
    ###
    # Apply normal inputs
    ###
    foreach {field val} $dictargs {
      if [catch {
        if {[dict exists $dat $field signal]} {
          my signal {*}[dict get $dat $field signal]
        }
        my Option_set $field $val
      } err] {
        puts [list [self] bg configure error: field $field val $val error $err]
      }
    }
    my Prefs_Store $dictargs
    my lock remove configure
  }

  ###
  # topic: 7b7c4a1ea317ff9e699c875353cf00cf
  ###
  method debugOut string {}

  ###
  # topic: 20b4a97617b2b969b96997e7b241a98a
  ###
  method event {submethod args} {
    ::tao::event::$submethod [self] {*}$args
  }

  ###
  # topic: d7787c21bbba4fbc8cc347fa6f0b1bc5
  ###
  method forward {method args} {
    oo::objdefine [self] forward $method {*}$args
  }

  ###
  # topic: 87ba9c0905dbadcb68abe425339caddc
  ###
  method get {{field {}}} {
    if { $field == {} } {
      set result {}
      foreach f [::info object vars [self]] {
        my variable $f
        if {[array exists $f]} {
          dict set result @$f [::array get $f]
        } else {
          dict set result $f [set $f]
        }
      }
      return $result
    }
    my variable $field
    if {[array exists $field]} {
      return [::array get $field]
    }
    if {[info exists $field]} {
      return [set $field]
    }
    return {}
  }

  ###
  # topic: d0bf3b83fdbef6d41b5585eb034088da
  ###
  method getVarname field {
    return [my varname $field]
  }

  ###
  # topic: 9afd530cdd4fa83b793dd66f59f707af
  ###
  method graft args {
    my variable organs
    if {[llength $args] == 1} {
      error "Need two arguments"
    }
    set object {}
    foreach {stub object} $args {
      set stub [string trimleft $stub /]
      dict set organs $stub $object
      oo::objdefine [self] forward ${stub} $object
      oo::objdefine [self] forward <${stub}> $object
      oo::objdefine [self] export <${stub}>
    }
    return $object
  }

  ###
  # topic: 4369b15a85b8dc3453ee6af2902bd383
  # description:
  #    Called during the constructor to
  #    set up all local variables and data
  #    structures. It is a seperate method
  #    to ensure inheritence chains predictably
  #    and also to keep us from having to pass
  #    along the constructor's arguments
  ###
  method initialize {} {}

  ###
  # topic: 3c4893b65a1c79b2549b9ee88f23c9e3
  # description:
  #    Provide a default value for all options and
  #    publically declared variables, and locks the
  #    pipeline mutex to prevent signal processing
  #    while the contructor is still running.
  #    Note, by default an odie object will ignore
  #    signals until a later call to <i>my lock remove pipeline</i>
  ###
  method InitializePublic {} {
    my variable config
    if {![info exists config]} {
      set config {}
    }
    set dat [my property option dict]
    foreach {var info} $dat {
      if {[dict exists $info set-command]} {
        if {[catch {my cget $var} value]} {
          dict set config $var [my cget $var default]
        } else {
          if { $value eq {} } {
            dict set config $var [my cget $var default]
          }
        }
      }
      if {![dict exists $config $var]} {
        dict set config $var [my cget $var default]
      }
    }
    foreach {var info} [my property variable dict] {
      if { $var eq "config" } continue
      my variable $var
      if {![info exists $var]} {
        if {[dict exists $info default]} {
          set $var [dict get $info default]
        } else {
          set $var {}
        }
      }
    }
    foreach {var info} [my property array dict] {
      if { $var eq "config" } continue
      my variable $var
      if {![info exists $var]} {
        if {[dict exists $info default]} {
          array set $var [dict get $info default]
        } else {
          array set $var {}
        }
      }
    }
    my configurelist [my Prefs_Load]
  }

  ###
  # topic: 6c9e9e67ccd608d1983bbebcd81f2fd3
  ###
  method lock::active {} {
    my variable ActiveLocks
    return $ActiveLocks
  }

  ###
  # topic: 86d39889df168ace883017cac2de3b61
  ###
  method lock::create args {
    my variable ActiveLocks
    set result 0
    foreach lock $args {
      if { $lock in $ActiveLocks } {
        set result 1
      } else {
        lappend ActiveLocks $lock
      }
    }
    return $result
  }

  ###
  # topic: 6d8562be9185ac4990c3128a5a6aaac8
  ###
  method lock::peek args {
    my variable ActiveLocks
    set result 0
    foreach lock $args {
      if { $lock in $ActiveLocks } {
        set result 1
      }
    }
    return $result
  }

  ###
  # topic: 8429bd3d95cbe42db11fa9d78073ed87
  ###
  method lock::remove args {
    my variable ActiveLocks
    if {![llength $ActiveLocks]} {
      return 0
    }
    set oldlist $ActiveLocks
    set ActiveLocks {}
    foreach item $oldlist {
      if {$item ni $args} { lappend ActiveLocks $item }
    }
    if {![llength $ActiveLocks]} {
      my lock remove_all
      return 1
    }
    return 0
  }

  ###
  # topic: 00210688cea68a175df35ff2c25ce5dd
  # description: Force-Removes all locks
  ###
  method lock::remove_all {} {
    my variable ActiveLocks
    set ActiveLocks {}
    my Signal_pipeline
  }

  ###
  # topic: 75af8a0e6c55a9619ee87698b08bd328
  ###
  method message::error {error errorInfo} {
    puts "Error\n$error\n***\n$::errorInfo"
    return -code 1 $error -errorinfo $errorInfo
  }

  ###
  # topic: d15a85525b1f7151cd808e592bc09fed
  ###
  method morph newclass {
    my lock create morph
    set class [string trimleft [info object class [self]]]
    set newclass [string trimleft $newclass :]
    if {[info command ::$newclass] eq {}} {
      error "Class $newclass does not exist"
    }
    if { $class ne $newclass } {
      my action morph_leave
      oo::objdefine [self] class ::${newclass}
      my variable config
      set savestate $config
      my InitializePublic
      my configurelist $savestate
      my action morph_enter
    }
    my lock remove morph
  }

  ###
  # topic: 87c7b53c998e1f15c46b6a2fd187ef81
  ###
  method mutex::down flag {
    my variable mutex
    if {![info exists mutex($flag)]} {
      set mutex($flag) 0
    }
    set value $mutex($flag)
    set mutex($flag) 0
    return $value
  }

  ###
  # topic: 958a56b4c9598f3988955d7606e8c049
  ###
  method mutex::peek flag {
    my variable mutex
    if {![info exists mutex($flag)]} {
      set mutex($flag) 0
    }
    return $mutex($flag)
  }

  ###
  # topic: 1adff94c1cc08f5286b11c97480b3546
  ###
  method mutex::up flag {
    my variable mutex
    if {![info exists mutex($flag)]} {
      set mutex($flag) 0
    }
    if {[set mutex($flag)] > 0} {
      return 1
    }
    set mutex($flag) 1
    return 0
  }

  ###
  # topic: 3277490dddb5b19f42faaaaa50026f64
  # description: Provide a quiet null handler for events
  ###
  method notify::default {sender dictargs} {}

  ###
  # topic: f1ce03ba2aab515d7d7c36ce04e49eda
  ###
  method Option_get::default {} {
    my variable $method
    if {[info exists $method]} {
      return [set $method]
    }
    return {}
  }

  ###
  # topic: 092e79383ef394de41de7a4143beef2b
  ###
  method Option_graft {organ pointer} {
    my variable config
    if { $pointer ne {} } {
      dict set config $organ $pointer
      my graft $organ $pointer
    }
  }

  ###
  # topic: 3749709452836a574ce3dd8165b1308c
  ###
  method Option_noop args {
  }

  ###
  # topic: 4fa8bc688ade4893c0083d96c9e1ddfc
  # description: Default handler for options
  ###
  method Option_set::default newvalue {
    my variable $method
    if {[info exists $method]} {
      set $method $newvalue
    }
  }

  ###
  # topic: 57e093ecd48756c19e14068cad2e6856
  ###
  method OptionsMirrored organ {
    set result {}
    foreach {opt info} [my property option dict] {
      if {$organ in [dict getnull $info mirror]} {
        lappend result -$opt [my cget $opt]
      }
    }
    return $result
  }

  ###
  # topic: f867ee5408660c0296d731cda02b2bf8
  ###
  method organ {{stub all}} {
    my variable organs
    if {![info exists organs]} {
      return {}
    }
    if { $stub eq "all" } {
      return $organs
    }
    return [dict getnull $organs $stub]
  }

  ###
  # topic: fca634e0193df7049d096dd43dd3c417
  # title: Load persistant preferences
  ###
  method Prefs_Load {} {}

  ###
  # topic: e7f90dcfee554639cbf35b695827421a
  # title: Store persistant preferences
  ###
  method Prefs_Store dictargs {}

  ###
  # topic: 03c9ac58d726fe271c331c513f05b3a9
  ###
  method private {method args} {
    return [my $method {*}$args]
  }

  ###
  # topic: 30668ecb1349a981d393d705f5ffe2e0
  ###
  method proxy who {
    return [$who code]
  }

  ###
  # topic: b57ca4f29c6f69e4167176e13ced14ec
  ###
  method put args {
    if { [llength $args] == 1 } {
      set args [lindex $args 0]
    }
    foreach {key val} [::tao::args_to_dict {*}$args] {
      string trimleft $key -
      my variable $key
      set $key $val
    }
  }

  ###
  # topic: 1fe5a989f9e4334a1052fb4ef99eb7d1
  ###
  method sensai object {
    foreach {stub obj} [$object organ all] {
      my graft $stub $obj
    }
  }

  ###
  # topic: b6214c62683a643102ade2ef21853873
  # description: Does nothing
  ###
  method signal args {
    set rawlist [::tao::args_to_dict {*}$args]
    my variable signals_pending signals_processed
        
    set sigdat [my property signal dict]
    ###
    # Process incoming signals
    ###
    set signalmap $signals_pending
    foreach rawsignal $rawlist {
      ::tao::signal_expand $rawsignal $sigdat signalmap
    }

    set newsignals {}
    foreach signal $signalmap {
      if {$signal in $signals_processed} continue
      if {$signal in $signals_pending} continue
      set action [dict get $sigdat $signal action]
      if {[string length $action]} {
        lappend newsignals $signal
        lappend signals_pending $signal
      }
      set apply_action [dict get $sigdat $signal apply_action]
      if {[string length $apply_action]} {
        eval $apply_action
      }
    }
    if {[llength [my lock active]]} {
      return
    }

    if {("idle" in $rawlist && [llength $signals_pending]) || [llength $newsignals] } {
      set event [my event schedule signal idle [namespace code {my Signal_pipeline}]]
    } else {
      set event {}
    }
    return [list $event $signals_pending]
  }

  ###
  # topic: b9adb42b9e32fca79a9af340144281b6
  ###
  method Signal_pipeline {} {
    if {[my mutex up pipeline]} {
      ###
      # Prevent the pipeline from being entered twice
      ###
      return
    }
    set errlist {}
    set trace [my cget trace]
    my action pipeline_busy
    set sigdat [my property signal dict]
    my variable signals_pending signals_processed
    set order [my property meta signal_order]
    set pass 0
    if {$trace} {
      puts [list [self] [self method] $signals_pending]
    }
    if [catch {
    while {[llength [set signals $signals_pending]]} {
      ###
      # Copy our pending signals and clear out the list
      ###
      set signals_pending {}
      # Ignore mutually exclusive tasks
      set ignored {}
      foreach signal $order {
        if { $signal in $signals && $signal ni $ignored } {
          foreach item [dict get $sigdat $signal excludes] {
            ::ladd ignored $item
          }
        }
      }      
      ###
      # Fire off signals in the order calculated
      ###
      foreach signal $order {
        if { $signal in $signals && $signal ni $ignored } {
          set action [dict get $sigdat $signal action]
        }
      }
      foreach signal $order {
        if { $signal in $signals && $signal ni $ignored } {
          lappend signals_processed $signal
          if {$trace} {
            puts [list $signal [dict get $sigdat $signal action]]
          }
          eval [dict get $sigdat $signal action]
        }
      }
    }
    } err] {
      lappend errlist $err $::errorInfo
    }
    my mutex down pipeline
    my action pipeline_idle
    foreach {err info} $errlist {
      my message error $err $info
    }
    ###
    # If this sequence triggered more sequences
    # schedule our next call
    ###
    set signals_processed {}
  }

  ###
  # topic: 135c91aa5f0344e5a37c31c003f7d7ca
  # title: Generate a path to a subordinate object
  ###
  method SubObject::default {} {
    return [namespace current]::SubObject_generic_$method
  }

  ###
  # topic: 853c3b333a67f543c032852f546556c2
  ###
  method trace {{onoff {}}} {
    my variable trace
    if { $onoff == {} } {
      return $trace
    }
    set trace $onoff
    if { $trace } {
      oo::objdefine [self] method debugOut string {puts [list [my simTime] [self] $string]}
    } else {
      oo::objdefine [self] method debugOut string {}
    }
  }

  ###
  # topic: d70aa45da749a2fe7c1fb9755678322b
  ###
  method Variable_get::default {} {
    my variable $method
    return [get $method]
  }

  ###
  # topic: 02c62587fbec93f8adccc41d201c7c26
  ###
  method Variable_set::default newvalue {
    my variable $method
    set $method $newvalue
  }
}

Added modules/tao/module.tcl.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
::namespace eval ::tao {}

###
# topic: 3d9cc4f6252df40c5fd760ea4ba86f13
# title: Manage the module stack
# description:
#    While the module stack does not impact normal operations within Tao
#    maintaining it allow Tao to populate the "package" field in the tao::db
#    [example {
#    ::tao::module push myPackage
#    ::tao::load_path $dir
#    ::tao::module pop
#    }]
# darglist: [arg operation] [opt [arg module]]
###
proc ::tao::module {cmd args} {
  ::variable moduleStack
  ::variable module
  
  switch $cmd {
    push {
      set module [lindex $args 0]
      lappend moduleStack $module
      return $module
    }
    pop {
      set priormodule      [lindex $moduleStack end]
      set moduleStack [lrange $moduleStack 0 end-1]
      set module [lindex $moduleStack end]
      return $priormodule
    }
    peek {
      set module      [lindex $moduleStack end]
      return $module
    }
    default {
      error "Invalid command \"$cmd\". Valid: peek, pop, push"
    }
  }
}

::tao::module push core

Added modules/tao/mvc.tcl.































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
###
# Base classes for Model/View/Controller architecture
###

###
# topic: 71b9a2bf1f9b9e1c8b1e06ceaa088b1d
# description:
#    This class implements a common data store used by
#    a model view controller
###
tao::class tao.mvcstore {

}

###
# topic: f9279c5be057cc75b1f1fd3bd4ee3052
###
tao::class tao.model {

}

###
# topic: 2927c0b0fc54227b3538f26e3bd0323b
###
tao::class tao.view {

}

###
# topic: 2d337edf2d1b9042d4ee2510fcc4c99d
###
tao::class tao.controller {
  
  variable mode_stack {}
  variable modes {}
  variable clearing 0

  property default_context {
    class action
    button {}
    main-script {my actionstack clear}
    exit-script {}
    push-script {}
    appswitch-script {}
    popups 1
    cursor arrow
    force_2d 1
    usermode 0
    icon {}
    auto-pop 0
    edit-ok  0
    interactive 0
    modal 0
  }

  signal busy {
    apply_action {my action busy}
    triggers {idle}
  }
  signal idle {
    apply_action {my action idle}
    follows  *
    triggers {}
  }

  ###
  # topic: b749283c69423a3823ff4a9c5ea54a0a
  # description:
  #    Code to run when the application is about to enter a
  #    busy phase
  ###
  method action::busy {} {}

  ###
  # topic: e7b6d7ade002fab7c871236e94d09ff5
  # description: Commands to run when the system ceases to be busy
  ###
  method action::idle {} {}

  ###
  # topic: 22e8612cf1155540ae8463e250978fe6
  # description:
  #    Action to perform at the top of every "peek"
  #    onto the stack
  ###
  method action::mode_peek {
  }

  ###
  # topic: 1906474f86290ff6391a4eb07fa2f7e3
  # description:
  #    Action to perform when a mode is popped off
  #    the stack/exited
  ###
  method action::mode_pop {
  }

  ###
  # topic: 780582fa0c41dcea48ac25c476c15604
  # title: method to execute when we enter the mode from another mode
  # description:
  #    Action to perform when a mode is pushed onto
  #    the stack/entered
  ###
  method action::mode_push {
  }

  ###
  # topic: 849976e96911e4a595d479a45c4c2ec2
  ###
  method action::stack_cleared {
  }

  ###
  # topic: 877b7f2efda12d0e9643afab6090b145
  ###
  method actionstack::clear {} {
    my lock create [self method].$method
    set cleared 0
    variable mode_stack
    while {[llength $mode_stack] > 0} {
      incr cleared
      if {[catch {my actionstack pop} err options]} {
        my action mode_peek
        return -options $options $err
      }
    }
    set mode_stack {}
    my action mode_peek
    if { $cleared } {
      my signal  layer_update
    }
    my lock remove [self method].$method
  }

  ###
  # topic: 2d1fac13797eacfd48cdb8e87462565b
  ###
  method actionstack::define {name settings} {
    my variable modes organs
    if {![info exists modes]} {
      set modes {}
    }
    if {![dict exists $modes $name]} {
      set context [my property default_context]
    } else {
      set context [dict get $modes $name]
    }
    foreach {var val} $settings {
      dict set context $var $val
    }
    dict set modes $name $context
    return $name
  }

  ###
  # topic: 715f11d7322b94a080cc657d2fd02d7f
  # description:
  #    A varient of action that clears the stack and establishes
  #    new base-behaviors. Used to implement the different "modes"
  #    in the visualization (i.e. runmode, playback, etc)
  ###
  method actionstack::morph newclass {
    ###
    # Tell runmode to cease
    ###
    my variable currentclass
    my lock create [self method].$method
    my actionstack clear
    if { [get currentclass] eq $newclass } {
      return
    }
    ###
    # After we have cleared the stack, destroy layers
    # we are not using and add layers that we are
    ###
    global g simconfig
    my action mode_pop
    my morph $newclass
    my activate_layers

    set currentclass $newclass
    my action mode_push [list prev_class $currentclass class $newclass]
    ###
    # Publish that we have changed modes
    ###
    my event generate mode_change prev_class $currentclass class $newclass
    my action mode_peek
    my lock remove [self method].$method
  }

  ###
  # topic: e2a03175995d1ba6e4f9e1224cbbb6cd
  ###
  method actionstack::peek {} {
    my lock create [self method].$method
    my action mode_peek
    my variable mode_stack organs
    if {[llength $mode_stack]==0} {
      my action mode_peek      

      set context [my property default_context]
      set doPop 0
      set force_interactive 1
    } else {
      set context [lindex [get mode_stack] end]
      set doPop 0
      set force_interactive 0
    }
    set code [catch {
      dict with organs {}
      dict with context {}
      my popups_enabled ${popups}
      my cursor $cursor
      my action icon $icon
      if { $button != {} } {
        catch {$button configure -state pressed}
      }
      eval ${main-script}
      if { ${auto-pop} } {
        set doPop 1
      }
    } result returnInfo]
    if { $code ni {0 2} } {      
      set ::errorInfo [list Evaluating object [self] context $context]\n${::errorInfo}
      catch {my actionstack pop}
      return {*}${returnInfo} $result
    }
    if { $doPop } {
      my actionstack pop
    }
    my lock remove [self method].$method
    if {$force_interactive || $interactive} {
      my Signal_pipeline
    }
  }

  ###
  # topic: 312260fae2812d18bdb57fbbe24f7771
  ###
  method actionstack::pop {} {
    my lock create [self method].$method
    my variable mode_stack organs
    set context [lindex $mode_stack end]
    if { $context ne {} } {
      if {![dict get $context usermode]} {
        set mode_stack [lrange $mode_stack 0 end-1]
        dict with organs {}
        dict with context {}
        if [catch ${exit-script} result returnInfo] {
          set ::errorInfo [list Evaluating object [self] context $context]\n${::errorInfo}
          return {*}${returnInfo} $result
        }
      }
    }
    my lock remove [self method].$method
    my actionstack peek
  }

  ###
  # topic: 6e52f9b7b20156b81348133e3c860e8f
  ###
  method actionstack::push {mode {inputcontext {}}} {
    my variable mode_stack modes organs
    my action busy
    my lock create [self method].$method
    set script {}
    ###
    # Load our organs as the local context
    ###
    set context [my property default_context]
    if {[dict exists $modes $mode]} {
      foreach {var val} [dict get $modes $mode] {
        dict set context $var $val
      }
    }
    foreach {var val} $inputcontext {
      dict set context $var $val
    }
    dict set context mode $mode
    dict set modes $mode $context
    set stack_clear 0
    
    if {[dict exists $context exclusive]} {
      ###
      # If we have certain modes that are mutually exclusive on
      # the task stack, clear the stack
      ###
      set exclusive [dict get  $context exclusive]
      set top [lindex $mode_stack end]
      if {[dict exists $top mode]} {
        if {[dict get $top mode] in $exclusive} {
          set stack_clear 1
        }
      }
    }
    ####
    # Modal actions want to be the
    # top thing on the stack
    # so cancel anything else going on
    ###
    if {[dict get $context modal]} {
      set stack_clear 1
    }

    if { $stack_clear } {
      my actionstack clear
    }
    lappend mode_stack $context
    dict with organs {}
    dict with context {}
    if [catch ${push-script} result returnInfo] {
      set ::errorInfo [list Evaluating object [self] context $context]\n${::errorInfo}
      return {*}${returnInfo} $result
    }
    my lock remove [self method].$method
    my actionstack peek
  }

  ###
  # topic: 3aaf2e553ea49a156469847f2a9e60f0
  ###
  method configurelist_triggers dictargs {
    set dat [my property option dict]
    ###
    # Apply normal inputs
    ###
    my lock create configure
    foreach {field val} $dictargs {
      my Option_set $field $val
    }
    ###
    # Generate all signals
    ###
    foreach {field val} $dictargs {
      set signal [dict getnull $dat $field signal]
      if {$signal ne {}} {
        my signal  $signal
      }
    }
    my Prefs_Store $dictargs
    my lock remove configure
    foreach {field val} $dictargs {
      set signal [dict getnull $dat $field signal]
      if {$signal ne {}} {
        my event generate {*}$signal [list value $val]
      }
    }
  }
}

Added modules/tao/onion.tcl.

































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
###
# topic: 0f30d28a31ce88dfb36ca1c12b454087
# description:
#    This class is a template for objects that will be managed
#    by an onion class
###
tao::class tao::layer {
  aliases tao.layer
  option prefix {}
  option layer_name {}
  property layer_index_order 0
  
  constructor {sharedobjects args} {
    foreach {organ object} $sharedobjects {
      my graft $organ $object
    }
    my graft layer [self]
    my configurelist [::tao::args_to_options {*}$args]
  }

  ###
  # topic: ce2844831edfd3d32b7e1044690e978a
  # description: Action to perform when layer is mapped visible
  ###
  method initialize {} {
  }

  ###
  # topic: 88c79c0e9188a477f535b66b01631961
  ###
  method node_is_managed unit {
    return 0
  }

  ###
  # topic: 8cc75f590cfad54a22ff0c454c90561c
  ###
  method type_is_managed unit {
    return [expr {$unit eq [my cget prefix]}]
  }
}

###
# topic: 2dba98b257eea6b843505bd2d4887b8a
# description:
#    A form of megawidget which farms out major functions
#    to layers
###
tao::class tao::onion {
  aliases tao.onion
  variable layers {}
  
  ###
  # Organs that are grafted into our layers
  ###
  property shared_organs {
    
  }

  ###
  # topic: 351937a37f294d3ac235e45b9c2f312e
  ###
  method action::activate_layers {} {}

  ###
  # topic: 81232b0943dce1f2586e0ac6159b1e2e
  ###
  method activate_layers {{force 0}} {
    set self [self]
    my variable layers
    set result {}
    set active [my active_layers]

    ###
    # Destroy any layers we are not using
    ###
    set lbefore [get layers]
    foreach {lname obj} $lbefore {
      if {![dict exists $active $lname] || $force} {
        $obj destroy
        dict unset layers $lname
      }
    }

    ###
    # Create or Morph the objects to represent
    # the layers, and then stitch them into
    # the application, and the application to
    # the layers
    ###    
    foreach {lname info} $active {
      set class  [dict get $info class]
      set ordercode [$class property layer_index_order]
      if { $ordercode ni {0 {}} } {
        lappend order($ordercode) $lname $info
      } else {
        lappend order(99) $lname $info
      }
    }
    set shared [my Shared_Organs]
    
    foreach {ordercode} [lsort -integer [array names order]] {
      set objlist $order($ordercode)
      foreach {lname info} $objlist {
        set created 0
        set prefix [dict get $info prefix]
        set class  [dict get $info class]
        set layer_obj [my SubObject layer $lname]
        dict set layers $lname $layer_obj
        if {[info command $layer_obj] == {} } {
          $class create $layer_obj $shared prefix $prefix layer_name $lname
          set created 1
          foreach {organ object} $shared {
            $layer_obj graft $organ $object
          }
        } else {
          foreach {organ object} $shared {
            $layer_obj graft $organ $object
          }
          $layer_obj morph $class
        }
        ::ladd result $layer_obj
        $layer_obj event subscribe [self] *
        $layer_obj initialize
      }
    }
    
    my action activate_layers
    return $result
  }

  ###
  # topic: 7d8c8694fc10c9e8c5017dfaff4b1b8c
  # description: Returns a list of layers with properties needed to create them
  ###
  method active_layers {} {
    ### Example
    #set result {
    #  xtype     {prefix y class sde.layer.xtype}
    #  eqpt      {prefix e class sde.layer.eqpt}
    #  portal    {prefix p class sde.layer.portal}
    #}
    # return $result
    return {}
  }

  ###
  # topic: d800511c8a288ee9b935135e56c91a65
  ###
  method layer {item args} {

    set scan [scan $item "%1s%d" class objid]
    switch $scan {
      2 {
        # Search by class/objid
        if { $class eq "y"} {
          foreach {layer obj} [my layers] {
            if { [$obj type_is_managed $item] } {
              if {[llength $args]} {
                return [$obj {*}$args]
              }
              return $obj
            }
          }
        } else {
          # Search my node if we have a prefix/number
          foreach {layer obj} [my layers] {
            if { [$obj node_is_managed $item] } {
              if {[llength $args]} {
                return [$obj {*}$args]
              }
              return $obj
            }
          }
        }
      }
      default {
        # Search my name/prefix
        foreach {layer obj} [my layers] {
          if { [string match $item $layer] } {
            if {[llength $args]} {
              return [$obj {*}$args]
            }
            return $obj
          }
          set data [my active_layers]
          if { [string match $item [dict get $data $layer prefix]] } {
            if {[llength $args]} {
              return [$obj {*}$args]
            }
            return $obj
          }
        }
        # Search by string
        ###
        # Search by type
        ###
        foreach {layer obj} [my layers] {
          if { [$obj type_is_managed $item] } {
            if {[llength $args]} {
              return [$obj {*}$args]
            }
            return $obj
          }
        }
        ###
        # Search fall back to search by node
        ###
        foreach {layer obj} [my layers] {
          if { [$obj node_is_managed $item] } {
            if {[llength $args]} {
              return [$obj {*}$args]
            }
            return $obj
          }
        }
      }
    }
    return ::noop
  }

  ###
  # topic: 75d06860b688273777a17cafb45710de
  # description: Return a list of layers for this application
  ###
  method layers {} {
    set result {}
    my variable layers
    if {![info exists layers]} {
      my activate_layers
    }
    return $layers
  }

  ###
  # topic: 96201b2abf6901f5750499e903be1351
  ###
  method Shared_Organs {} {
    dict set shared master [self]
    foreach organ [my property shared_organs] {
      set obj [my organ $organ]
      if { $obj ne {} } {
        dict set shared $organ $obj
      }
    }
    return $shared
  }

  ###
  # topic: b1fe13c9c2f33fb26b71b03c7cb1d0a5
  ###
  method SubObject::layer name {
    return [namespace current]::SubObject_Layer_$name
  }
}

Added modules/tao/onions.md.





























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
Onions have layers. Like ogres. Or parfaits.

# Class tao::layer

## Options

* prefix - A letter code for this layer
* layer\_name - A plaintext name for this layer.
* layer\_index\_order - Integer which expresses what order this layer should be index. (0 first -> infinity)

## Methods

### method node\_is\_managed *unit*

Returns true if an object or record described by *unit* is managed by this object.

### method type\_is\_managed *unit*

Returns true if an type, class or family of records described by *unit* is managed by this object.

# Class tao::onion

## Variables

* layers - A dict containing a mapping of layer names and the objects which implement them.

## Properties

* shared_organs - A list of stubs which are also connected to any node or layer spawned by this object.

## Methods

### method action activate_layers

Action to perform after all of the layer objects have been connected.

### method activate_layers ?1|0?

Using the output of *active_layers*, build a nest of layers. If a *1* is
given as the first argument, all existing layers are unmapped and destroyed
before mapping new layers. Otherwise layers that were previously mapped
and not present in the current incarnation of the object are destroyed. Layers
which exist in the current incarnation, but which arent't mapped are created.
Layers that are mapped, and present in the *active_layers*, but which
have a different class implementation morph into the new class.

### method active_layers

Return a dict describing the layers that should be mapped to this object.

Example:

    method active_layers {} {
      set result {
        xtype     {prefix y class sde.layer.xtype}
        eqpt      {prefix e class sde.layer.eqpt}
        portal    {prefix p class sde.layer.portal}
      }
      return $result
    }
    
### method layer *layerid* ?*method*? ?*args...*?

With only the *layerid* argument, return the object which implements
the layer described by *layerid*. If the layer does not exist, ::noop (a command which takes any argument
and does nothing) is returned.

If more arguments are specified, the command will exercise the *method* of the
layer object using any additional *args*.

Example:

    set obj [::db layer users]
    set username [$obj record_exists $userid]
    
    OR
    
    set exists [::db layer users record_exists $userid]

### method layers

Return a dict describing the layers currently mapped to this object.

### method Shared_Organs

Return a list of organs for this object which should also be grafted to
any layers or other nodes spawned by it. The default implementation is to
return the contents of the value of *property shared_organs*

### Method SubObject layer *name*

Return the fully qualified name of the object which will implement this layer.

The default implementation return \[namespace current\]::SubObject\_Layer\_\$name

Added modules/tao/ootools.tcl.





































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
::namespace eval ::tao {}

::namespace eval ::tao::event {}

::namespace eval ::tao::info {}

::namespace eval ::tao::parser {}

::namespace eval ::tao::signal {}

###
# topic: 643efabec4303b20b66b760a1ad279bf
###
proc ::tao::args_to_dict args {
  if {[llength $args]==1} {
    return [lindex $args 0]
  }
  return $args
}

###
# topic: b40970b0d9a2525990b9105ec8c96d3d
###
proc ::tao::args_to_options args {
  set result {}
  foreach {var val} [args_to_dict {*}$args] {
    lappend result [string trimleft $var -] $val
  }
  return $result
}

###
# topic: 396899726d57640d3e90a2caa180d855
# title: Return the canonical name of a class
###
proc ::tao::canonical name {
  set class ::[string trimleft $name :]
  ::tao::db eval {select cname from class_alias where alias=:class} {
    set class $cname
  }
  return $class
}

###
# topic: da87af1492df6d913beb343d9b534d1c
# title: Create or modify a tao class
# description:
#    This command is an enhancement to [emph {::oo::class create}] and [emph {oo::define}].
#    In addition to the normal behavior expected from these operations, [emph tao::class]
#    tracks the class in the [emph tao::db] as well as rebuild the dynamic methods
###
proc ::tao::class {name body} {
  set class [canonical $name]
  if { [::info command $class] == {} } {
    ::tao::metaclass create $class
  }
  ::tao::parser::push $class
  namespace eval ::tao::parser $body
  ::tao::parser::pop
  ::tao::dynamic_methods $class
  foreach {rname} [::tao::db eval {select name from class where regenerate!=0}] {
    ::tao::dynamic_methods $rname
  }
  set ::tao::coreclasses [::tao::db eval {select class from class_property where type='classinfo' and property='type' and dict='core'}]
}

###
# topic: 87e896b8994dba3927f227685169a939
###
proc ::tao::class_ancestors {class {stackvar {}}} {
  if { $stackvar ne {} } {
    upvar 1 $stackvar stack
  } else {
    set stack {}
  }
  if { $class in $stack } {
    return {}
  }
  lappend stack $class
  if {![catch {::info class superclasses $class} ancestors]} {
    foreach ancestor $ancestors {
      class_ancestors $ancestor stack
    }
  }
  if {![catch {::info class superclasses $class} ancestors]} {
    foreach ancestor $ancestors {
      class_ancestors $ancestor stack
    }
  }
  return $stack
}

###
# topic: 19f6ce3edca7d84e2f7d82e8a7e9035f
# description: Return a list of tao classes
###
proc ::tao::class_choices {} {
  return [lsort -dictionary $::tao::info:::class]
}

###
# topic: 8a0deafc19c1f3605a7ca961ec2ab01f
###
proc ::tao::class_descendents {class {stackvar {}}} {
  if { $stackvar ne {} } {
    upvar 1 $stackvar stack
  } else {
    set stack {}
  }
  if { $class in $stack } {
    return {}
  }
  lappend stack $class
  foreach {child} [::tao::db eval {select class from class_ancestor where ancestor=:class}] {
    class_descendents $child stack
  }
  return $stack
}

###
# topic: 8c73a1ebe15b4935a4ff657399742257
###
proc ::tao::class_destroy class {
  if {[dict exists $::tao::info::class $class]} {
    dict unset ::tao::info::class $class
  }
  ::tao::db eval {
delete from class_property where class=:class;
delete from class_ensemble where class=:class;
delete from class_typemethod where class=:class;
delete from class_alias where cname=:class;
delete from class_ancestor where class=:class or ancestor=:class;
  }
}

###
# topic: 4969d897a83d91a230a17f166dbcaede
###
proc ::tao::dynamic_arguments {arglist args} {
  set idx 0
  set len [llength $args]
  if {$len > [llength $arglist]} {
    ###
    # Catch if the user supplies too many arguments
    ###
    set dargs 0
    if {[lindex $arglist end] ni {args dictargs}} {
      set string [dynamic_wrongargs_message $arglist]
      error $string
    }
  }
  foreach argdef $arglist {
    if {$argdef eq "args"} {
      ###
      # Perform args processing in the style of tcl
      ###
      uplevel 1 [list set args [lrange $args $idx end]]
      break
    }
    if {$argdef eq "dictargs"} {
      ###
      # Perform args processing in the style of tcl
      ###
      uplevel 1 [list set args [lrange $args $idx end]]
      ###
      # Perform args processing in the style of tao
      ###
      set dictargs [::tao::args_to_options {*}[lrange $args $idx end]]
      uplevel 1 [list set dictargs $dictargs]
      break
    }
    if {$idx > $len} {
      ###
      # Catch if the user supplies too few arguments
      ###
      if {[llength $argdef]==1} {
        set string [dynamic_wrongargs_message $arglist]
        error $string
      } else {
        uplevel 1 [list set [lindex $argdef 0] [lindex $argdef 1]]
      }
    } else {
      uplevel 1 [list set [lindex $argdef 0] [lindex $args $idx]]
    }
    incr idx
  }
}

###
# topic: a92cd258900010f656f4c6e7dbffae57
###
proc ::tao::dynamic_methods class {
  set ancestors [::tao::db eval {select ancestor from class_ancestor where class=:class order by CAST(seq as INTEGER);}]
  set order 0
  set script {}
  
  ::tao::dynamic_methods_ensembles $class $ancestors
  ::tao::dynamic_methods_class    $class $ancestors
  ::tao::dynamic_methods_property $class $ancestors
  ::tao::db eval {update class set regenerate=0 where name=:class;}
}

###
# topic: b88add196bb63abccc44639db5e5eae1
###
proc ::tao::dynamic_methods_class {thisclass ancestors} {
  set cmethods {}
  foreach anc $ancestors {
    ::tao::db eval {select method,arglist,body from class_typemethod where class=:anc} {
      if { $method in $cmethods } continue
      lappend cmethods $method
      ::oo::objdefine $thisclass method $method $arglist $body
    }
  }
}

###
# topic: fb8d74e9c08db81ee6f1275dad4d7d6f
###
proc ::tao::dynamic_methods_ensembles {thisclass ancestors} {

  set ensembledict {}
  #set trace [string match $thisclass "::taotk::sqlconsole"]
  set trace 0
  if {$trace} { puts "dynamic_methods_ensembles $thisclass"}
  foreach ancestor $ancestors {
    if {$trace} { puts $ancestor }
    ::tao::db eval {select * from class_ensemble where class=:ancestor} {
      if {[dict exists $ensembledict $ensemble $method]} continue
      if { $trace } { puts "$ensemble :: $method from $ancestor"}
      dict set ensembledict $ensemble $method [list $arglist $body]
    }
  }

  foreach {ensemble einfo} $ensembledict {
    set eswitch {}
    set default standard
    if {[dict exists $einfo default]} {
      set emethodinfo [dict get $einfo default]
      set arglist     [lindex $emethodinfo 0]
      set realbody    [lindex $emethodinfo 1]
      set body "\n      ::tao::dynamic_arguments [list $arglist] {*}\$args"
      append body "\n      " [string trim $realbody] "      \n"
      set default $body
      dict unset einfo default
    }
    set eswitch \n
    append eswitch "\n    [list <list> [list return [lsort -dictionary [dict keys $einfo]]]]" \n
    foreach {submethod} [lsort -dictionary [dict keys $einfo]] {
      set esubmethodinfo [dict get $einfo $submethod]
      set arglist     [lindex $esubmethodinfo 0]
      set realbody    [lindex $esubmethodinfo 1]
      if {[string length [string trim $realbody]] eq {}} {
        append eswitch "    [list $submethod {}]" \n
      } else {
        set body "\n      ::tao::dynamic_arguments [list $arglist] {*}\$args"
        append body "\n      " [string trim $realbody] "      \n"
        append eswitch "    [list $submethod $body]" \n
      }
    }
    if {$default=="standard"} {
      set default "error \"unknown method $ensemble \$method. Valid: [lsort -dictionary [dict keys $eswitch]]\""
    }
    append eswitch [list default $default] \n
    set body {}
    append body \n "set code \[catch {switch -- \$method [list $eswitch]} result opts\]"

    #if { $ensemble == "action" } {
    #  append body \n {  if {$code == 0} { my event generate event $method {*}$dictargs}}
    #}
    append body \n {return -options $opts $result}
    oo::define $thisclass method $ensemble {{method default} args} $body
    # Define a property for this ensemble for introspection
    ::tao::parser::property ensemble_methods $ensemble [lsort -dictionary [dict keys $einfo]]
  }
  if {$trace} { puts "/dynamic_methods_ensembles $thisclass"}

}

###
# topic: 6b7879602c202398bd25f733c0933cf9
###
proc ::tao::dynamic_methods_property {thisclass ancestors} {
  ###
  # Apply properties
  ###  
  set info {}
  dict set info option {}
  set proplist {}
  foreach ancestor $ancestors {
    ::tao::db eval {select property,type,dict from class_property where class=:ancestor} {
      if {[dict exists $info $type $property]} continue
      dict set info $type $property $dict
      if { $type in {eval const subst variable}} {
        # For these values, we want to exclude equivilent calls
        if {[dict exists $info eval $property]} continue
        if {[dict exists $info const $property]} continue
        if {[dict exists $info subst $property]} continue
        lappend proplist $property
        set mdef [split $property _]
        if {[llength $mdef] > 1} {
          set ptype [lindex $mdef 0]
          lappend proptypes($ptype) $property
        }
      }     
    }
  }
  
  set publicvars {}
  ###
  # Build options
  ###
  set option_classes [dict getnull $info option_class]
  # Build option handlers
  foreach {property pdict} [dict getnull $info option] {
    set contents {
      default {}
    }
    #append body \n " [list $property "return \[my cget [list $property]\]"]"
    set optionclass [dict getnull $pdict class]
    if {[dict exists $option_classes $optionclass]} {
      foreach {f v} [dict get $option_classes $optionclass] {
        dict set contents [string trimleft $f -] $v
      }
    }
    if {[dict exists $info option $optionclass]} {
      foreach {f v} [dict get $info option $optionclass] {
        dict set contents [string trimleft $f -] $v
      }
    }
    foreach {f v} $pdict {
      dict set contents [string trimleft $f -] $v
    }
    dict set info option $property $contents
  }
  
  dict set info meta class $thisclass
  dict set info meta ancestors $ancestors
  dict set info meta signal_order [::tao::signal_order [dict getnull $info signal]]
  dict set info meta types [lsort -dictionary -unique [array names proptypes]]
  dict set info meta local [get proplist]
  ###
  # Build the body of the property method
  ###
  set commonbody "switch \$field \{"
  append commonbody \n "  [list class [list return $thisclass]]"
  append commonbody \n "  [list ancestors [list return $ancestors]]"
  
  foreach {type typedict} $info {
    set typebody "    switch \[lindex \$args 0\] \{"
    append typebody \n "    [list list [list return [lsort -unique -dictionary [dict keys $typedict]]]]"
    append typebody \n "    [list dict [list return $typedict]]"
    foreach {subprop value} $typedict {
      switch $type {
        variable {
          append typebody \n "    [list $subprop [list return $value]]"          
        }
        default {
          append typebody \n "    [list $subprop [list return $value]]"          
        }
      }
    }
    append typebody "\n    \}" \n
    append commonbody \n "  [list $type $typebody]"
  }
  # Build const property handlers
  foreach {property pdict} [dict getnull $info const] {
    append commonbody \n " [list $property [list return $pdict]]"   
  }
  set body {
my variable config
if {[llength $args]==0} {
  if {[dict exists $config $field]} {
    return [dict get $config $field]
  }
}
  }
  append body $commonbody
  append classbody $commonbody

  # Build eval property handlers
  foreach {property pdict} [dict getnull $info eval] {
    if {$property in $proplist} continue
    append body \n " [list $property $pdict]"
  }

  # Build subst property handlers
  foreach {property pdict} [dict getnull $info subst] {
    if {$property in $proplist} continue
    append body \n " [list $property [list return [subst $pdict]]]"
  }
  
  # Build option handlers
  foreach {property pdict} [dict getnull $info option] {
    dict set publicvars $property $pdict
    append body \n " [list $property "return \[my cget [list $property]\]"]"
  }  
  
  # Build public variable handlers
  foreach {property pdict} [dict getnull $info variable] {
    dict set publicvars $property $pdict
    append body \n " [list $property "my variable $property \; return \$property\]"]"
  }

  # End of switch
  append body \n "\}"
  append classbody \n "\}"

  append body \n {return {}}
  
  oo::define $thisclass method property {field args} $body
  oo::objdefine $thisclass method property {field args} $classbody
}

###
# topic: 53ab28ac5c6ee601fe1fe07b073be88e
###
proc ::tao::dynamic_wrongargs_message arglist {
  set result "Wrong # args: should be:"
  set dargs 0
  foreach argdef $arglist {
    if {$argdef in {args dictargs}} {
      set dargs 1
      break
    }
    if {[llength $argdef]==1} {
      append result " $argdef"
    } else {
      append result " ?[lindex $argdef 0]?"
    }
  }
  if { $dargs } {
    append result " ?option value?..."
  }
  return $result
}

###
# topic: cd54fcd0eef299655f36c9d1e1454d53
###
proc ::tao::macro {name arglist body} {
  proc ::tao::parser::$name $arglist $body
}

###
# topic: cf50771bb0664678ec3857b360c25aab
# title: Go nowhere, do nothing
###
proc ::tao::noop args {}

###
# topic: 9e8830a711a1a888fb4c94c75bd46bad
# description: Register the existence of an object
###
proc ::tao::object_create object {
}

###
# topic: d42790a731ce9e3ff1866e71f9c42f17
# description: Unregister an object from the odie event manager
###
proc ::tao::object_destroy object {  
  variable trace
  if { $trace } {
    puts [list ::tao::object_destroy $object]
  }
  ::tao::event::generate $object destroy {}
  ###
  # Cancel any events
  ###
  ::tao::event::cancel $object *
  set names [list $object {*}[::tao::db eval {select alias from object_alias where cname=:object}]]
  foreach name $names {
    if {[dict exists $::tao::info::object $name]} {
      dict unset ::tao::info::object $name
    }

    ::tao::db eval {
delete from object where name=:name;
delete from object_bind where object=:name;
delete from object_subscribers where sender=:name;
delete from object_subscribers where receiver=:name;
delete from object_alias where cname=:name or alias=:name;
    }
  }
}

###
# topic: d9ebb42dd1ce3ecde3905b57f96109ab
###
proc ::tao::object_rename {object newname} {
  variable trace
  if { $trace } {
    puts [list ::tao::object_rename $object -> $newname]
  }
  rename $object ::[string trimleft $newname]
  ::tao::db eval {
update object_alias set cname=:newname where cname=:object;
update object set name=:newname where name=:object;
update object_bind set object=:newname where object=:object;
update object_subscribers set sender=:newname where sender=:object;
update object_subscribers set receiver=:newname where receiver=:object;

insert or replace into object_alias(cname,alias) VALUES (:newname,:object);
}
}

###
# topic: 6f46e5ab32dc211c4f838aec8d187c17
###
proc ::tao::Signal_compare {i j sigdat {trace 0}} {
  if {$i == $j} {
    return 0
  }

  set j_preceeds_i [Signal_matches $j [dict get $sigdat $i preceeds]]
  set i_preceeds_j [Signal_matches $i [dict get $sigdat $j preceeds]]
  set j_follows_i [Signal_matches $j [dict get $sigdat $i follows]]
  set i_follows_j [Signal_matches $i [dict get $sigdat $j follows]]

  if {$i_preceeds_j && !$j_preceeds_i && !$i_follows_j} {
    return -1
  }
  if {$j_preceeds_i && !$i_preceeds_j && !$j_follows_i} {
    return 1
  }
  if {$j_follows_i && !$i_follows_j} {
    return 1
  }
  if {$i_follows_j && !$j_follows_i} {
    return -1
  }
  set j_triggers_i [Signal_matches $j [dict get $sigdat $j triggers]]
  set i_triggers_j [Signal_matches $i [dict get $sigdat $i triggers]]
  return 0
}

###
# topic: 1f4128fa725b7af77fc6458fe653a651
###
proc ::tao::signal_expand {rawsignal sigdat {signalvar {}}} {
  if {$signalvar ne {}} {
    upvar 1 $signalvar result
  } else {
    set result {}
  }
  if {$rawsignal in $result} {
    return {}
  }
  if {[dict exists $sigdat $rawsignal]} {
    lappend result $rawsignal
    # Map triggers
    foreach s [dict get $sigdat $rawsignal triggers] {
      signal_expand $s $sigdat result
    }
  } else {
    # Map aliases
    foreach {s info} $sigdat {
      if {$rawsignal in [dict get $info aliases]} {
        signal_expand $s $sigdat result
      }
    }
  }
  return $result
}

###
# topic: a92545861c81e86de17b19b008507776
###
proc ::tao::Signal_matches {signal fieldinfo} {
  foreach value $fieldinfo {
    if {[string match $value $signal]} {
      return 1
    }
  }
  return 0
}

###
# topic: 9cfad45cdb257837b13844261768286e
###
proc ::tao::signal_order sigdat {
  set allsig [lsort -dictionary [dict keys $sigdat]]
  
  foreach i $allsig {
    set follows($i) {}
    set preceeds($i) {}
  }
  foreach i $allsig {
    foreach j $allsig {
      if { $i eq $j } continue
      set cmp [Signal_compare $i $j $sigdat]
      if { $cmp < 0 } {
        ::ladd follows($i) $j
      }
    }
  }
  # Resolve mutual dependencies
  foreach i $allsig {
    foreach j $follows($i) {
      foreach k $follows($j) {
        if {[Signal_compare $i $k $sigdat] < 0} {
          ::ladd follows($i) $k
        }
      }
    }
  }
  foreach i $allsig {
    foreach j $follows($i) {
      ::ladd preceeds($j) $i
    }
  }
  # Start with sorted order
  set order $allsig
  set pass 0
  set changed 1
  while {$changed} {
    set changed 0
    foreach i $allsig {
      set iidx [lsearch $order $i]
      set max $iidx
      foreach j $preceeds($i) {
        set jidx [lsearch $order $j]
        if {$jidx > $max } {
          set after $j
          set max $jidx
        }
      }
      if { $max > $iidx } {
        set changed 1
        set order [lreplace $order $iidx $iidx]
        set order [linsert $order [expr {$max + 1}] $i]
      }
    }
    if {[incr pass]>10} break
  }
  return $order
}

###
# topic: de8ee09c5a76e55364264b1e7a4b8003
###
proc ::tao::singleton {name body} {
  set class ::[string trimleft $name :].class
  #::ladd ::tao::class_list $class
  if { [::info command $class] == {} } {
    ::tao::metaclass create $class
  }
  ::tao::parser::push $class
  namespace eval ::tao::parser $body
  ::tao::parser::pop

  foreach {rname} [::tao::db eval {select name from class where regenerate!=0}] {
    ::tao::dynamic_methods $rname
  }
  $class create $name
}

Added modules/tao/options.md.

Added modules/tao/parser.md.

Added modules/tao/parser.tcl.













































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
::namespace eval ::tao {}

::namespace eval ::tao::parser {}

###
# topic: 5832132afd4f65a0dd404f834e7fce7f
# title: Specify other names that this class will answer to
###
proc ::tao::parser::aliases args {
  set class [peek]
  foreach name $args {
    set alias ::[string trimleft $name :]
    set cname [::tao::db one {select cname from class_alias where alias=:alias}]
    if { $cname ni [list {} $class] } {
      error "$alias is already an alias for $cname"
    }
    ::tao::db eval {
insert into class_alias(cname,alias) VALUES (:class,:alias);
}
  }
}

###
# topic: 7a5c7e04989704eef117ff3c9dd88823
# title: Specify the a method for the class object itself, instead of for objects of the class
###
proc ::tao::parser::class_method {name arglist body} {
  set class [peek]
  method $name $arglist $body
  ::tao::db eval {insert or replace into class_typemethod (class,method,arglist,body) VALUES (:class,:name,:arglist,:body);}
}

###
# topic: 710a93168e4ba7a971d3dbb8a3e7bcbc
###
proc ::tao::parser::component args {
  
}

###
# topic: 2cfc44a49f067124fda228458f77f177
# title: Specify the constructor for a class
###
proc ::tao::parser::constructor {arglist rawbody} {
  set body {
::tao::object_create [self]
my InitializePublic
  }
  append body $rawbody
  append body {
# Remove lock constructor
my lock remove constructor
  }
  ::oo::define [peek] constructor $arglist $body
}

###
# topic: 4cb3696bf06d1e372107795de7fe1545
# title: Specify the destructor for a class
###
proc ::tao::parser::destructor rawbody {
  set body {
::tao::object_destroy [self]
  }
  append body $rawbody
  ::oo::define [peek] destructor $body
}

###
# topic: ec9ca249b75e2667ad5bcb2f7cd8c568
# title: Define an ensemble method for this agent
###
::proc ::tao::parser::method {rawmethod args} {
  set class [peek]
  set mlist [split $rawmethod "::"]
  if {[llength $mlist]==1} {
    set method $rawmethod
    set arglist [lindex $args 0]
    set body [lindex $args 1]
    ::oo::define $class method $rawmethod {*}$args
    return
  }
  set ensemble [lindex $mlist 0]
  set method [join [lrange $mlist 2 end] "::"]
  switch [llength $args] {
    1 {
      set arglist dictargs
      set body [lindex $args 0]
      ::tao::db eval {
insert or replace into class_ensemble(class,ensemble,method,arglist,body) VALUES
(:class,:ensemble,:method,:arglist,:body)}
    }
    2 {
      set arglist [lindex $args 0]
      set body [lindex $args 1]
      ::tao::db eval {
insert or replace into class_ensemble(class,ensemble,method,arglist,body) VALUES
(:class,:ensemble,:method,:arglist,:body)}
    }
    default {
      error "Usage: method NAME ARGLIST BODY"
    }
  }
}

###
# topic: 68aa446005235a0632a10e2a441c0777
# title: Define an option for the class
###
proc ::tao::parser::option {name args} {
  set class [peek]
  set dictargs {default {}}
  foreach {var val} [::tao::args_to_dict {*}$args] {
    dict set dictargs [string trimleft $var -] $val
  }
  set name [string trimleft $name -]
  
  ###
  # Mirrored Option Handling
  ###
  set mirror [dict getnull $dictargs mirror]
  if {[llength $mirror]} {
    if {![dict exists $dictargs signal]} {
      set signal {}
      foreach i $mirror {
        set sname option_mirror_$i
        lappend signal $sname
        if {![::tao::db exists {select * from class_property where (class=:class or class in (select ancestor from class_ancestor where class=:class)) and type='signal' and property=:sname}]} {
          ::tao::parser::signal $sname [string map [list %signal% sname %organ% $i] {
            action {
              if {[my organ %organ%] ne {}} {
                my %organ% configure {*}[my OptionsMirrored %organ%]
              }
            }
          }]
        }
      }
      dict set dictargs signal $signal
    }
  }
  property option $name $dictargs
}

###
# topic: 827a3a331a2e212a6e301f59c1eead59
# title: Define a class of options
# description:
#    Option classes are a template of properties that other
#    options can inherit.
###
proc ::tao::parser::option_class {name args} {
  set class [peek]
  set dictargs {default {}}
  foreach {var val} [::tao::args_to_dict {*}$args] {
    dict set dictargs [string trimleft $var -] $val
  }
  set name [string trimleft $name -]
  property option_class $name $dictargs
}

###
# topic: baeb5170936f985e0e97be63018bc130
# title: Internal function
# description: Returns the current class being processed
###
proc ::tao::parser::peek args {
  if {[llength $args] == 2} {
    upvar 1 [lindex $args 0] class [lindex $args 1] docnode 
  }
  ::variable classStack
  set class   [lindex $classStack end]
  return ${class}
}

###
# topic: 1c598e92d29ba0311212b3fdf2334b34
# title: Internal function
# description: Removes the current class being processed from the parser stack.
###
proc ::tao::parser::pop {} {
  ::variable classStack
  set class      [lindex $classStack end]
  set classStack [lrange $classStack 0 end-1]

  tao::db eval {update class set regenerate=1 where name=:class}
  # Signal for all decendents to regenerate
  foreach d [::tao::class_descendents $class] {
    tao::db eval {update class set regenerate=1 where name=:d}
  }
  return $class
}

###
# topic: 83160a2aba9dfa455d82b46cdd2e4127
# title: Define the properties for this class as a key/value list
###
proc ::tao::parser::properties args {
  set class [peek]
  switch [llength $args] {
    1 {
      foreach {var val} [lindex $args 0] {
        ::tao::db eval {insert or replace into class_property (class,type,property,dict) VALUES (:class,'const',:var,:val);}
      }
    }
    2 {
      set type [lindex $args 0]
      foreach {var val} [lindex $args 1] {
        ::tao::db eval {insert or replace into class_property (class,type,property,dict) VALUES (:class,:type,:var,:val);}
      }
    }
    default {
      error "Usage: property ?type? infodict"
    }
  }
}

###
# topic: 709b71e10365e576653d00f185ca9efd
# title: Define a single property for this class
# description: If no type is given [emph const] is assumed.
# darglist: [opt [arg type]] [arg name] [arg value]
###
proc ::tao::parser::property args {
  set class [peek]
  switch [llength $args] {
    2 {
      set type const
      set property [lindex $args 0]
      set value [lindex $args 1]
    }
    3 {
      set type     [lindex $args 0]
      set property [lindex $args 1]
      set value    [lindex $args 2]
    }
    default {
      error "Usage: property ?type? field value"
    }
    default {
      error "Usage:
property name typet valuedict
OR property name value"
    }
  }
  if { $type eq {} } {
    set type eval
  }
  ::tao::db eval {insert or replace into class_property (class,type,property,dict) VALUES (:class,:type,:property,:value);}
}

###
# topic: bd23198ef1938428fb1532dd96de2c12
# description: Push a class onto the stack
###
proc ::tao::parser::push type {
  ::variable classStack
  lappend classStack $type
  if {![::tao::db exists {select name from class where name=:type}]} {
    ::tao::db eval {insert into class(name,package,regenerate) VALUES (:type,$::tao::module,1);}
  }
  if {![dict exists $::tao::info::class $type]} {
    dict set ::tao::info::class $type {
      aliases   {}
      ancestors {}
      regenerate 1
      property {}
      ensemble {}
      superclass {::tao::moac}
    }
  } else {
    dict set ::tao::info::class $type regenerate 1
  }
}

###
# topic: 4d12b6ca2823d960a81e6f15fd9962e6
# title: Create a signal for this class
# description:
#    Really just a wrapper for [emph {property signal}]. However,
#    this keyword ensures manditory fields are given.
###
proc ::tao::parser::signal {name infodict} {
  set result {
    apply_action {}
    action       {}
    aliases      {}
    comment      {}
    excludes     {}
    preceeds     {}
    follows      {}
    triggers     {}
  }
  dict set result name $name
  foreach {f v} $infodict {
    dict set result $f $v
  }
  property signal $name $result
}

###
# topic: 2f74ddd49a0c8e8f92e73a843acca2d7
# title: Specify ancestors for this class
# description:
#    This keyword mimics the behavior of the TclOO [emph superclass]
#    keyword. In addition to the TclOO connotations, this keyword
#    also indexes the class in the in-memory database.
#    [para]
#    For classes with no ancestors, call this keyword with no arguments.
#    Failure to do so will cause problems with the property method.
#    [para]
#    This function will also map classes classes refered to by alias.
###
proc ::tao::parser::superclass args {
  set class [peek]
  set ancestors {}
  set direct {}
  set rawvalue {}
  foreach item $args {
    set anc ::[string trimleft $item :]
    set item $anc
    if {[::tao::db exists {select cname from class_alias where alias=:anc}]} {
      set item [::tao::db one {select cname from class_alias where alias=:anc}]
    }
    lappend rawvalue $item
  }
  foreach item $rawvalue {
    if { $item in {::tao::moac ::oo::class} } continue
    if { $item in $::tao::coreclasses } continue
    lappend direct $item
    if { $item ni $ancestors && $item ne $class } {
      lappend direct $item
      lappend ancestors $item
    }
  }
  foreach item $rawvalue {
    if { $item in {::tao::moac ::oo::class} } continue
    if { $item ni $::tao::coreclasses } continue
    lappend direct $item
    if { $item ni $ancestors && $item ne $class } {
      lappend direct $item
      lappend ancestors $item
    }
  }
  if { $class ne "::tao::moac" } {
    lappend ancestors ::tao::moac
  }
  ::tao::db eval {update class set superclass=:ancestors where name=:class}
  ::oo::define $class superclass {*}$ancestors
  
  set order -1
  ::tao::db eval {delete from class_ancestor where class=:class}
  set ancestors [::tao::class_ancestors $class]
  foreach d $ancestors {
    incr order
    ::tao::db eval {insert into class_ancestor(class,seq,ancestor,direct) VALUES (:class,:order,:d,0);}
  }
  foreach d $direct {
    ::tao::db eval {update class_ancestor set direct=1 where class=:class and ancestor=:d}
  }
  property meta ancestors $ancestors
}

###
# topic: 615b7c43b863b0d8d1f9107a8d126b21
# title: Specify a variable which should be initialized in the constructor
# description:
#    This keyword can also be expressed:
#    [example {property variable NAME {default DEFAULT}}]
#    [para]
#    Variables registered in the variable property are also initialized
#    (if missing) when the object changes class via the [emph morph] method.
###
proc ::tao::parser::variable {name {default {}}} {
  property variable $name [list default $default]
}

###
# topic: c5f7c9ada6fe1605219273b957283d70
# description: Work space for the IRM class parser
###
namespace eval ::tao::parser {
  foreach keyword {
    deletemethod export filter forward  renamemethod
    self unexport unknown
  } {
    proc $keyword args "::oo::define \[peek\] $keyword {*}\$args"
  }
  namespace export *
}

Added modules/tao/pkgIndex.tcl.

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded listutil 1.7 [list source [file join $dir lutils.tcl]]
package ifneeded tao 9.4.4 [list source [file join $dir index.tcl]]

Added modules/tao/property.md.

Added modules/tao/signals.md.

Added modules/tao/tao.md.



























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
The Tao package is a framework built on top of TclOO. Classes and objects
created in Tao are 100% compadible with standard TclOO.

Tao adds a host of features that is not available in vanilla TclOO
They include the following:

* [events](events.md)
* [options](options.md)
* [moac](moac.md)
* [parser](parser.md)
* [signals](signals.md)
* [taodb](taodb.md)

# Development

Tao is maintained at <http://fossil.etoyoc.com/fossil/taolib>.
If you are viewing this file from within tclhttpd's sources, you are
viewing a snapshot that is periodically updated from the mainstream
sources.

Tao was built, designed, and maintained by Sean Woods <[email protected]>.

# Major Concepts

* All tao framework objects decend from the [Mother of all Classes](moac.md)
* Tao classes are built using the *::tao::class* keyword, instead of *::oo::class create*
* Tao classes can be modified using the *::tao::class* keyword, instead of *::oo::define*
* A method in \<brackets\> indicates that the method is actually being forwarded to another object.
* *::tao::class* is a pre-parser, which adds additional keywords and modifies the behavior of the constructor and destructor

Added modules/tao/taodb.md.

Added modules/wysiwyg/buttons/blank-trans.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/blank.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/first-trans.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/first.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/goto.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/last-trans.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/last.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/next-trans.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/next.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/prev-trans.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/prev.gif.

cannot compute difference between binary files

Added modules/wysiwyg/buttons/search.gif.

cannot compute difference between binary files

Added modules/wysiwyg/css/styles.css.































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* WYSIWYG EDITOR */

/* Toolbar */
.toolbar1   { border: 1px solid #666666; height: 26px; background-image: url(../icons/background_silver.jpg); }
.toolbar2   { border: 1px solid #666666; height: 24px; background-image: url(../icons/background_silver.jpg); border-bottom: 0px; border-top: 0px; }

/* Command Buttons */
.button     { width: 20px; height: 20px; border: 0px solid transparent; margin: 1px; padding: 0px; background: transparent; }
.buttonOver { width: 20px; height: 20px; border: 1px solid #999999; margin: 0; padding: 0px; }


/* Font Type and Size Drop Down */
.dropdown          { background-color: #FFFFFF; border: 1px solid #333333; height: 140px; overflow: auto; padding: 1px; }
button.mouseOver   { background-color: #EEEEEE; border: 1px solid #CCCCCC; padding: 3px; cursor: default; text-align: left;}
button.mouseOut    { background-color: #FFFFFF; border: 1px solid #FFFFFF; padding: 3px; cursor: default; text-align: left;}




/* CREATE TABLE POPUP */

/* Select Border Width/Type */
.on   { background-color: #EEEEEE; border: 1px solid #CCCCCC; padding: 6px; width: 140px; cursor: default; height: 5px;}
.off  { background-color: #FFFFFF; border: 1px solid #FFFFFF; padding: 6px; width: 140px; cursor: default; height: 5px;}

/* Select Shading/Border Color */
.selectColorTable  { border: 1px solid #7E7E81; background-color: #F7F7F7; padding: 1px; }
.selectColorBorder { border: 1px solid #F7F7F7; }
.selectColorOn     { border: 1px solid #999999; background-color: #CCCCCC; }
.selectColorOff    { border: 1px solid #F7F7F7; background-color: #F7F7F7; }
.selectColorBox    { border: 1px solid #FFFFFF; font-size: 1px; height: 13px; width: 13px; }

Added modules/wysiwyg/icons/backcolor.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/backcolor_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/background_silver.jpg.

cannot compute difference between binary files

Added modules/wysiwyg/icons/bold.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/bold_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/copy.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/copy_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/cut.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/cut_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/forecolor.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/forecolor_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/help.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/help_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/indent_left.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/indent_left_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/indent_right.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/indent_right_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/insert_hyperlink.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/insert_hyperlink_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/insert_picture.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/insert_picture_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/insert_table.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/insert_table_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/italics.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/italics_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/justify_center.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/justify_center_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/justify_left.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/justify_left_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/justify_right.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/justify_right_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/list_ordered.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/list_ordered_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/list_unordered.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/list_unordered_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/logo.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/paste.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/paste_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/redo.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/redo_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/select_font.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/select_font_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/select_size.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/select_size_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/seperator.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/seperator2.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/strikethrough.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/strikethrough_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/subscript.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/subscript_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/superscript.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/superscript_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/underline.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/underline_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/undo.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/undo_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/view_source.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/view_source_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/view_text.gif.

cannot compute difference between binary files

Added modules/wysiwyg/icons/view_text_on.gif.

cannot compute difference between binary files

Added modules/wysiwyg/js/ddbg3.gif.

cannot compute difference between binary files

Added modules/wysiwyg/js/example.html.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG Examples</title>
</head>
<script language="JavaScript" type="text/javascript" src="wysiwyg.js">
</script>

<body>
<form name="example" method="get">
<textarea id="textarea1" name="test1" style="height: 170px; width: 500px;">
  <table border="0" cellpadding="0" cellspacing="0" style="margin-left: 10px;">
	 <tr>
	  <td style="padding: 0 10 10 0;"><a href="http://www.openwebware.com/products/openwysiwyg/"><img src="http://www.openwebware.com/images/openwysiwyg/logo9060.gif" border="0" height="60" width="90" alt="openWYSIWYG - Cross-browser WYSIWYG editor"></a></td>
		<td style="font-family: verdana; font-size: 11px; line-height: 130%; color: #494949;" valign="top">	
	  <b><a href="http://www.openwebware.com/products/openwysiwyg/" style="font-family: arial; font-size: 12px; color: #055F92;">openWYSIWYG - Cross-browser WYSIWYG editor</a></b><br />
	  <?php
		
		echo "Hello World";
		
		?>
		</td>
	 </tr>
	</table>
</textarea>
<script language="javascript1.2">
  generate_wysiwyg('textarea1');
</script>


<br><br>
<textarea id="textarea2" name="test2" style="height: 200px; width: 500px;">
<h1>GNU Lesser General Public License</h1>

<tt>
<p>Version 2.1, February 1999</p>

<blockquote>
<p>Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.</p>

<p>[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]</p></blockquote>

<h3>Preamble</h3>

<p> The licenses for most software are designed to take away your freedom to share and change it.</p>
</tt>
</textarea>
<script language="javascript1.2">
  generate_wysiwyg('textarea2');
</script>

<br /><br />
<input type="submit" id="button" />
</form>


</body>
</html>

Added modules/wysiwyg/js/expand.gif.

cannot compute difference between binary files

Added modules/wysiwyg/js/readme.html.









































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG - Online Documentation</title>
<meta name="description" content="openWYSIWYG - An open source free cross-browser wysiwyg editor.">
<meta name="keywords" content="wysiwyg editor browser dhtml javascript component content management software system open source free cross-browser">
<script language="JavaScript" type="text/javascript" src="wysiwyg.js"></script>
<style>
a {color: #3F8BD8;}
a:hover {color: #FF9900;}
h2 {font-size:15pt; font-weight:bold;color:red; font-family: "Trebuchet MS"; text-decoration: underline;}
h3 {font-size:12pt; color: #494949; font-family: "Trebuchet MS";}
</style>
</head>
<body style="background-color: #EEEEEE;">

<center>
<table border="0" cellpadding="0" cellspacing="0" style=" border: 1px solid #CCCCCC; background-color: #FFFFFF; padding: 20px;">
 <tr>
  <td><a href="http://www.openwebware.com/"><img src="http://www.openwebware.com/images/docs/logo.gif" alt="openwebware - Free Components and Applications" hspace="10" vspace="10" border="0"></a></td>
	<td><span style="font-family: arial, verdana, helvetica; font-size: 20px; font-weight: bold; color: #494949;">openWYSIWYG 1.01 Documentation</td>
 </tr>
 <tr>
  <td colspan="2" style="font-family: verdana, helvetica; font-size: 13px; color: #494949;" >
	<center><b>Please read this document completely before using openWYSIWYG.</b></center>
		<p>Please note that this documentation is not all-inclusive, a more detailed instruction manual will be available as openWYSIWYG matures. The good news, this document will walk you through the basics of getting started.</p>
	 <p>If you have any suggestions on how to improve this document, or feel your contributions will make it more complete, please <a href="http://www.openwebware.com/about/contact/">contact us</a>. We're always looking for ways to improve, whether it's the product itself or the accompanying documentation.</p>
  
	<ol>
   <li><a href="#introduction">Introduction</a></li>
	 <ol type="i">
    <li><a href="#openWYSIWYG">What is openWYSIWYG?</a></li>
    <li><a href="#free">Is openWYSIWYG really free and open source?</a></li>
    <li><a href="#example">Do you have a working example I can see?</a></li>
    <li><a href="#info">Where can I learn more about it, download the latest version, or talk to other openWYSIWYG developers?</a></li>
   </ol>
   <li><a href="#requirements">Browser Requirements</a></li>
   <li><a href="#install">Installation</a></li>
   <ol type="i">
    <li><a href="#howtoadd">How do I add openWYSIWYG to my web page or web application?</a></li>
   </ol>
   <li><a href="#faqs">Frequently Asked Questions</a></li>
	 <ol type="i">
    <li><a href="#goals">What are the project goals for openWYSIWYG?</a></li>
    <li><a href="#help">openWYSIWYG is great, is there anyway I can help?</a></li>
    <li><a href="#feature">I'd like to add a feature, can you add it?</a></li>
		<li><a href="#browsers">Why don't you support Safari, Opera, or &lt;insert browser name&gt;?</a></li>
		<li><a href="#question">My question isn't answered here?</a></li>
   </ol>
	 <li><a href="#issues">Known Issues</a></li>
   <li><a href="#change">Change Log</a></li>
	 <li><a href="#features">Feature Recommendations for the Next Version</a>
	 <li><a href="#disclaimer">Copyright and Disclaimer</a></li>
  </ol>
	
<a name="#introduction"><h2>1. Introduction</h2></a>
<p>If you are just getting started with openWYSIWYG, then you've come to the right place. This 
document explains what openWYSIWYG is, contains information on installing and setting up 
openWYSIWYG, answers frequently asked questions, lists the program's requirements, and provides other useful information.</p>


<br /><br />
<a name="#openWYSIWYG"><h3>1.i. What is openWYSIWYG?</h3></a>
<p>openWYSIWYG is a free cross-browser WYSIWYG (what you see is what you get) editor. 
With just a few simple lines of JavaScript code you can  easily replace a &lt;textarea&gt; 
with a powerful WYSIWYG editor that lets your users do the following:</p>
<ul>
 <li>Format text to be bold, italicized, or underlined.</li> 
 <li>Change the face, size, style and colour.</li> 
 <li>Left, centre, or right-justify paragraphs.</li> 
 <li>Make bulleted or numbered lists.</li> 
 <li>Indent or un-indent paragraphs.</li> 
 <li>Insert hyperlinks, images, and tables.</li>
 <li>View the HTML source code of what you're editing.</li>
 <li>And much more...</li>
</ul>

<p>What sets openWYSIWYG apart from other WYSIWYG editors?</p>
<ul>
 <li>It loads extremely fast and is completely written in JavaScript and DHTML. No server side code (like PHP) required.</li> 
 <li>Regardless of what programming language you use, openWYSIWYG will work. (ASP, ASP. Net, PHP, Perl, Java, Python, Cold Fusion, etc).</li> 
 <li>It's open source, meaning you'll have access to the full source code to modify or customize it to your needs.</li>
 <li>With just one line of code it can easily be added to your content management system or custom web application.</li>
 <li>It's compatible with the most popular internet browsers, meaning your users will have no trouble making use of it.</li>
 <li>And best of all, it's free! It can be incorporated into any free or commercial program.</li> 
</ul>


<br /><br />
<a name="#free"><h3>1.ii. Is openWYSIWYG really free and open source?</h3></a>
<p>Yes! Unlike other WYSIWYG editors out there you don't have 
to fork out big dollars for openWYSIWYG. You can distribute it in your 
content management system or custom web application. It's absolutely free!</p> 

<p>openWYSIWYG is an open source application released under the 
<a href="http://www.opensource.org/licenses/lgpl-license.php" target="_blank">LGPL</a>, 
meaning you'll have access to the full source code to modify or customize it to your 
needs. Add new features, change the styles, or even optimize the code. It's entirely 
up to you.</p>


<br /><br />
<a name="#example"><h3>1.iii. Do you have a working example I can see?</h3></a>

<p>Absolutely, just check out a working example below:</p>

	<textarea id="textarea1" name="test1" style="height: 170px; width: 500px;">
  <table border="0" cellpadding="0" cellspacing="0" style="margin-left: 10px;">
	 <tr>
	  <td style="padding: 0 10 10 0;"><a href="http://www.openwebware.com/products/openwysiwyg/"><img src="http://www.openwebware.com/images/openwysiwyg/logo9060.gif" border="0" height="60" width="90" alt="openWYSIWYG - Cross-browser WYSIWYG editor"></a></td>
		<td style="font-family: verdana; font-size: 11px; line-height: 130%; color: #494949;" valign="top">	
	  <b><a href="http://www.openwebware.com/products/openwysiwyg/" style="font-family: arial; font-size: 12px; color: #055F92;">openWYSIWYG - Cross-browser WYSIWYG editor</a></b><br />
	  Need a powerful cross-browser WYSIWYG editing component? openWYSIWYG is the ultimate 
		&amp;lt;textarea&amp;gt; replacement for your content management system.
		</td>
	 </tr>
	 <tr>
	  <td style="padding: 0 10 10 0;"><a href="http://www.openwebware.com/products/openpopups/"><img src="http://www.openwebware.com/images/openpopups/logo9060.gif" border="0" height="60" width="90" alt="openWYSIWYG - Cross-browser WYSIWYG editor"></a></td>
		<td style="font-family: verdana; font-size: 11px; line-height: 130%; color: #494949;" valign="top">	
	  <b><a href="http://www.openwebware.com/products/openpopups/" style="font-family: arial; font-size: 12px; color: #055F92;">openPopUps - JavaScript and &amp;&lt;div&amp;&gt; powered popup window</a></b><br />
	  The perfect pop up window replacement for your advertisements and web applications. Pop 
		up blockers will fail to prevent an openPopUp window from opening. 
		</td>
	 </tr>
	</table>
	</textarea>
  <script language="javascript1.2">
    generate_wysiwyg('textarea1');
  </script>


<br /><br />
<a name="#info"><h3>1.iv. Where can I learn more about it, download the latest version, or 
talk to other openWYSIWYG developers?</h3></a>

<p>You can learn more about openWYSIWYG and download the latest version at <a href="http://www.openwebware.com/products/openwysiwyg/">www.openwebware.com</a>.
There's also an <a href="http://www.openwebware.com/forum/viewforum.php?f=1">excellent user community</a> where you can share ideas, learn various tricks, 
or even post suggestions and comments.</p>


<br /><br />
<a name="#requirements"><h2>2. Browser Requirements</h2></a>

<p>openWYSIWYG is cross-browser compatible and will work with the most popular internet 
browsers. This means your users will have no trouble making use of it. Supported browsers include: 
<b>IE</b> 5.5+ (Windows), <b>Firefox</b> 1.0+, <b>Mozilla</b> 1.3+ and <b>Netscape</b> 7+.</p>


<br /><br />
<a name="#install"><h2>3. Installation</h2></a>

<p>Once you've downloaded openWYSIWYG you'll want to unzip it (while maintaining the directory 
structure).</p>

<p>openWYSIWYG is coded completely in JavaScript, HTML, and CSS. 
It also uses images (.gif and .jpg), so if you're uploading these files to your 
web server you'll want to make sure they're readable.</p>

<p>On Unix based servers, that means every directory has chmod permissions of 755 
while the files (.html, .js, .jpg., .gif, etc) are 644. Most Unix based servers 
use these settings for folders and files by default, so  you most likely won't 
have to change a thing.</p>

<br /><br />
<a name="#howtoadd"><h3>3.i. How do I add openWYSIWYG to my web page or web application?</h3></a>

<p>You can easily add openWYSIWYG to your content management system or custom 
web application by just adding a few simple lines of JavaScript code.</p>

<p><b>1.</b> Near the beginning of the web page to which you plan to add openWYSIWYG insert 
the following line of code before the closing &lt;/head&gt; tag.</p>

<div style="margin-left: 20px;">Include the following:</div>
<div style="background-color: #FFFFEE; font-family: courier new; font-size: 12px; padding: 5px; width: 100%; border: 1px solid #444444; margin-left: 20px;">
  <span style="color: #0000FF;">&lt;script language=</span><!--
  --><span style="color: #008080;">"JavaScript"</span> 
  <span style="color: #0000FF;">type=</span><!--
  --><span style="color: #008080;">"text/javascript"</span> 
  <span style="color: #0000FF;">src=</span><!--
  --><span style="color: #008080;">"/<span style="color: #CC0000;">your_directory_path</span>/openwysiwyg/wysiwyg.js"&gt;</span><!--
  --><span style="color: #0000FF;">&lt;/script&gt;</span>
</div>

<p>Where <span style="font-family: courier new; font-size: 13px; color: #CC0000;">your_directory_path</span> is the path to your openwysiwyg directory.


<p><b>2.</b> Next, add opening and closing &lt;textarea&gt; tags where you plan to include 
your WYSIWYG editor. You'll also want to give your &lt;textarea&gt; an ID value.</p>

<div style="margin-left: 20px;">Example &lt;textarea&gt; code:</div>
<div style="background-color: #FFFFEE; font-family: courier new; font-size: 12px; padding: 5px; width: 300px; border: 1px solid #444444; margin-left: 20px;">
<span style="color: #0000FF;">&lt;textarea id="<span style="color: #CC0000;">your_textarea</span>"&gt;&lt;/textarea&gt;</span>
</div>

<p>Your &lt;textarea&gt;'s ID should be something unique.</p>


<p><b>3.</b> Finally, add the following JavaScript code just below your closing &lt;/textarea&gt; tag.</p>


<div style="margin-left: 20px;">Example JavaScript code:</div>
<div style="background-color: #FFFFEE; font-family: courier new; font-size: 12px; padding: 5px; width: 300px; border: 1px solid #444444; margin-left: 20px;">
	<span style="color: #0000FF;">&lt;script language=</span><span style="color: #008080;">"JavaScript"</span>&gt;<br>
  &nbsp;&nbsp;<span style="color: #000080;">generate_wysiwyg</span>('<span style="color: #CC0000;">your_textarea</span>');<br>
  <span style="color: #0000FF;">&lt;/script&gt;</span>
</div>

<p>The value you pass to the generate_wysiwyg function (<span style="font-family: courier new; font-size: 13px; color: #CC0000;">your_textarea</span>) 
must be the exact same as your &lt;textarea&gt;'s ID.</p>

<p>And that's about it, you've just added openWYSIWYG to your content management 
system or custom web application with just a few small lines of code.</p>

<br /><br />
<a name="#faqs"><h2>4. Frequently Asked Questions</h2></a>


<a name="#goals"><h3>4.i.What are the project goals for openWYSIWYG?</h3></a>

<p>The project goals for openWYSIWYG are designed to make it easy for developers who 
contribute to the editor to know where it's going. This also lets people know 
what's important to us and what we believe makes a good editor.</p>

<p><b>100% JavaScript</b>
<div style="margin-left: 50px;">openWYSIWYG must always be coded entirely in JavaScript and DHTML.
This is so developers can use it in their applications regardless of the programming language 
they choose to build their web applications, be it Perl, PHP, ASP, Cold Fusion, or any other 
language.
<br /><br />
That being said, add-ons or plug-ins (e.g. image/media uploading utility) can be coded in 
a server side language (Perl, PHP, ASP, etc).</div></p>


<p><b>Fast Loading and Unbloated</b>
<div style="margin-left: 50px;">openWYSIWYG must always be fast loading. Regardless of what feature 
is added, it cannot slow down the loading of the editor itself. There are far too many free WYSIWYG 
editors out there that take an unbelievable amount of time to load. End users (the very people who will 
use your web applications) don't like this!<br /><br />
Also, the editor must not become bloated, filled with features that only a small minority of users 
will make use of. If there's ever a doubt to which features you think should be added please
refer to the list of <a href="#features">feature recommendations for the next version</a> 
found in this document.</div></p>


<p><b>Easy to Use</b>
<div style="margin-left: 50px;">openWYSIWYG must be easy to use for developers to integrate into 
their applications, easy for programmers to add new features, and easy for end users 
to use.</div></p>

<br /><br />
<a name="#help"><h3>4.ii.openWYSIWYG is great, is there any way I can help?</h3></a>

<p>Absolutely. Whether you're just starting with openWYSIWYG, are a developer or programmer, 
or have your own website, almost anyone can help.</p>

<p><b>If You're a Programmer or Developer</b>
<div style="margin-left: 50px;">Any code improvements you want to share are most certainly 
welcome. After all, openWYSIWYG is open source, so we're always open to suggestions and 
improvements.<br /><br /> 

If you notice anything that you can do better, or have an improvement you would like to make 
you can always share it with others in the <a href="http://www.openwebware.com/forum/viewforum.php?f=1">
openWYSIWYG forum</a>, or <a href="mailto:[email protected]">send us an email</a> with 
your code improvements, new features, or suggestions.<br /><br />

If you're not sure where to get started you can always check out the <a href="#features">feature 
recommendations</a> slated for the next version.<br /><br />

All contributions will be credited to the creator in the openWYSIWYG source code and on the 
openwebware.com website.</div></p>


<p><b>If You're a Webmaster or Site Owner</b>
<div style="margin-left: 50px;">As a webmaster, the best thing you can do to help is also the easiest thing to do; 
give us a link on your website. The more people who can find out about openWYSIWYG the 
better it will be.<br /><br />

Just copy the HTML from one of the code samples below and place it somewhere on your 
website.<br /><br />

<i class="siteTitles">Image Link:</i><br />
<a href="http://www.openwebware.com/products/openwysiwyg/"><img src="http://www.openwebware.com/images/openwysiwyg/32_x_88.gif" height="32" width="88" border="0" alt="openWYSIWYG - Free Open Source WYSIWYG Editor" /></a>
<br /><br />
<textarea rows="4" cols="75">&lt;a href="http://www.openwebware.com/products/openwysiwyg/"&gt;&lt;img src="http://www.openwebware.com/images/openwysiwyg/32_x_88.gif" height="32" width="88" border="0" alt="openWYSIWYG - Free Open Source WYSIWYG Editor" /&gt;&lt;/a&gt;</textarea>
<br /><br />
	
<i class="siteTitles">Text Link:</i><br />
<a href="http://www.openwebware.com/products/openwysiwyg/" style="font-family: arial; font-size: 12px;">openWYSIWYG - Free Open Source WYSIWYG Editor</a>
<br /><br />
<textarea rows="3" cols="75">&lt;a href="http://www.openwebware.com/products/openwysiwyg/" style="font-family: arial; font-size: 12px;"&gt;openWYSIWYG - Free Open Source WYSIWYG Editor&lt;/a&gt;</textarea>
</div></p>


<p><b>If You're a New User</b>
<div style="margin-left: 50px;"><a href="http://www.openwebware.com/forum/viewforum.php?f=1">
Participate in our forum</a> and post a message or two to help other openWYSIWYG users 
(or learn something new yourself).</div></p>


<br /><br />
<a name="#feature"><h3>4.iii.I'd like to add a feature, can you add it?</h3></a>
<p>Probably not. If it's not listed in the <a href="#features">feature recommendations</a> for 
the next version we just won't have the time to work on it. That doesn't mean you can't work on it 
or <a href="http://www.openwebware.com/forum/viewforum.php?f=1">post a message</a>
in the forum asking if someone else could help you with it.</p>


<br /><br />
<a name="#browsers"><h3>4.iv.Why don't you support Safari, Opera, or &lt;insert browser name&gt;?</h3></a>
<p>It's not that we don't want to, we just don't yet. Our first goal was to provide support for 
the most popular browsers, those being Internet Explorer and Mozilla (Mozilla and Firefox). 
Safari is definitely something we would like to support since it's gaining in popularity 
within the Mac community. While not fully tested, if your users are working with Macs 
they should be able to access openWYSIWYG using a Mozilla based browser (e.g. Mozilla or Firefox).</p>

<p>As for Opera, to be realistic, we currently don't have any plans to support it. Opera 
just hasn't reached a level of popularity to justify the time required to develop support for it.</p>


<br /><br />
<a name="#question"><h3>4.v.My question isn't answered here?</h3></a>
<p>We're always happy to answer questions. <a href="http://www.openwebware.com/forum/viewforum.php?f=1">
Post your question in the forum</a> if it wasn't answered here.</p>


<br /><br />
<a name="#issues"><h2>5. Known Issues</h2></a>
<p><b>HTML header tags (e.g.: &lt;body&gt;, &lt;head&gt;, etc) aren't preserved</b>
<div style="margin-left: 50px;">This probably has to do with the browser trying to be smart about the way it generates its HTML. The editor already has HTML header information of its own so inserting a second one confuses the browser and the content gets stripped. While this is a very minor issue, we do hope to research this further and find a solution.</div></p>

<br /><br />
<a name="#change"><h2>6. Change Log</h2></a>

<p><b>Version 1.01 (Released: April 9, 2006)</b><br />
Addresses the following:
<ul>
<li>A bizarre problem on certain version combinations of IE and Windows where; the textarea wasn't hidden, the font size and font type drop downs did not display at all, and the "Text" mode button wasn't hidden when first loading.</li>
<li>Font Size and Font Select buttons weren't "unselectable" in IE 6+ (meaning users could drag and drop them into the editor). This is now fixed.</li>
<li>The WYSIWYG should now always update the textarea on the user's last command.</li>
<li>All document.all references have been changed to document.getElementById.</li>
<li>Minor UI changes to the Insert Table popup.</li>
<li>Minor design changes to the toolbar (CSS, HTML changes) so it displays better in various HTML doctypes.</li>
<li>Undo/Redo now works in Internet Explorer.</li> 
</ul>
</p>

<p><b>Version 1.00 (Released: March 1, 2006)</b><br />
Initial Release</p>


<br /><br />
<a name="#features"><h2>7. Feature Recommendations for the Next Version</h2></a>
<p>Included below is a list of features and fixes recommended for the next update 
to openWYSIWYG. We could really use your help, so if you would like to lend a hand
<a href="maitlo:[email protected]">let us know</a>, any additions and 
enhancements will be credited in the source code and on the openwebware.com website.</p>

<ul>
 <li><b>Features and Improvements</b></li>
 <ul>
  <li>XHTML compliant code output</li>
  <li>Table Editing Features (modify table, insert table cell, insert row, merge table cell, etc)</li>
 </ul>
</ul>

<ul>
 <li><b>Add-ons and Plug-ins</b></li>
 <ul>
  <li>Image/Media uploader for PHP</li>
 </ul>
</ul>
 
<br /><br />
<a name="#disclaimer"><h2>8. Copyright and Disclaimer</h2></a>
This application is open source software released under the 
<a href="http://www.opensource.org/licenses/lgpl-license.php" target="_blank">LGPL</a>. 
Please see source code for more details. This package and its contents are Copyright 
� 2006 openWebWare.com, All Rights Reserved.


	</td>
 </tr>
</table>
</center>

</body>
</html>

Added modules/wysiwyg/js/rightarrow.gif.

cannot compute difference between binary files

Added modules/wysiwyg/js/wysiwyg.js.





















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
//
// openWYSIWYG v1.01 Copyright (c) 2006 openWebWare.com
// This copyright notice MUST stay intact for use.
//
// An open source WYSIWYG editor for use in web based applications.
// For full source code and docs, visit http://www.openwebware.com/
//
// This library 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 2.1 of the License, or 
// (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software Foundation, Inc., 59 
// Temple Place, Suite 330, Boston, MA 02111-1307 USA 


/* ---------------------------------------------------------------------- *\
  Global Variables: Set global variables such as images directory, 
	                  WYSIWYG Height, Width, and CSS Directory.
\* ---------------------------------------------------------------------- */

// Images Directory
imagesDir = "/wysiwyg/icons/";

// CSS Directory
cssDir = "/wysiwyg/css/";

// Popups Directory
popupsDir = "/wysiwyg/popups/";

// WYSIWYG Width and Height
wysiwygWidth = 500;
wysiwygHeight = 150;

// Include Style Sheet
document.write('<link rel="stylesheet" type="text/css" href="' +cssDir+ 'styles.css">\n');


/* ---------------------------------------------------------------------- *\
  Toolbar Settings: Set the features and buttons available in the WYSIWYG
	                  Toolbar.
\* ---------------------------------------------------------------------- */


// List of available font types
  var Fonts = new Array();
  Fonts[0] = "Arial";
  Fonts[1] = "Sans Serif";
  Fonts[2] = "Tahoma";
	Fonts[3] = "Verdana";
	Fonts[4] = "Courier New";
	Fonts[5] = "Georgia";
	Fonts[6] = "Times New Roman";
	Fonts[7] = "Impact";
  Fonts[8] = "Comic Sans MS";

// List of available block formats (not in use)
var BlockFormats = new Array();
  BlockFormats[0]  = "Address";
  BlockFormats[1]  = "Bulleted List";
  BlockFormats[2]  = "Definition";
	BlockFormats[3]  = "Definition Term";
	BlockFormats[4]  = "Directory List";
	BlockFormats[5]  = "Formatted";
	BlockFormats[6]  = "Heading 1";
	BlockFormats[7]  = "Heading 2";
	BlockFormats[8]  = "Heading 3";
	BlockFormats[9]  = "Heading 4";
	BlockFormats[10] = "Heading 5";
	BlockFormats[11] = "Heading 6";
	BlockFormats[12] = "Menu List";
	BlockFormats[13] = "Normal";
	BlockFormats[14] = "Numbered List";

// List of available font sizes
var FontSizes = new Array();
  FontSizes[0]  = "1";
  FontSizes[1]  = "2";
  FontSizes[2]  = "3";
	FontSizes[3]  = "4";
	FontSizes[4]  = "5";
	FontSizes[5]  = "6";
	FontSizes[6]  = "7";

// Order of available commands in toolbar one
var buttonName = new Array();
  buttonName[0]  = "bold";
  buttonName[1]  = "italic";
  buttonName[2]  = "underline";
	//buttonName[3]  = "strikethrough";
  buttonName[4]  = "seperator";
	buttonName[5]  = "subscript";
	buttonName[6]  = "superscript";
	buttonName[7]  = "seperator";
	buttonName[8]  = "justifyleft";
	buttonName[9]  = "justifycenter";
	buttonName[10] = "justifyright";
	buttonName[11] = "seperator";
	buttonName[12] = "unorderedlist";
	buttonName[13] = "orderedlist";
	buttonName[14] = "outdent";
	buttonName[15] = "indent";

// Order of available commands in toolbar two
var buttonName2 = new Array();
  buttonName2[0]  = "forecolor";
	buttonName2[1]  = "backcolor";
	buttonName2[2]  = "seperator";
	buttonName2[3]  = "cut";
	buttonName2[4]  = "copy";
	buttonName2[5]  = "paste";
	buttonName2[6]  = "seperator";
  buttonName2[7]  = "undo";
	buttonName2[8]  = "redo";
  buttonName2[9]  = "seperator";
	buttonName2[10]  = "inserttable";
  buttonName2[11]  = "insertimage";
  buttonName2[12]  = "createlink";
	buttonName2[13]  = "seperator";
	buttonName2[14]  = "viewSource";
	buttonName2[15]  = "seperator";
  buttonName2[16]  = "help";
	
// List of available actions and their respective ID and images
var ToolbarList = {
//Name              buttonID                 buttonTitle           buttonImage                            buttonImageRollover
  "bold":           ['Bold',                 'Bold',               imagesDir + 'bold.gif',               imagesDir + 'bold_on.gif'],
  "italic":         ['Italic',               'Italic',             imagesDir + 'italics.gif',            imagesDir + 'italics_on.gif'],
  "underline":      ['Underline',            'Underline',          imagesDir + 'underline.gif',          imagesDir + 'underline_on.gif'],
	"strikethrough":  ['Strikethrough',        'Strikethrough',      imagesDir + 'strikethrough.gif',      imagesDir + 'strikethrough_on.gif'],
	"seperator":      ['',                     '',                   imagesDir + 'seperator.gif',          imagesDir + 'seperator.gif'],
	"subscript":      ['Subscript',            'Subscript',          imagesDir + 'subscript.gif',          imagesDir + 'subscript_on.gif'],
	"superscript":    ['Superscript',          'Superscript',        imagesDir + 'superscript.gif',        imagesDir + 'superscript_on.gif'],
	"justifyleft":    ['Justifyleft',          'Justifyleft',        imagesDir + 'justify_left.gif',       imagesDir + 'justify_left_on.gif'],
	"justifycenter":  ['Justifycenter',        'Justifycenter',      imagesDir + 'justify_center.gif',     imagesDir + 'justify_center_on.gif'],
	"justifyright":   ['Justifyright',         'Justifyright',       imagesDir + 'justify_right.gif',      imagesDir + 'justify_right_on.gif'],
	"unorderedlist":  ['InsertUnorderedList',  'InsertUnorderedList',imagesDir + 'list_unordered.gif',     imagesDir + 'list_unordered_on.gif'],
	"orderedlist":    ['InsertOrderedList',    'InsertOrderedList',  imagesDir + 'list_ordered.gif',       imagesDir + 'list_ordered_on.gif'],
	"outdent":        ['Outdent',              'Outdent',            imagesDir + 'indent_left.gif',        imagesDir + 'indent_left_on.gif'],
	"indent":         ['Indent',               'Indent',             imagesDir + 'indent_right.gif',       imagesDir + 'indent_right_on.gif'],
	"cut":            ['Cut',                  'Cut',                imagesDir + 'cut.gif',                imagesDir + 'cut_on.gif'],
	"copy":           ['Copy',                 'Copy',               imagesDir + 'copy.gif',               imagesDir + 'copy_on.gif'],
  "paste":          ['Paste',                'Paste',              imagesDir + 'paste.gif',              imagesDir + 'paste_on.gif'],
	"forecolor":      ['ForeColor',            'ForeColor',          imagesDir + 'forecolor.gif',          imagesDir + 'forecolor_on.gif'],
	"backcolor":      ['BackColor',            'BackColor',          imagesDir + 'backcolor.gif',          imagesDir + 'backcolor_on.gif'],
	"undo":           ['Undo',                 'Undo',               imagesDir + 'undo.gif',               imagesDir + 'undo_on.gif'],
	"redo":           ['Redo',                 'Redo',               imagesDir + 'redo.gif',               imagesDir + 'redo_on.gif'],
	"inserttable":    ['InsertTable',          'InsertTable',        imagesDir + 'insert_table.gif',       imagesDir + 'insert_table_on.gif'],
	"insertimage":    ['InsertImage',          'InsertImage',        imagesDir + 'insert_picture.gif',     imagesDir + 'insert_picture_on.gif'],
	"createlink":     ['CreateLink',           'CreateLink',         imagesDir + 'insert_hyperlink.gif',   imagesDir + 'insert_hyperlink_on.gif'],
	"viewSource":     ['ViewSource',           'ViewSource',         imagesDir + 'view_source.gif',        imagesDir + 'view_source_on.gif'],
	"viewText":       ['ViewText',             'ViewText',           imagesDir + 'view_text.gif',          imagesDir + 'view_text_on.gif'],
	"help":           ['Help',                 'Help',               imagesDir + 'help.gif',               imagesDir + 'help_on.gif'],
	"selectfont":     ['SelectFont',           'SelectFont',         imagesDir + 'select_font.gif',        imagesDir + 'select_font_on.gif'],
	"selectsize":     ['SelectSize',           'SelectSize',         imagesDir + 'select_size.gif',        imagesDir + 'select_size_on.gif']
};



/* ---------------------------------------------------------------------- *\
  Function    : insertAdjacentHTML(), insertAdjacentText() and insertAdjacentElement()
  Description : Emulates insertAdjacentHTML(), insertAdjacentText() and 
	              insertAdjacentElement() three functions so they work with 
								Netscape 6/Mozilla
  Notes       : by Thor Larholm [email protected]
\* ---------------------------------------------------------------------- */
if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement){
  HTMLElement.prototype.insertAdjacentElement = function
  (where,parsedNode)
	{
	  switch (where){
		case 'beforeBegin':
			this.parentNode.insertBefore(parsedNode,this)
			break;
		case 'afterBegin':
			this.insertBefore(parsedNode,this.firstChild);
			break;
		case 'beforeEnd':
			this.appendChild(parsedNode);
			break;
		case 'afterEnd':
			if (this.nextSibling) 
      this.parentNode.insertBefore(parsedNode,this.nextSibling);
			else this.parentNode.appendChild(parsedNode);
			break;
		}
	}

	HTMLElement.prototype.insertAdjacentHTML = function
  (where,htmlStr)
	{
		var r = this.ownerDocument.createRange();
		r.setStartBefore(this);
		var parsedHTML = r.createContextualFragment(htmlStr);
		this.insertAdjacentElement(where,parsedHTML)
	}


	HTMLElement.prototype.insertAdjacentText = function
  (where,txtStr)
	{
		var parsedText = document.createTextNode(txtStr)
		this.insertAdjacentElement(where,parsedText)
	}
};


// Create viewTextMode global variable and set to 0
// enabling all toolbar commands while in HTML mode
viewTextMode = 0;



/* ---------------------------------------------------------------------- *\
  Function    : generate_wysiwyg()
  Description : replace textarea with wysiwyg editor
  Usage       : generate_wysiwyg("textarea_id");
  Arguments   : textarea_id - ID of textarea to replace
\* ---------------------------------------------------------------------- */
function generate_wysiwyg(textareaID) {
 
  	// Hide the textarea 
	document.getElementById(textareaID).style.display = 'none'; 
	
  // Pass the textareaID to the "n" variable.
  var n = textareaID;
	
	// Toolbars width is 2 pixels wider than the wysiwygs
	toolbarWidth = parseFloat(wysiwygWidth) + 2;
	
  // Generate WYSIWYG toolbar one
  var toolbar;
  toolbar =  '<table cellpadding="0" cellspacing="0" border="0" class="toolbar1" style="width:' + toolbarWidth + 'px;"><tr><td style="width: 6px;"><img src="' +imagesDir+ 'seperator2.gif" alt="" hspace="3"></td>';
  
	// Create IDs for inserting Font Type and Size drop downs
	toolbar += '<td style="width: 90px;"><span id="FontSelect' + n + '"></span></td>';
	toolbar += '<td style="width: 60px;"><span id="FontSizes'  + n + '"></span></td>';
  
	// Output all command buttons that belong to toolbar one
	for (var i = 0; i <= buttonName.length;) { 
    if (buttonName[i]) {
	    var buttonObj            = ToolbarList[buttonName[i]];
		  var buttonID             = buttonObj[0];
	    var buttonTitle          = buttonObj[1];
      var buttonImage          = buttonObj[2];
		  var buttonImageRollover  = buttonObj[3];
	    
			if (buttonName[i] == "seperator") {
		    toolbar += '<td style="width: 12px;" align="center"><img src="' +buttonImage+ '" border=0 unselectable="on" width="2" height="18" hspace="2" unselectable="on"></td>';
			}
	    else {
		    toolbar += '<td style="width: 22px;"><img src="' +buttonImage+ '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +buttonID+ '" class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' + buttonImageRollover + '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on" width="20" height="20"></td>';
	    }
    }
    i++;
  }

  toolbar += '<td>&nbsp;</td></tr></table>';  

  // Generate WYSIWYG toolbar two
  var toolbar2;
  toolbar2 = '<table cellpadding="0" cellspacing="0" border="0" class="toolbar2" style="width:' + toolbarWidth + 'px;"><tr><td style="width: 6px;"><img src="' +imagesDir+ 'seperator2.gif" alt="" hspace="3"></td>';
 
  // Output all command buttons that belong to toolbar two
  for (var j = 0; j <= buttonName2.length;) {
    if (buttonName2[j]) {
	    var buttonObj            = ToolbarList[buttonName2[j]];
		  var buttonID             = buttonObj[0];
	    var buttonTitle          = buttonObj[1];
      var buttonImage          = buttonObj[2];
		  var buttonImageRollover  = buttonObj[3];
	  
		  if (buttonName2[j] == "seperator") {
		    toolbar2 += '<td style="width: 12px;" align="center"><img src="' +buttonImage+ '" border=0 unselectable="on" width="2" height="18" hspace="2" unselectable="on"></td>';
			}
	    else if (buttonName2[j] == "viewSource"){
		    toolbar2 += '<td style="width: 22px;">';
				toolbar2 += '<span id="HTMLMode' + n + '"><img src="'  +buttonImage+  '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +buttonID+ '" class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +buttonImageRollover+ '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on"  width="20" height="20"></span>';
				toolbar2 += '<span id="textMode' + n + '"><img src="' +imagesDir+ 'view_text.gif" border=0 unselectable="on" title="viewText"          id="ViewText"       class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +imagesDir+ 'view_text_on.gif\';"    onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' +imagesDir+ 'view_text.gif\';" unselectable="on"  width="20" height="20"></span>';
	      toolbar2 += '</td>';
			}
	    else {
		    toolbar2 += '<td style="width: 22px;"><img src="' +buttonImage+ '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +buttonID+ '" class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +buttonImageRollover+ '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on" width="20" height="20"></td>';
	    }
    }
    j++;
  }

  toolbar2 += '<td>&nbsp;</td></tr></table>';  
	
 	
	// Create iframe which will be used for rich text editing
	var iframe = '<table cellpadding="0" cellspacing="0" border="0" style="width:' + wysiwygWidth + 'px; height:' + wysiwygHeight + 'px;border: 1px inset #CCCCCC;"><tr><td valign="top">\n'
  + '<iframe frameborder="0" id="wysiwyg' + n + '"></iframe>\n'
  + '</td></tr></table>\n';

  // Insert after the textArea both toolbar one and two
  document.getElementById(n).insertAdjacentHTML("afterEnd", toolbar + toolbar2 + iframe);
	
  // Insert the Font Type and Size drop downs into the toolbar
	outputFontSelect(n);
	outputFontSizes(n); 
	
  // Hide the dynamic drop down lists for the Font Types and Sizes
  hideFonts(n);
	hideFontSizes(n);
	
	// Hide the "Text Mode" button
	document.getElementById("textMode" + n).style.display = 'none'; 
	
	// Give the iframe the global wysiwyg height and width
  document.getElementById("wysiwyg" + n).style.height = wysiwygHeight + "px";
  document.getElementById("wysiwyg" + n).style.width = wysiwygWidth + "px";
	
	// Pass the textarea's existing text over to the content variable
  var content = document.getElementById(n).value;
	
	var doc = document.getElementById("wysiwyg" + n).contentWindow.document;
	
	// Write the textarea's content into the iframe
  doc.open();
  doc.write(content);
  doc.close();
	
	// Make the iframe editable in both Mozilla and IE
  doc.body.contentEditable = true;
  doc.designMode = "on";
	
  	// Update the textarea with content in WYSIWYG when user submits form
  var browserName = navigator.appName;
  if (browserName == "Microsoft Internet Explorer") {
    for (var idx=0; idx < document.forms.length; idx++) {
      document.forms[idx].attachEvent('onsubmit', function() { updateTextArea(n); });
    }
  }
  else {
  	for (var idx=0; idx < document.forms.length; idx++) {
    	document.forms[idx].addEventListener('submit',function OnSumbmit() { updateTextArea(n); }, true);
    }
  }
 	

};



/* ---------------------------------------------------------------------- *\
  Function    : formatText()
  Description : replace textarea with wysiwyg editor
  Usage       : formatText(id, n, selected);
  Arguments   : id - The execCommand (e.g. Bold)
                n  - The editor identifier that the command 
								     affects (the textarea's ID)
                selected - The selected value when applicable (e.g. Arial)
\* ---------------------------------------------------------------------- */
function formatText(id, n, selected) {

  // When user clicks toolbar button make sure it always targets its respective WYSIWYG
  document.getElementById("wysiwyg" + n).contentWindow.focus();
	
	// When in Text Mode these execCommands are disabled
	var formatIDs = new Array("FontSize","FontName","Bold","Italic","Underline","Subscript","Superscript","Strikethrough","Justifyleft","Justifyright","Justifycenter","InsertUnorderedList","InsertOrderedList","Indent","Outdent","ForeColor","BackColor","InsertImage","InsertTable","CreateLink");
  
	// Check if button clicked is in disabled list
	for (var i = 0; i <= formatIDs.length;) {
		if (formatIDs[i] == id) {
			 var disabled_id = 1; 
		}
	  i++;
	}
	
	// Check if in Text Mode and disabled button was clicked
	if (viewTextMode == 1 && disabled_id == 1) {
	  alert ("You are in HTML Mode. This feature has been disabled.");	
	}
	
	else {
	
	  // FontSize
	  if (id == "FontSize") {
      document.getElementById("wysiwyg" + n).contentWindow.document.execCommand("FontSize", false, selected);
	  }
	  
		// FontName
	  else if (id == "FontName") {
      document.getElementById("wysiwyg" + n).contentWindow.document.execCommand("FontName", false, selected);
	  }
	
	  // ForeColor and BackColor
    else if (id == 'ForeColor' || id == 'BackColor') {
      var w = screen.availWidth;
      var h = screen.availHeight;
      var popW = 210, popH = 165;
      var leftPos = (w-popW)/2, topPos = (h-popH)/2;
      var currentColor = _dec_to_rgb(document.getElementById("wysiwyg" + n).contentWindow.document.queryCommandValue(id));
   
	    window.open(popupsDir + 'select_color.html?color=' + currentColor + '&command=' + id + '&wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,width=' + popW + ',height=' + popH + ',top=' + topPos + ',left=' + leftPos);
    }
	  
		// InsertImage
	  else if (id == "InsertImage") {
      window.open(popupsDir + 'insert_image.html?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=190');
	  }
	  
		// InsertTable
	  else if (id == "InsertTable") {
	    window.open(popupsDir + 'create_table.html?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=360');
	  }
	  
		// CreateLink
	  else if (id == "CreateLink") {
	    window.open(popupsDir + 'insert_hyperlink.html?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=300,height=110');
	  }
	  
		// ViewSource
    else if (id == "ViewSource") {
	    viewSource(n);
	  }
		
		// ViewText
		else if (id == "ViewText") {
	    viewText(n);
	  }

		// Help
		else if (id == "Help") {
	    window.open(popupsDir + 'about.html','popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=330');
	  }
	  
		// Every other command
	  else {
      document.getElementById("wysiwyg" + n).contentWindow.document.execCommand(id, false, null);
		}
  }
};



/* ---------------------------------------------------------------------- *\
  Function    : insertHTML()
  Description : insert HTML into WYSIWYG in rich text
  Usage       : insertHTML(<b>hello</b>, "textareaID")
  Arguments   : html - The HTML being inserted (e.g. <b>hello</b>)
                n  - The editor identifier that the HTML 
								     will be inserted into (the textarea's ID)
\* ---------------------------------------------------------------------- */
function insertHTML(html, n) {

  var browserName = navigator.appName;
	 	 
	if (browserName == "Microsoft Internet Explorer") {	  
	  document.getElementById('wysiwyg' + n).contentWindow.document.selection.createRange().pasteHTML(html);   
	} 
	 
	else {
	  var div = document.getElementById('wysiwyg' + n).contentWindow.document.createElement("div");
		 
		div.innerHTML = html;
		var node = insertNodeAtSelection(div, n);		
	}
	
}


/* ---------------------------------------------------------------------- *\
  Function    : insertNodeAtSelection()
  Description : insert HTML into WYSIWYG in rich text (mozilla)
  Usage       : insertNodeAtSelection(insertNode, n)
  Arguments   : insertNode - The HTML being inserted (must be innerHTML 
	                           inserted within a div element)
                n          - The editor identifier that the HTML will be 
								             inserted into (the textarea's ID)
\* ---------------------------------------------------------------------- */
function insertNodeAtSelection(insertNode, n) {
  // get current selection
  var sel = document.getElementById('wysiwyg' + n).contentWindow.getSelection();

  // get the first range of the selection
  // (there's almost always only one range)
  var range = sel.getRangeAt(0);

  // deselect everything
  sel.removeAllRanges();

  // remove content of current selection from document
  range.deleteContents();

  // get location of current selection
  var container = range.startContainer;
  var pos = range.startOffset;

  // make a new range for the new selection
  range=document.createRange();

  if (container.nodeType==3 && insertNode.nodeType==3) {

    // if we insert text in a textnode, do optimized insertion
    container.insertData(pos, insertNode.nodeValue);

    // put cursor after inserted text
    range.setEnd(container, pos+insertNode.length);
    range.setStart(container, pos+insertNode.length);
  } 
	
	else {
    var afterNode;
    
		if (container.nodeType==3) {
      // when inserting into a textnode
      // we create 2 new textnodes
      // and put the insertNode in between

      var textNode = container;
      container = textNode.parentNode;
      var text = textNode.nodeValue;

      // text before the split
      var textBefore = text.substr(0,pos);
      // text after the split
      var textAfter = text.substr(pos);

      var beforeNode = document.createTextNode(textBefore);
      afterNode = document.createTextNode(textAfter);

      // insert the 3 new nodes before the old one
      container.insertBefore(afterNode, textNode);
      container.insertBefore(insertNode, afterNode);
      container.insertBefore(beforeNode, insertNode);

      // remove the old node
      container.removeChild(textNode);
    } 
	
	  else {
      // else simply insert the node
      afterNode = container.childNodes[pos];
      container.insertBefore(insertNode, afterNode);
    }

    range.setEnd(afterNode, 0);
    range.setStart(afterNode, 0);
  }

  sel.addRange(range);
};

	

/* ---------------------------------------------------------------------- *\
  Function    : _dec_to_rgb
  Description : convert a decimal color value to rgb hexadecimal
  Usage       : var hex = _dec_to_rgb('65535');   // returns FFFF00
  Arguments   : value   - dec value
\* ---------------------------------------------------------------------- */

function _dec_to_rgb(value) {
  var hex_string = "";
  for (var hexpair = 0; hexpair < 3; hexpair++) {
    var myByte = value & 0xFF;            // get low byte
    value >>= 8;                          // drop low byte
    var nybble2 = myByte & 0x0F;          // get low nybble (4 bits)
    var nybble1 = (myByte >> 4) & 0x0F;   // get high nybble
    hex_string += nybble1.toString(16);   // convert nybble to hex
    hex_string += nybble2.toString(16);   // convert nybble to hex
  }
  return hex_string.toUpperCase();
};



/* ---------------------------------------------------------------------- *\
  Function    : outputFontSelect()
  Description : creates the Font Select drop down and inserts it into 
	              the toolbar
  Usage       : outputFontSelect(n)
  Arguments   : n   - The editor identifier that the Font Select will update
	                    when making font changes (the textarea's ID)
\* ---------------------------------------------------------------------- */
function outputFontSelect(n) {

  var FontSelectObj        = ToolbarList['selectfont'];
  var FontSelect           = FontSelectObj[2];
  var FontSelectOn         = FontSelectObj[3];
  
	Fonts.sort();
	var FontSelectDropDown = new Array;
	FontSelectDropDown[n] = '<table border="0" cellpadding="0" cellspacing="0"><tr><td onMouseOver="document.getElementById(\'selectFont' + n + '\').src=\'' + FontSelectOn + '\';" onMouseOut="document.getElementById(\'selectFont' + n + '\').src=\'' + FontSelect + '\';"><img src="' + FontSelect + '" id="selectFont' + n + '" width="85" height="20" onClick="showFonts(\'' + n + '\');" unselectable="on"><br>';
	FontSelectDropDown[n] += '<span id="Fonts' + n + '" class="dropdown" style="width: 145px;">';

	for (var i = 0; i <= Fonts.length;) {
	  if (Fonts[i]) {
      FontSelectDropDown[n] += '<button type="button" onClick="formatText(\'FontName\',\'' + n + '\',\'' + Fonts[i] + '\')\; hideFonts(\'' + n + '\');" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 120px;"><table cellpadding="0" cellspacing="0" border="0"><tr><td align="left" style="font-family:' + Fonts[i] + '; font-size: 12px;">' + Fonts[i] + '</td></tr></table></button><br>';	
    }	  
	  i++;
  }
	FontSelectDropDown[n] += '</span></td></tr></table>';
	document.getElementById('FontSelect' + n).insertAdjacentHTML("afterBegin", FontSelectDropDown[n]);
};



/* ---------------------------------------------------------------------- *\
  Function    : outputFontSizes()
  Description : creates the Font Sizes drop down and inserts it into 
	              the toolbar
  Usage       : outputFontSelect(n)
  Arguments   : n   - The editor identifier that the Font Sizes will update
	                    when making font changes (the textarea's ID)
\* ---------------------------------------------------------------------- */
function outputFontSizes(n) {

  var FontSizeObj        = ToolbarList['selectsize'];
  var FontSize           = FontSizeObj[2];
  var FontSizeOn         = FontSizeObj[3];

	FontSizes.sort();
	var FontSizesDropDown = new Array;
	FontSizesDropDown[n] = '<table border="0" cellpadding="0" cellspacing="0"><tr><td onMouseOver="document.getElementById(\'selectSize' + n + '\').src=\'' + FontSizeOn + '\';" onMouseOut="document.getElementById(\'selectSize' + n + '\').src=\'' + FontSize + '\';"><img src="' + FontSize + '" id="selectSize' + n + '" width="49" height="20" onClick="showFontSizes(\'' + n + '\');" unselectable="on"><br>';
  FontSizesDropDown[n] += '<span id="Sizes' + n + '" class="dropdown" style="width: 170px;">';

	for (var i = 0; i <= FontSizes.length;) {
	  if (FontSizes[i]) {
      FontSizesDropDown[n] += '<button type="button" onClick="formatText(\'FontSize\',\'' + n + '\',\'' + FontSizes[i] + '\')\;hideFontSizes(\'' + n + '\');" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 145px;"><table cellpadding="0" cellspacing="0" border="0"><tr><td align="left" style="font-family: arial, verdana, helvetica;"><font size="' + FontSizes[i] + '">size ' + FontSizes[i] + '</font></td></tr></table></button><br>';	
    }	  
	  i++;
  }
	FontSizesDropDown[n] += '</span></td></tr></table>';
	document.getElementById('FontSizes' + n).insertAdjacentHTML("afterBegin", FontSizesDropDown[n]);
};



/* ---------------------------------------------------------------------- *\
  Function    : hideFonts()
  Description : Hides the list of font names in the font select drop down
  Usage       : hideFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function hideFonts(n) {
  document.getElementById('Fonts' + n).style.display = 'none'; 
};



/* ---------------------------------------------------------------------- *\
  Function    : hideFontSizes()
  Description : Hides the list of font sizes in the font sizes drop down
  Usage       : hideFontSizes(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function hideFontSizes(n) {
  document.getElementById('Sizes' + n).style.display = 'none'; 
};



/* ---------------------------------------------------------------------- *\
  Function    : showFonts()
  Description : Shows the list of font names in the font select drop down
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function showFonts(n) { 
  if (document.getElementById('Fonts' + n).style.display == 'block') {
    document.getElementById('Fonts' + n).style.display = 'none';
	}
  else {
    document.getElementById('Fonts' + n).style.display = 'block'; 
    document.getElementById('Fonts' + n).style.position = 'absolute';		
  }
};



/* ---------------------------------------------------------------------- *\
  Function    : showFontSizes()
  Description : Shows the list of font sizes in the font sizes drop down
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function showFontSizes(n) { 
  if (document.getElementById('Sizes' + n).style.display == 'block') {
    document.getElementById('Sizes' + n).style.display = 'none';
	}
  else {
    document.getElementById('Sizes' + n).style.display = 'block'; 
    document.getElementById('Sizes' + n).style.position = 'absolute';		
  }
};



/* ---------------------------------------------------------------------- *\
  Function    : viewSource()
  Description : Shows the HTML source code generated by the WYSIWYG editor
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function viewSource(n) {
  var getDocument = document.getElementById("wysiwyg" + n).contentWindow.document;
  var browserName = navigator.appName;
	
	// View Source for IE 	 
  if (browserName == "Microsoft Internet Explorer") {
    var iHTML = getDocument.body.innerHTML;
    getDocument.body.innerText = iHTML;
	}
 
  // View Source for Mozilla/Netscape
  else {
    var html = document.createTextNode(getDocument.body.innerHTML);
    getDocument.body.innerHTML = "";
    getDocument.body.appendChild(html);
	}
  
	// Hide the HTML Mode button and show the Text Mode button
  document.getElementById('HTMLMode' + n).style.display = 'none'; 
	document.getElementById('textMode' + n).style.display = 'block';
	
	// set the font values for displaying HTML source
	getDocument.body.style.fontSize = "12px";
	getDocument.body.style.fontFamily = "Courier New"; 
	
  viewTextMode = 1;
};



/* ---------------------------------------------------------------------- *\
  Function    : viewSource()
  Description : Shows the HTML source code generated by the WYSIWYG editor
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function viewText(n) { 
  var getDocument = document.getElementById("wysiwyg" + n).contentWindow.document;
  var browserName = navigator.appName;
	
	// View Text for IE 	  	 
  if (browserName == "Microsoft Internet Explorer") {
    var iText = getDocument.body.innerText;
    getDocument.body.innerHTML = iText;
	}
  
	// View Text for Mozilla/Netscape
  else {
    var html = getDocument.body.ownerDocument.createRange();
    html.selectNodeContents(getDocument.body);
    getDocument.body.innerHTML = html.toString();
	}
  
	// Hide the Text Mode button and show the HTML Mode button
  document.getElementById('textMode' + n).style.display = 'none'; 
	document.getElementById('HTMLMode' + n).style.display = 'block';
	
	// reset the font values
  getDocument.body.style.fontSize = "";
	getDocument.body.style.fontFamily = ""; 
	viewTextMode = 0;
};



/* ---------------------------------------------------------------------- *\
  Function    : updateTextArea()
  Description : Updates the text area value with the HTML source of the WYSIWYG
  Usage       : updateTextArea(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function updateTextArea(n) {
  document.getElementById(n).value = document.getElementById("wysiwyg" + n).contentWindow.document.body.innerHTML;
};

Added modules/wysiwyg/pkgIndex.tcl.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded httpd::wysiwyg 0.1 [list source [file join $dir wysiwyg.tcl]]

Added modules/wysiwyg/popups/about.html.





























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<html>
<head>
<title>openWYSIWYG | About</title>
</head>
<body bgcolor="#EEEEEE" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0">


<table border="0" cellpadding="0" cellspacing="0" style="padding: 10px;"><tr><td>
<table width="380" border="0" cellpadding="0" cellspacing="0">
 <tr>
  <td style="border-bottom: 2px solid #FFFFFF;" rowspan="2"><img src="../icons/logo.gif" alt="openWebWare: openWYSIWYG" height="34" width="191"></td>
	<td colspan="4">&nbsp;</td>
 </tr>
 <tr>
  <td width="60" style="background-color: #F7F7F7;">
	
	<table width="60" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border-width: 2 2 0 2; border-style: solid; border-color: #FFFFFF; border-bottom: 2px solid #F7F7F7; padding: 2px;">
	 <tr>
	  <td align="center" style="font-family: arial, verdana, helvetica, sans serif; font-size: 10px;"><a href="about.html" style="color: #000000; text-decoration: none;"><div>About</div></a></td>
	 </tr>
	</table> 

	</td>
	<td width="5" style="border-bottom: 2px solid #FFFFFF;">&nbsp;</td>
	<td width="60" style="background-color: #F7F7F7;">
	
	<table width="60" border="0" cellpadding="0" cellspacing="0" style="background-color: #DDDDDD; border: 2px solid #FFFFFF; padding: 2px;">
	 <tr>
	  <td align="center" style="font-family: arial, verdana, helvetica, sans serif; font-size: 10px;"><a href="about_license.html" style="color: #000000; text-decoration: none;"><div>License</div></a></td>
	 </tr>
	</table> 
	
	</td>
	<td width="5" style="border-bottom: 2px solid #FFFFFF;">&nbsp;</td>
 </tr>	
</table>

<table width="380" border="0" cellpadding="0" cellspacing="0" style="height: 260px; background-color: #F7F7F7; border-width: 0 2 2 2; border-style: solid; border-color: #FFFFFF; padding: 5px;">
 <tr>
  <td style="font-family: arial, verdana, helvetica, sans serif; font-size: 10px;">
	An open source cross-browser WYSIWYG editor.<br><br>

  Version 1.01<br><br>

  Copyright &copy 2006 <a href="http://www.openwebware.com/" target="_blank">openWebWare.com</a><br>
  All Rights Reserved<br><br>
	
	<br><b style="font-size: 12px;">Resources:</b>
	<ul>
	 <li><a href="http://www.openwebware.com/" target="_blank">openWebWare.com Website</a> - open source applications and developer tools.</li>
	 <li style="margin-top: 3px;"><a href="http://www.openwebware.com/products/openwysiwyg/" target="_blank">openWYSIWYG Homepage</a> - cross browser &lt;textarea&gt; replacelemt.</li>
	 <li style="margin-top: 3px;"><a href="http://www.openwebware.com/forum/viewforum.php?f=1" target="_blank">User Forums</a> - trade openWYSIWYG tips and tricks with other developers.</li>
	 <li style="margin-top: 3px;"><a href="http://www.openwebware.com/products/openwysiwyg/docs/" target="_blank">Online Documentation</a> - user documentation.</li>
	</ul>
	
	</td>
 </tr>
</table>
</td></tr></table>

</body>
</html>

Added modules/wysiwyg/popups/about_license.html.





































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<html>
<head>
<title>openWYSIWYG | About</title>
</head>
<body bgcolor="#EEEEEE" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0">


<table border="0" cellpadding="0" cellspacing="0" style="padding: 10px;"><tr><td>
<table width="380" border="0" cellpadding="0" cellspacing="0">
 <tr>
  <td style="border-bottom: 2px solid #FFFFFF;" rowspan="2"><img src="../icons/logo.gif" alt="openWebWare: openWYSIWYG" height="34" width="191"></td>
	<td colspan="4">&nbsp;</td>
 </tr>
 <tr>
  <td width="60" style="background-color: #F7F7F7;">
	
	<table width="60" border="0" cellpadding="0" cellspacing="0" style="background-color: #DDDDDD; border: 2px solid #FFFFFF; padding: 2px;">
	 <tr>
	  <td align="center" style="font-family: arial, verdana, helvetica, sans serif; font-size: 10px;"><a href="about.html" style="color: #000000; text-decoration: none;"><div>About</div></a></td>
	 </tr>
	</table> 

	</td>
	<td width="5" style="border-bottom: 2px solid #FFFFFF;">&nbsp;</td>
	<td width="60" style="background-color: #F7F7F7;">
	
	<table width="60" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border-width: 2 2 0 2; border-style: solid; border-color: #FFFFFF; border-bottom: 2px solid #F7F7F7; padding: 2px;">
	 <tr>
	  <td align="center" style="font-family: arial, verdana, helvetica, sans serif; font-size: 10px;"><a href="about_license.html" style="color: #000000; text-decoration: none;"><div>License</div></a></td>
	 </tr>
	</table> 
	
	</td>
	<td width="5" style="border-bottom: 2px solid #FFFFFF;">&nbsp;</td>
 </tr>	
</table>

<table width="380" border="0" cellpadding="0" cellspacing="0" style="height: 260px; background-color: #F7F7F7; border-width: 0 2 2 2; border-style: solid; border-color: #FFFFFF; padding: 5px;">
 <tr>
  <td style="font-family: arial, verdana, helvetica, sans serif; font-size: 10px;">
  
	<iframe style="width: 360px; height: 244px;" src="license.html"></iframe>
	
	</td>
 </tr>
</table>
</td></tr></table>

</body>
</html>

Added modules/wysiwyg/popups/create_table.html.







































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG | Create Table</title>
</head>
<link rel="stylesheet" type="text/css" href="../styles/styles.css">
<script language="JavaScript" type="text/javascript">

var qsParm = new Array();

/* ---------------------------------------------------------------------- *\
  Function    : init()
  Description : Calls the initial functions when page loads.
\* ---------------------------------------------------------------------- */
function init() {
  retrieveWYSIWYG(); 
	hideOnBorderStyles(); 
	hideOnBorderWidths(); 
	hideColorMenus();
}



/* ---------------------------------------------------------------------- *\
  Function    : retrieveWYSIWYG()
  Description : Retrieves the textarea ID for which the table will be inserted into.
\* ---------------------------------------------------------------------- */
function retrieveWYSIWYG() {
  var query = window.location.search.substring(1);
  var parms = query.split('&');
  for (var i=0; i<parms.length; i++) {
    var pos = parms[i].indexOf('=');
    if (pos > 0) {
       var key = parms[i].substring(0,pos);
       var val = parms[i].substring(pos+1);
       qsParm[key] = val;
    }
  }
}



/* ---------------------------------------------------------------------- *\
  Function    : buildTable()
  Description : Builds a table and inserts it into the WYSIWYG.
\* ---------------------------------------------------------------------- */
function buildTable() {
  
	// Checks if the table border will use the BORDER-COLLAPSE CSS attribute
	var collapse;
	if (document.getElementById('borderCollapse').checked == true) {
	  collapse = document.getElementById('borderCollapse').value;
		}
	else {
	  collapse = "separate";
		}
	
	// Builds a table based on the data input into the form
  var table = '<table border="0" cellpadding="0" cellspacing="0" style="';
	table += 'BORDER-COLLAPSE: ' + collapse + ';';  
	table += ' border: ' + document.getElementById('borderWidth').value + ' ' +  document.getElementById('borderStyle').value + ' ' +  document.getElementById('borderColor').value + ';';	
  table += ' width: ' + document.getElementById('tableWidth').value + document.getElementById('widthType').value + ';';
	table += ' background-color: ' + document.getElementById('shadingColor').value + ';"';
  table += ' alignment="' + document.getElementById('alignment').value + '">\n';	
	
	// Creates the number of rows and cols the table will have
	for (var i = 0; i < document.getElementById('rows').value; i++) {
	  table += '<tr>\n';
		  for (var j = 0; j < document.getElementById('cols').value; j++) {
		    table += '<td style="border: ' + document.getElementById('borderWidth').value + ' ' +  document.getElementById('borderStyle').value + ' ' +  document.getElementById('borderColor').value + '; padding: ' + document.getElementById('padding').value + ';">&nbsp;</td>\n';
		  }
		table += '</tr>\n';
  }
	
	table += '</table>\n';
	
	
	// Inserts the table code into the WYSIWYG editor	
	window.opener.insertHTML(table, qsParm['wysiwyg']);
  window.close();
}

/* ---------------------------------------------------------------------- *\
  Function    : hideOnBorderWidths()
  Description : Hides any table cell with an ID of "#px on" (e.g. "3px on").
\* ---------------------------------------------------------------------- */
function hideOnBorderWidths() {

  var onBorderWidths = new Array();
    onBorderWidths[0] = "1px on";
    onBorderWidths[1] = "2px on";
    onBorderWidths[2] = "3px on";
		onBorderWidths[3] = "4px on";
		onBorderWidths[4] = "5px on";
		onBorderWidths[5] = "6px on";
	
  for (var j = 0; j < onBorderWidths.length;) {
    document.getElementById(onBorderWidths[j]).style.display = 'none';
	  j++;
  }
}


/* ---------------------------------------------------------------------- *\
  Function    : showOffBorderWidths()
  Description : Shows all table cells with an ID of "#px" (e.g. "3px"). 
\* ---------------------------------------------------------------------- */
function showOffBorderWidths() {

  var offBorderWidths = new Array();
    offBorderWidths[0] = "1px";
    offBorderWidths[1] = "2px";
    offBorderWidths[2] = "3px";
		offBorderWidths[3] = "4px";
		offBorderWidths[4] = "5px";
		offBorderWidths[5] = "6px";
	
  for (var j = 0; j < offBorderWidths.length;) {
    document.getElementById(offBorderWidths[j]).style.display = 'block';
	  j++;
  }
}



/* ---------------------------------------------------------------------- *\
  Function    : selectWidth()
  Description : Selects the width to be used in the output table.
	Usage       : selectWidth("3px")
\* ---------------------------------------------------------------------- */
function selectWidth(id) {

  // Hide the currently selected width
  hideOnBorderWidths();
	
	// Show all of the width options as unselected
	showOffBorderWidths();
	
	// Hide the "off" element and replace with an "on" element so option appears selected
	document.getElementById(id).style.display = 'none';
	document.getElementById(id + ' on').style.display = 'block';
	
	// Assign value to <input type="hidden" id="borderWidth">
	document.getElementById('borderWidth').value = id;
} 


/* ---------------------------------------------------------------------- *\
  Function    : hideOnBorderStyles()
  Description : Hides any table cell with an ID of "borderstyle on" 
	              (e.g. "dashed on").
\* ---------------------------------------------------------------------- */
function hideOnBorderStyles() {

  var onBorderStyles = new Array();
    onBorderStyles[0] = "No Border on";
    onBorderStyles[1] = "solid on";
    onBorderStyles[2] = "dashed on";
		onBorderStyles[3] = "dotted on";
		onBorderStyles[4] = "double on";
		onBorderStyles[5] = "inset on";
		onBorderStyles[6] = "outset on";
		onBorderStyles[7] = "groove on";
		onBorderStyles[8] = "ridge on";
	
  for (var j = 0; j < onBorderStyles.length;) {
    document.getElementById(onBorderStyles[j]).style.display = 'none';
	  j++;
  }
}



/* ---------------------------------------------------------------------- *\
  Function    : showOffBorderStyles()
  Description : Shows all table cells with an ID of "borderstyle" 
	              (e.g. "solid"). 
\* ---------------------------------------------------------------------- */
function showOffBorderStyles() {

  var offBorderStyles = new Array();
    offBorderStyles[0] = "No Border";
    offBorderStyles[1] = "solid";
    offBorderStyles[2] = "dashed";
		offBorderStyles[3] = "dotted";
		offBorderStyles[4] = "double";
		offBorderStyles[5] = "inset";
		offBorderStyles[6] = "outset";
		offBorderStyles[7] = "groove";
		offBorderStyles[8] = "ridge";
	
  for (var j = 0; j < offBorderStyles.length;) {
    document.getElementById(offBorderStyles[j]).style.display = 'block';
	  j++;
  }
}



/* ---------------------------------------------------------------------- *\
  Function    : selectBorder()
  Description : Selects the border style to be used in the output table.
	Usage       : selectBorder("dashed")
\* ---------------------------------------------------------------------- */
function selectBorder(id) {
  
	// Hide the currently selected border style
  hideOnBorderStyles();
	
	// Show all of the border style options as unselected
	showOffBorderStyles();
	
	// Hide the "off" element and replace with an "on" element so option appears selected
	document.getElementById(id).style.display = 'none';
	document.getElementById(id + ' on').style.display = 'block';
	
	// Assign value to <input type="hidden" id="borderStyle">
	document.getElementById('borderStyle').value = id;
} 
 


/* ---------------------------------------------------------------------- *\
  Function    : hideColorMenus()
  Description : Hide the menus used for selecting the border color and 
	              shading color. 
\* ---------------------------------------------------------------------- */
function hideColorMenus() {
  document.getElementById('borderColorMenu').style.display = "none";
	document.getElementById('shadingColorMenu').style.display = "none";
}


/* ---------------------------------------------------------------------- *\
  Function    : showBorderColorMenu()
  Description : Show the border color menu so user can select the table's 
	              border color. 
\* ---------------------------------------------------------------------- */
function showBorderColorMenu() {
  document.getElementById('borderColorMenu').style.display = "block";
}


/* ---------------------------------------------------------------------- *\
  Function    : previewBorderColor()
  Description : When mousing over a border color display the color in the 
	              preview square.
\* ---------------------------------------------------------------------- */
function previewBorderColor(color) {
  document.getElementById('borderColorPreview').style.backgroundColor = color;  
}


/* ---------------------------------------------------------------------- *\
  Function    : selectBorderColor()
  Description : Assigns the selected border color to 
	              <input type="hidden" id="borderColor">.
\* ---------------------------------------------------------------------- */
function selectBorderColor(color) {
  document.getElementById('borderColorPreview').style.backgroundColor = color;  
	document.getElementById('borderColorMenu').style.display = "none";
	document.getElementById('borderColor').value = color;
}



/* ---------------------------------------------------------------------- *\
  Function    : showShadingColorMenu()
  Description : Show the shading color menu so user can select the table's 
	              shading color. 
\* ---------------------------------------------------------------------- */
function showShadingColorMenu() {
  document.getElementById('shadingColorMenu').style.display = "block";
}



/* ---------------------------------------------------------------------- *\
  Function    : previewShadingColor()
  Description : When mousing over a shading color display the color in the 
	              preview square.
\* ---------------------------------------------------------------------- */
function previewShadingColor(color) {
  document.getElementById('shadingColorPreview').style.backgroundColor = color;  
}



/* ---------------------------------------------------------------------- *\
  Function    : selectShadingColor()
  Description : Assigns the selected shading color to 
	              <input type="hidden" id="shadingColor">.
\* ---------------------------------------------------------------------- */
function selectShadingColor(color) {
  document.getElementById('shadingColorPreview').style.backgroundColor = color;  
	document.getElementById('shadingColorMenu').style.display = "none";
	document.getElementById('shadingColor').value = color;
}
</script>

<body bgcolor="#EEEEEE" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0" onLoad="init();">

<table border="0" cellpadding="0" cellspacing="0" style="padding: 10px;"><tr><td>

<input type="hidden" name="borderWidth"  id="borderWidth"    value="0px">
<input type="hidden" name="borderStyle"  id="borderStyle"    value="solid">
<input type="hidden" name="borderColor"  id="borderColor"    value="#000000">
<input type="hidden" name="shadingColor" id="shadingColor"   value="#FFFFFF">

<span style="font-family: arial, verdana, helvetica; font-size: 11px; font-weight: bold;">Table Properties:</span>
<table width="380" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border: 2px solid #FFFFFF; padding: 5px;">
 <tr>
  <td style="padding-bottom: 2px; width: 50px; font-family: arial, verdana, helvetica; font-size: 11px;">Rows:</td>
	<td style="padding-bottom: 2px; width: 80px; "><input type="text" size="4" id="rows" name="rows" value="5" style="font-size: 10px; width: 65px;"></td>
  <td style="padding-bottom: 2px; width: 80px; font-family: arial, verdana, helvetica; font-size: 11px;">Table Width:
	<td style="padding-bottom: 2px; width: 180px; ">
	<input type="text" name="tableWidth" id="tableWidth" value="100" size="10" style="font-size: 10px; width: 65px;">&nbsp;
	<select name="widthType" id="widthType" style="margin-right: 10px; font-size: 10px;">
	 <option value="%">Percent</option>
	 <option value="px">Pixels</option>
	</select>
	</td>	
 </tr>
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Cols:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;"><input type="text" size="4" id="cols" name="cols" value="5" style="font-size: 10px; width: 65px;"></td>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Alignment:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;">
	<select name="alignment" id="alignment" style="margin-right: 10px; font-size: 10px; width: 65px;">
	 <option value="">Not Set</option>
	 <option value="Left">Left</option>
	 <option value="Right">Right</option>
	 <option value="Center">Center</option>
	</select>
	</td>
 </tr>
 <tr>
  <td style="padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Padding:</td>
	<td style="padding-top: 0px;"><input type="text" size="4" id="padding" name="padding" value="5" style="font-size: 10px; width: 65px;"></td> 
  <td style="padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Collapse:</td>
	<td style="padding-top: 0px;"><input type="checkbox" name="borderCollapse" id="borderCollapse"></td>
 </tr>
</table>	

<br>
<span style="font-family: arial, verdana, helvetica; font-size: 11px; font-weight: bold;">Border Properties:</span>
<table width="380" border="0" cellpadding="5" cellspacing="0" style="background-color: #F7F7F7; border: 2px solid #FFFFFF; padding: 5px;">
 <tr>
  <td>
	
	<div style="overflow: auto; width: 135px; height: 150px; border: 1px inset #CCCCCC; background-color: #FFFFFF;">
	<table border="0" cellpadding="0" cellspacing="0" width="115">
	 <tr id="No Border"    ><td class="off" onClick="selectBorder('No Border');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'" style="font-family: arial, verdana, helvetica; font-size: 11px;">&nbsp;No Border&nbsp;</td></tr>
	 <tr id="No Border on" ><td class="on" style="font-family: arial, verdana, helvetica; font-size: 11px;">&nbsp;No Border&nbsp;</td></tr>
	 
	 <tr id="solid"       ><td class="off" onClick="selectBorder('solid');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><hr style="border: 1px solid #000000;"></td></tr>
	 <tr id="solid on"    ><td class="on"><hr style="border: 1px solid #000000;"></td></tr>
	 
	 <tr id="dashed"      ><td class="off" onClick="selectBorder('dashed');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><hr style="border: 2px dashed #000000;"></td></tr>
	 <tr id="dashed on"   ><td class="on"><hr style="border: 2px dashed #000000;"></td></tr>
	 
	 
   <tr id="dotted"       ><td class="off" onClick="selectBorder('dotted');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><hr style="border: 2px dotted #000000;"></td></tr>
	 <tr id="dotted on"    ><td class="on"><hr style="border: 2px dotted #000000;"></td></tr>
	 
	 <tr id="double"       ><td class="off" onClick="selectBorder('double');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><div style="border-top-width: 6px; border-top-style: double; border-top-color: #000000; font-size: 1px; margin: 6 0 2 0;">&nbsp;</div></td></tr>
	 <tr id="double on"    ><td class="on"><div style="border-top-width: 6px; border-top-style: double; border-top-color: #000000; font-size: 1px; margin: 6 0 2 0;">&nbsp;</div></td></tr>
  
	 <tr id="inset"       ><td class="off" onClick="selectBorder('inset');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><div style="border: 2px inset #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
   <tr id="inset on"    ><td class="on"><div style="border: 2px inset #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
   
	 <tr id="outset"       ><td class="off" onClick="selectBorder('outset');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><div style="border: 2px outset #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
   <tr id="outset on"    ><td class="on"><div style="border: 2px outset #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
	 
	 <tr id="groove"       ><td class="off" onClick="selectBorder('groove');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><div style="border: 2px groove #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
   <tr id="groove on"    ><td class="on"><div style="border: 2px groove #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
	 
	 <tr id="ridge"        ><td class="off" onClick="selectBorder('ridge');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><div style="border: 2px ridge #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
   <tr id="ridge on"     ><td class="on"><div style="border: 2px ridge #DDDDDD; font-size: 4px; padding: 4px;">&nbsp;</div></td></tr>
	</table>
	</div>	
	
	</td>
	<td>
	
  <div style="overflow: auto; width: 135px; height: 150px; border: 1px inset #CCCCCC; background-color: #FFFFFF;">
	<table border="0" cellpadding="0" cellspacing="0" width="115">

	 <tr id="1px"       ><td class="off" onClick="selectWidth('1px');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">1px&nbsp;</td><td style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 <tr id="1px on"    ><td class="on"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">1px&nbsp;</td><td style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 
	 <tr id="2px"       ><td class="off" onClick="selectWidth('2px');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">2px&nbsp;</td><td style="border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 <tr id="2px on"    ><td class="on"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">2px&nbsp;</td><td style="border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
  
	 <tr id="3px"       ><td class="off" onClick="selectWidth('3px');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">3px&nbsp;</td><td style="border-bottom-width: 3px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 <tr id="3px on"    ><td class="on"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">3px&nbsp;</td><td style="border-bottom-width: 3px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 
	 <tr id="4px"       ><td class="off" onClick="selectWidth('4px');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">4px&nbsp;</td><td style="border-bottom-width: 4px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 <tr id="4px on"    ><td class="on"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">4px&nbsp;</td><td style="border-bottom-width: 4px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 
	 <tr id="5px"       ><td class="off" onClick="selectWidth('5px');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">5px&nbsp;</td><td style="border-bottom-width: 5px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 <tr id="5px on"    ><td class="on"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">5px&nbsp;</td><td style="border-bottom-width: 5px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 
	 <tr id="6px"       ><td class="off" onClick="selectWidth('6px');" onMouseOver="this.className = 'on'" onMouseOut="this.className = 'off'"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">6px&nbsp;</td><td style="border-bottom-width: 6px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 <tr id="6px on"    ><td class="on"><table cellpaddin="0" cellspacing="0" border="0"><tr><td style="font-family: arial, verdana, helvetica, sans serif; font-size: 12px;">6px&nbsp;</td><td style="border-bottom-width: 6px; border-bottom-style: solid; border-bottom-color: #000000; font-size: 1px; margin: 6 0 0 0; width: 80px;">&nbsp;</td></tr></table></td></tr>
	 
	</table>
	</div>	
	
	</td>
	<td style="font-family: arial, verdana, helvetica; font-size: 11px;" valign="top">
	
	 Color:
	 <table border="0" cellpadding="0" cellspacing="0">
	  <tr>
		 <td width="25"><table border="0" cellpadding="0" cellspacing="0"><tr><td style="width: 25px; background-color: #000000; border: 1px solid #000000; font-size: 10px;" id="borderColorPreview">&nbsp;</td></tr></table></td>
	   <td><button style="font-size: 10px; font-family: arial, verdana, helvetica, sans serif; margin-left: 2px; width: 28px;" onClick="showBorderColorMenu();">Pick</button></td>
		</tr>
	 </table> 
	 
	 
	 <div style="position: absolute; right: 30px;" id="borderColorMenu">
	 <table border="0" cellpadding="0" cellspacing="0" class="selectColorTable">
	  <tr>
		 <td>
		 
		  <table border="0" cellpadding="1" cellspacing="0"> 
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#000000');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#000000');"><div style="background-color: #000000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#993300');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#993300');"><div style="background-color: #993300;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#333300');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#333300');"><div style="background-color: #333300;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#003300');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#003300');"><div style="background-color: #003300;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#003366');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#003366');"><div style="background-color: #003366;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#000080');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#000080');"><div style="background-color: #000080;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#333399');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#333399');"><div style="background-color: #333399;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#333333');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#333333');"><div style="background-color: #333333;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#800000');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#800000');"><div style="background-color: #800000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FF6600');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FF6600');"><div style="background-color: #FF6600;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#808000');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#808000');"><div style="background-color: #808000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#008000');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#008000');"><div style="background-color: #008000;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#008080');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#008080');"><div style="background-color: #008080;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#0000FF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#0000FF');"><div style="background-color: #0000FF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#666699');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#666699');"><div style="background-color: #666699;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#808080');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#808080');"><div style="background-color: #808080;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FF0000');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FF0000');"><div style="background-color: #FF0000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FF9900');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FF9900');"><div style="background-color: #FF9900;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#99CC00');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#99CC00');"><div style="background-color: #99CC00;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#339966');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#339966');"><div style="background-color: #339966;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#33CCCC');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#33CCCC');"><div style="background-color: #33CCCC;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#3366FF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#3366FF');"><div style="background-color: #3366FF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#800080');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#800080');"><div style="background-color: #800080;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#999999');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#999999');"><div style="background-color: #999999;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FF00FF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FF00FF');"><div style="background-color: #FF00FF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FFCC00');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FFCC00');"><div style="background-color: #FFCC00;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FFFF00');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FFFF00');"><div style="background-color: #FFFF00;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#00FF00');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#00FF00');"><div style="background-color: #00FF00;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#00FFFF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#00FFFF');"><div style="background-color: #00FFFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#00CCFF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#00CCFF');"><div style="background-color: #00CCFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#993366');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#993366');"><div style="background-color: #993366;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#C0C0C0');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#C0C0C0');"><div style="background-color: #C0C0C0;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FF99CC');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FF99CC');"><div style="background-color: #FF99CC;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FFCC99');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FFCC99');"><div style="background-color: #FFCC99;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FFFF99');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FFFF99');"><div style="background-color: #FFFF99;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#CCFFCC');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#CCFFCC');"><div style="background-color: #CCFFCC;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#CCFFFF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#CCFFFF');"><div style="background-color: #CCFFFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#99CCFF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#99CCFF');"><div style="background-color: #99CCFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#CC99FF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#666699');"><div style="background-color: #666699;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewBorderColor('#FFFFFF');" onMouseOut="className = 'selectColorOff'" onClick="selectBorderColor('#FFFFFF');"><div style="background-color: #FFFFFF;" class="selectColorBox">&nbsp;</div></td>
			 </tr>	 
			</table>
			
		</tr>
	 </table>
	 </div>
	 
	 <br>	 
	 Shading:
	 <table border="0" cellpadding="0" cellspacing="0">
	  <tr>
		 <td width="25"><table border="0" cellpadding="0" cellspacing="0"><tr><td style="width: 25px; background-color: #FFFFFF; border: 1px solid #000000; font-size: 10px;" id="shadingColorPreview">&nbsp;</td></tr></table></td>
	   <td><button style="font-size: 10px; font-family: arial, verdana, helvetica, sans serif; margin-left: 2px; width: 28px;" onClick="showShadingColorMenu();">Pick</button></td>
		</tr>
	 </table> 
	 
	 <div style="position: absolute; right: 30px;" id="shadingColorMenu">
	 <table border="0" cellpadding="0" cellspacing="0" class="selectColorTable">
	  <tr>
		 <td>

		  <table border="0" cellpadding="1" cellspacing="0"> 
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#000000');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#000000');"><div style="background-color: #000000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#993300');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#993300');"><div style="background-color: #993300;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#333300');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#333300');"><div style="background-color: #333300;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#003300');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#003300');"><div style="background-color: #003300;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#003366');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#003366');"><div style="background-color: #003366;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#000080');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#000080');"><div style="background-color: #000080;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#333399');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#333399');"><div style="background-color: #333399;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#333333');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#333333');"><div style="background-color: #333333;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#800000');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#800000');"><div style="background-color: #800000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FF6600');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FF6600');"><div style="background-color: #FF6600;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#808000');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#808000');"><div style="background-color: #808000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#008000');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#008000');"><div style="background-color: #008000;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#008080');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#008080');"><div style="background-color: #008080;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#0000FF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#0000FF');"><div style="background-color: #0000FF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#666699');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#666699');"><div style="background-color: #666699;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#808080');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#808080');"><div style="background-color: #808080;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FF0000');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FF0000');"><div style="background-color: #FF0000;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FF9900');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FF9900');"><div style="background-color: #FF9900;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#99CC00');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#99CC00');"><div style="background-color: #99CC00;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#339966');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#339966');"><div style="background-color: #339966;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#33CCCC');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#33CCCC');"><div style="background-color: #33CCCC;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#3366FF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#3366FF');"><div style="background-color: #3366FF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#800080');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#800080');"><div style="background-color: #800080;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#999999');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#999999');"><div style="background-color: #999999;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FF00FF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FF00FF');"><div style="background-color: #FF00FF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FFCC00');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FFCC00');"><div style="background-color: #FFCC00;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FFFF00');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FFFF00');"><div style="background-color: #FFFF00;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#00FF00');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#00FF00');"><div style="background-color: #00FF00;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#00FFFF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#00FFFF');"><div style="background-color: #00FFFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#00CCFF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#00CCFF');"><div style="background-color: #00CCFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#993366');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#993366');"><div style="background-color: #993366;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#C0C0C0');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#C0C0C0');"><div style="background-color: #C0C0C0;" class="selectColorBox">&nbsp;</div></td>
			 </tr>
			 <tr>
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FF99CC');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FF99CC');"><div style="background-color: #FF99CC;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FFCC99');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FFCC99');"><div style="background-color: #FFCC99;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FFFF99');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FFFF99');"><div style="background-color: #FFFF99;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#CCFFCC');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#CCFFCC');"><div style="background-color: #CCFFCC;" class="selectColorBox">&nbsp;</div></td>		 
			  <td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#CCFFFF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#CCFFFF');"><div style="background-color: #CCFFFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#99CCFF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#99CCFF');"><div style="background-color: #99CCFF;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#CC99FF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#666699');"><div style="background-color: #666699;" class="selectColorBox">&nbsp;</div></td>
				<td class="selectColorBorder" onMouseOver="className = 'selectColorOn'; previewShadingColor('#FFFFFF');" onMouseOut="className = 'selectColorOff'" onClick="selectShadingColor('#FFFFFF');"><div style="background-color: #FFFFFF;" class="selectColorBox">&nbsp;</div></td>
		   </tr>	 
			</table>
			
		</tr>
	 </table>
	 </div>
	
	</td>
 </tr>
</table>
</td></tr></table>

<div align="right"><input type="submit" value="  Submit  " onClick="buildTable();" style="font-size: 12px;">&nbsp;<input type="submit" value="  Cancel  " onClick="window.close();" style="font-size: 12px; margin-right: 15px;" ></div>
</body>
</html>

Added modules/wysiwyg/popups/insert_hyperlink.html.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG | Select Color</title>
</head>
<script language="JavaScript" type="text/javascript">

var qsParm = new Array();


/* ---------------------------------------------------------------------- *\
  Function    : retrieveWYSIWYG()
  Description : Retrieves the textarea ID for which the link will be inserted into.
\* ---------------------------------------------------------------------- */
function retrieveWYSIWYG() {
  var query = window.location.search.substring(1);
  var parms = query.split('&');
  for (var i=0; i<parms.length; i++) {
    var pos = parms[i].indexOf('=');
    if (pos > 0) {
       var key = parms[i].substring(0,pos);
       var val = parms[i].substring(pos+1);
       qsParm[key] = val;
    }
  }
}


function insertHyperLink() {
  var hyperLink = document.getElementById('linkType').value + document.getElementById('url').value;
  window.opener.document.getElementById('wysiwyg' + qsParm['wysiwyg']).contentWindow.document.execCommand("CreateLink", false, hyperLink);
  window.close();
}

</script>
<body bgcolor="#EEEEEE" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0" onLoad="retrieveWYSIWYG();">

<table border="0" cellpadding="0" cellspacing="0" style="padding: 10px;"><tr><td>

<span style="font-family: arial, verdana, helvetica; font-size: 11px; font-weight: bold;">Insert Hyperlink:</span>
<table width="280" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border: 2px solid #FFFFFF; padding: 5px;">
 <tr>
  <td style="padding-bottom: 2px; width: 50px; font-family: arial, verdana, helvetica; font-size: 11px;">Type:</td>
	<td style="padding-bottom: 2px;">
	<select name="linkType" id="linkType" style="margin-right: 10px; font-size: 10px;">
	 <option value="http://">http:</option>
	 <option value="https://">https:</option>
	 <option value="mailto:">mailto:</option>
	</select>
	</td>	
 </tr>
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">URL:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;"><input type="text" name="url" id="url" value=""  style="font-size: 10px; width: 100%;"></td>
 </tr>
</table>	

<div align="right" style="padding-top: 5px;"><input type="submit" value="  Submit  " onClick="insertHyperLink();" style="font-size: 12px;" >&nbsp;<input type="submit" value="  Cancel  " onClick="window.close();" style="font-size: 12px;" ></div>

</tr></td</table>

</body>
</html>

Added modules/wysiwyg/popups/insert_image.html.



























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG | Select Color</title>
</head>
<script language="JavaScript" type="text/javascript">

var qsParm = new Array();


/* ---------------------------------------------------------------------- *\
  Function    : retrieveWYSIWYG()
  Description : Retrieves the textarea ID for which the image will be inserted into.
\* ---------------------------------------------------------------------- */
function retrieveWYSIWYG() {
  var query = window.location.search.substring(1);
  var parms = query.split('&');
  for (var i=0; i<parms.length; i++) {
    var pos = parms[i].indexOf('=');
    if (pos > 0) {
       var key = parms[i].substring(0,pos);
       var val = parms[i].substring(pos+1);
       qsParm[key] = val;
    }
  }
}


/* ---------------------------------------------------------------------- *\
  Function    : insertImage()
  Description : Inserts image into the WYSIWYG.
\* ---------------------------------------------------------------------- */
function insertImage() {
  var image = '<img src="' + document.getElementById('imageurl').value + '" alt="' + document.getElementById('alt').value + '" alignment="' + document.getElementById('alignment').value + '" border="' + document.getElementById('borderThickness').value + '" hspace="' + document.getElementById('horizontal').value + '" vspace="' + document.getElementById('vertical').value + '">';
  window.opener.insertHTML(image, qsParm['wysiwyg']);
  window.close();
}

</script>
<body bgcolor="#EEEEEE" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0" onLoad="retrieveWYSIWYG();">

<table border="0" cellpadding="0" cellspacing="0" style="padding: 10px;"><tr><td>

<span style="font-family: arial, verdana, helvetica; font-size: 11px; font-weight: bold;">Insert Image:</span>
<table width="380" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border: 2px solid #FFFFFF; padding: 5px;">
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;" width="80">Image URL:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;" width="300"><input type="text" name="imageurl" id="imageurl" value=""  style="font-size: 10px; width: 100%;"></td>
 </tr>
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Alternate Text:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;"><input type="text" name="alt" id="alt" value=""  style="font-size: 10px; width: 100%;"></td>
 </tr>
</table>
	


<table width="380" border="0" cellpadding="0" cellspacing="0" style="margin-top: 10px;"><tr><td>

<span style="font-family: arial, verdana, helvetica; font-size: 11px; font-weight: bold;">Layout:</span>
<table width="185" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border: 2px solid #FFFFFF; padding: 5px;">
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;" width="100">Alignment:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;" width="85">
	<select name="alignment" id="alignment" style="font-family: arial, verdana, helvetica; font-size: 11px; width: 100%;">
	 <option value="">Not Set</option>
	 <option value="left">Left</option>
	 <option value="right">Right</option>
	 <option value="texttop">Texttop</option>
	 <option value="absmiddle">Absmiddle</option>
	 <option value="baseline">Baseline</option>
	 <option value="absbottom">Absbottom</option>
	 <option value="bottom">Bottom</option>
	 <option value="middle">Middle</option>
	 <option value="top">Top</option>
	</select>
	</td>
 </tr>
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Border Thickness:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;"><input type="text" name="borderThickness" id="borderThickness" value=""  style="font-size: 10px; width: 100%;"></td>
 </tr>
</table>	

</td>
<td width="10">&nbsp;</td>
<td>

<span style="font-family: arial, verdana, helvetica; font-size: 11px; font-weight: bold;">Spacing:</span>
<table width="185" border="0" cellpadding="0" cellspacing="0" style="background-color: #F7F7F7; border: 2px solid #FFFFFF; padding: 5px;">
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;" width="80">Horizontal:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;" width="105"><input type="text" name="horizontal" id="horizontal" value=""  style="font-size: 10px; width: 100%;"></td>
 </tr>
 <tr>
  <td style="padding-bottom: 2px; padding-top: 0px; font-family: arial, verdana, helvetica; font-size: 11px;">Vertical:</td>
	<td style="padding-bottom: 2px; padding-top: 0px;"><input type="text" name="vertical" id="vertical" value=""  style="font-size: 10px; width: 100%;"></td>
 </tr>
</table>	

</td></tr></table>

<div align="right" style="padding-top: 5px;"><input type="submit" value="  Submit  " onClick="insertImage();" style="font-size: 12px;" >&nbsp;<input type="submit" value="  Cancel  " onClick="window.close();" style="font-size: 12px;" ></div>

</tr></td</table>

</body>
</html>

Added modules/wysiwyg/popups/license.html.













































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG | License</title>
</head>
<body style="font-family: arial, verdana, helvetia, sans serif; font-size: 12px; background-color: #FFFFFF;">
<h1>GNU Lesser General Public License</h1>

<p>Version 2.1, February 1999</p>

<blockquote>
<p>Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.</p>

<p>[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]</p></blockquote>

<h3>Preamble</h3>

<p> The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. </p>

 <p>This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.
</p>
<p> When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.</p>

 <p>To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.
</p>
<p> For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. </p>

 <p>We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. </p>

 <p>To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. </p>
<p>
 Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. </p>

 <p>Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. </p>

 <p>When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. </p>

 <p>We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. </p>

 <p>For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.
</p>
 <p>In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. </p>

<p> Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.
</p>
 <p>The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. </p>

<h3>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</h3>

<p><strong>0.</strong> This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".</p>

<p> A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. </p>

<p> The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) </p>

<p> "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.</p>

 <p>Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. </p>

<p><strong>1.</strong> You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.
</p>
<p> You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. </p>

<p><strong>2.</strong> You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
</p>

<blockquote>
<p>a) The modified work must itself be a software library. </p>
<p>b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.</p>
<p>c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. </p>
<p>d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. </p>


<p> (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) 
</p>
<p> These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
</p>
 <p>Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.
</p>
<p> In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
</p></blockquote>
<p><strong>3.</strong> You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. </p>

 <p>Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.
</p>
<p> This option is useful when you wish to copy part of the code of the Library into a program that is not a library.
</p>
<p><strong>4.</strong> You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.
</p>

 <p>If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.</p>

<p><strong>5.</strong> A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. </p>

<p> However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. </p>

<p> When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. </p>

<p> If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) </p>

<p>Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. </p>

<p><strong>6.</strong> As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. </p>
<p>
 You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: </p>

<blockquote><p>a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) </p>

<p>b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. </p>
<p>
c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. </p>

<p>d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. </p>

<p>e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.</p>
</blockquote>

 <p>For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. </p>

<p> It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. </p>

<p><strong>7.</strong> You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: </p>

<blockquote>
<p>a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. </p>

<p>b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.</p></blockquote>

<p><strong>8.</strong> You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. </p>
<p>
<strong>9.</strong> You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. </p>
<p>
<strong>10.</strong> Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. </p>

<p><strong>11.</strong> If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. </p>
<p>
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. </p>

<p>It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. </p>

<p>This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. </p>
<p>
<strong>12.</strong> If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. </p>
<p>
<strong>13.</strong> The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</p>

<p>Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. </p>
<p>
<strong>14.</strong> If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. </p>
<p>
NO WARRANTY </p>
<p>
<strong>15. </strong>BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </p>
<p>
<strong>16.</strong> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </p>

<h3><strong>END OF TERMS AND CONDITIONS</strong></h3>

</body>
</html>

Added modules/wysiwyg/popups/select_color.html.









































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<title>openWYSIWYG | Select Color</title>
</head>
<script language="JavaScript" type="text/javascript">

var qsParm = new Array();


/* ---------------------------------------------------------------------- *\
  Function    : retrieveWYSIWYG()
  Description : Retrieves the textarea ID for which the color will be inserted into.
\* ---------------------------------------------------------------------- */
function retreiveColor() {
  var query = window.location.search.substring(1);
  var parms = query.split('&');
  for (var i=0; i<parms.length; i++) {
    var pos = parms[i].indexOf('=');
    if (pos > 0) {
       var key = parms[i].substring(0,pos);
       var val = parms[i].substring(pos+1);
       qsParm[key] = val;
    }
  }
  document.getElementById('enterColor').value = "#" + (qsParm['color']);
}


/* ---------------------------------------------------------------------- *\
  Function    : selectColor()
  Description : Selects the color and inserts it into the WYSIWYG
\* ---------------------------------------------------------------------- */
function selectColor(color) {
	window.opener.document.getElementById('wysiwyg' + qsParm['wysiwyg']).contentWindow.document.execCommand(qsParm['command'], false, color);
  window.close();
}


/* ---------------------------------------------------------------------- *\
  Function    : previewColor()
  Description : Updates the preview pane as the user mouses over different colors
\* ---------------------------------------------------------------------- */
function previewColor(color) {
  document.getElementById('enterColor').value = color;
	document.getElementById('PreviewColor').style.backgroundColor = color;
}
</script>
<body bgcolor="#EEEEEE" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0" onLoad="retreiveColor();">
<center>
<table border="0" cellspacing="0" cellpadding="4" width="100%">
 <tr><form onSubmit="selectColor(document.getElementById('enterColor').value);">
  <td valign=center><div style="background-color: #000000; padding: 1; height: 21px; width: 50px"><div id="PreviewColor" style="height: 100%; width: 100%"></div></div></td>
  <td valign=center><input type="text" size="15" id="enterColor" name="enterColor" id="enterColor"></td>
  <td width="100%"></td>
 </tr></form>
</table>

<table border=0 cellspacing=1 cellpadding=0 bgcolor="#000000" style="cursor: hand;" >
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#003300" onMouseOver="previewColor('#003300')" onClick="selectColor('#003300')" height="10" width="10"></td>
  <td bgcolor="#006600" onMouseOver="previewColor('#006600')" onClick="selectColor('#006600')" height="10" width="10"></td>
  <td bgcolor="#009900" onMouseOver="previewColor('#009900')" onClick="selectColor('#009900')" height="10" width="10"></td>
  <td bgcolor="#00CC00" onMouseOver="previewColor('#00CC00')" onClick="selectColor('#00CC00')" height="10" width="10"></td>
  <td bgcolor="#00FF00" onMouseOver="previewColor('#00FF00')" onClick="selectColor('#00FF00')" height="10" width="10"></td>
  <td bgcolor="#330000" onMouseOver="previewColor('#330000')" onClick="selectColor('#330000')" height="10" width="10"></td>
  <td bgcolor="#333300" onMouseOver="previewColor('#333300')" onClick="selectColor('#333300')" height="10" width="10"></td>
  <td bgcolor="#336600" onMouseOver="previewColor('#336600')" onClick="selectColor('#336600')" height="10" width="10"></td>
  <td bgcolor="#339900" onMouseOver="previewColor('#339900')" onClick="selectColor('#339900')" height="10" width="10"></td>
  <td bgcolor="#33CC00" onMouseOver="previewColor('#33CC00')" onClick="selectColor('#33CC00')" height="10" width="10"></td>
  <td bgcolor="#33FF00" onMouseOver="previewColor('#33FF00')" onClick="selectColor('#33FF00')" height="10" width="10"></td>
  <td bgcolor="#660000" onMouseOver="previewColor('#660000')" onClick="selectColor('#660000')" height="10" width="10"></td>
  <td bgcolor="#663300" onMouseOver="previewColor('#663300')" onClick="selectColor('#663300')" height="10" width="10"></td>
  <td bgcolor="#666600" onMouseOver="previewColor('#666600')" onClick="selectColor('#666600')" height="10" width="10"></td>
  <td bgcolor="#669900" onMouseOver="previewColor('#669900')" onClick="selectColor('#669900')" height="10" width="10"></td>
  <td bgcolor="#66CC00" onMouseOver="previewColor('#66CC00')" onClick="selectColor('#66CC00')" height="10" width="10"></td>
  <td bgcolor="#66FF00" onMouseOver="previewColor('#66FF00')" onClick="selectColor('#66FF00')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#333333" onMouseOver="previewColor('#333333')" onClick="selectColor('#333333')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#000033" onMouseOver="previewColor('#000033')" onClick="selectColor('#000033')" height="10" width="10"></td>
  <td bgcolor="#003333" onMouseOver="previewColor('#003333')" onClick="selectColor('#003333')" height="10" width="10"></td>
  <td bgcolor="#006633" onMouseOver="previewColor('#006633')" onClick="selectColor('#006633')" height="10" width="10"></td>
  <td bgcolor="#009933" onMouseOver="previewColor('#009933')" onClick="selectColor('#009933')" height="10" width="10"></td>
  <td bgcolor="#00CC33" onMouseOver="previewColor('#00CC33')" onClick="selectColor('#00CC33')" height="10" width="10"></td>
  <td bgcolor="#00FF33" onMouseOver="previewColor('#00FF33')" onClick="selectColor('#00FF33')" height="10" width="10"></td>
  <td bgcolor="#330033" onMouseOver="previewColor('#330033')" onClick="selectColor('#330033')" height="10" width="10"></td>
  <td bgcolor="#333333" onMouseOver="previewColor('#333333')" onClick="selectColor('#333333')" height="10" width="10"></td>
  <td bgcolor="#336633" onMouseOver="previewColor('#336633')" onClick="selectColor('#336633')" height="10" width="10"></td>
  <td bgcolor="#339933" onMouseOver="previewColor('#339933')" onClick="selectColor('#339933')" height="10" width="10"></td>
  <td bgcolor="#33CC33" onMouseOver="previewColor('#33CC33')" onClick="selectColor('#33CC33')" height="10" width="10"></td>
  <td bgcolor="#33FF33" onMouseOver="previewColor('#33FF33')" onClick="selectColor('#33FF33')" height="10" width="10"></td>
  <td bgcolor="#660033" onMouseOver="previewColor('#660033')" onClick="selectColor('#660033')" height="10" width="10"></td>
  <td bgcolor="#663333" onMouseOver="previewColor('#663333')" onClick="selectColor('#663333')" height="10" width="10"></td>
  <td bgcolor="#666633" onMouseOver="previewColor('#666633')" onClick="selectColor('#666633')" height="10" width="10"></td>
  <td bgcolor="#669933" onMouseOver="previewColor('#669933')" onClick="selectColor('#669933')" height="10" width="10"></td>
  <td bgcolor="#66CC33" onMouseOver="previewColor('#66CC33')" onClick="selectColor('#66CC33')" height="10" width="10"></td>
  <td bgcolor="#66FF33" onMouseOver="previewColor('#66FF33')" onClick="selectColor('#66FF33')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#666666" onMouseOver="previewColor('#666666')" onClick="selectColor('#666666')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#000066" onMouseOver="previewColor('#000066')" onClick="selectColor('#000066')" height="10" width="10"></td>
  <td bgcolor="#003366" onMouseOver="previewColor('#003366')" onClick="selectColor('#003366')" height="10" width="10"></td>
  <td bgcolor="#006666" onMouseOver="previewColor('#006666')" onClick="selectColor('#006666')" height="10" width="10"></td>
  <td bgcolor="#009966" onMouseOver="previewColor('#009966')" onClick="selectColor('#009966')" height="10" width="10"></td>
  <td bgcolor="#00CC66" onMouseOver="previewColor('#00CC66')" onClick="selectColor('#00CC66')" height="10" width="10"></td>
  <td bgcolor="#00FF66" onMouseOver="previewColor('#00FF66')" onClick="selectColor('#00FF66')" height="10" width="10"></td>
  <td bgcolor="#330066" onMouseOver="previewColor('#330066')" onClick="selectColor('#330066')" height="10" width="10"></td>
  <td bgcolor="#333366" onMouseOver="previewColor('#333366')" onClick="selectColor('#333366')" height="10" width="10"></td>
  <td bgcolor="#336666" onMouseOver="previewColor('#336666')" onClick="selectColor('#336666')" height="10" width="10"></td>
  <td bgcolor="#339966" onMouseOver="previewColor('#339966')" onClick="selectColor('#339966')" height="10" width="10"></td>
  <td bgcolor="#33CC66" onMouseOver="previewColor('#33CC66')" onClick="selectColor('#33CC66')" height="10" width="10"></td>
  <td bgcolor="#33FF66" onMouseOver="previewColor('#33FF66')" onClick="selectColor('#33FF66')" height="10" width="10"></td>
  <td bgcolor="#660066" onMouseOver="previewColor('#660066')" onClick="selectColor('#660066')" height="10" width="10"></td>
  <td bgcolor="#663366" onMouseOver="previewColor('#663366')" onClick="selectColor('#663366')" height="10" width="10"></td>
  <td bgcolor="#666666" onMouseOver="previewColor('#666666')" onClick="selectColor('#666666')" height="10" width="10"></td>
  <td bgcolor="#669966" onMouseOver="previewColor('#669966')" onClick="selectColor('#669966')" height="10" width="10"></td>
  <td bgcolor="#66CC66" onMouseOver="previewColor('#66CC66')" onClick="selectColor('#66CC66')" height="10" width="10"></td>
  <td bgcolor="#66FF66" onMouseOver="previewColor('#66FF66')" onClick="selectColor('#66FF66')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#999999" onMouseOver="previewColor('#999999')" onClick="selectColor('#999999')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#000099" onMouseOver="previewColor('#000099')" onClick="selectColor('#000099')" height="10" width="10"></td>
  <td bgcolor="#003399" onMouseOver="previewColor('#003399')" onClick="selectColor('#003399')" height="10" width="10"></td>
  <td bgcolor="#006699" onMouseOver="previewColor('#006699')" onClick="selectColor('#006699')" height="10" width="10"></td>
  <td bgcolor="#009999" onMouseOver="previewColor('#009999')" onClick="selectColor('#009999')" height="10" width="10"></td>
  <td bgcolor="#00CC99" onMouseOver="previewColor('#00CC99')" onClick="selectColor('#00CC99')" height="10" width="10"></td>
  <td bgcolor="#00FF99" onMouseOver="previewColor('#00FF99')" onClick="selectColor('#00FF99')" height="10" width="10"></td>
  <td bgcolor="#330099" onMouseOver="previewColor('#330099')" onClick="selectColor('#330099')" height="10" width="10"></td>
  <td bgcolor="#333399" onMouseOver="previewColor('#333399')" onClick="selectColor('#333399')" height="10" width="10"></td>
  <td bgcolor="#336699" onMouseOver="previewColor('#336699')" onClick="selectColor('#336699')" height="10" width="10"></td>
  <td bgcolor="#339999" onMouseOver="previewColor('#339999')" onClick="selectColor('#339999')" height="10" width="10"></td>
  <td bgcolor="#33CC99" onMouseOver="previewColor('#33CC99')" onClick="selectColor('#33CC99')" height="10" width="10"></td>
  <td bgcolor="#33FF99" onMouseOver="previewColor('#33FF99')" onClick="selectColor('#33FF99')" height="10" width="10"></td>
  <td bgcolor="#660099" onMouseOver="previewColor('#660099')" onClick="selectColor('#660099')" height="10" width="10"></td>
  <td bgcolor="#663399" onMouseOver="previewColor('#663399')" onClick="selectColor('#663399')" height="10" width="10"></td>
  <td bgcolor="#666699" onMouseOver="previewColor('#666699')" onClick="selectColor('#666699')" height="10" width="10"></td>
  <td bgcolor="#669999" onMouseOver="previewColor('#669999')" onClick="selectColor('#669999')" height="10" width="10"></td>
  <td bgcolor="#66CC99" onMouseOver="previewColor('#66CC99')" onClick="selectColor('#66CC99')" height="10" width="10"></td>
  <td bgcolor="#66FF99" onMouseOver="previewColor('#66FF99')" onClick="selectColor('#66FF99')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#CCCCCC" onMouseOver="previewColor('#CCCCCC')" onClick="selectColor('#CCCCCC')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#0000CC" onMouseOver="previewColor('#0000CC')" onClick="selectColor('#0000CC')" height="10" width="10"></td>
  <td bgcolor="#0033CC" onMouseOver="previewColor('#0033CC')" onClick="selectColor('#0033CC')" height="10" width="10"></td>
  <td bgcolor="#0066CC" onMouseOver="previewColor('#0066CC')" onClick="selectColor('#0066CC')" height="10" width="10"></td>
  <td bgcolor="#0099CC" onMouseOver="previewColor('#0099CC')" onClick="selectColor('#0099CC')" height="10" width="10"></td>
  <td bgcolor="#00CCCC" onMouseOver="previewColor('#00CCCC')" onClick="selectColor('#00CCCC')" height="10" width="10"></td>
  <td bgcolor="#00FFCC" onMouseOver="previewColor('#00FFCC')" onClick="selectColor('#00FFCC')" height="10" width="10"></td>
  <td bgcolor="#3300CC" onMouseOver="previewColor('#3300CC')" onClick="selectColor('#3300CC')" height="10" width="10"></td>
  <td bgcolor="#3333CC" onMouseOver="previewColor('#3333CC')" onClick="selectColor('#3333CC')" height="10" width="10"></td>
  <td bgcolor="#3366CC" onMouseOver="previewColor('#3366CC')" onClick="selectColor('#3366CC')" height="10" width="10"></td>
  <td bgcolor="#3399CC" onMouseOver="previewColor('#3399CC')" onClick="selectColor('#3399CC')" height="10" width="10"></td>
  <td bgcolor="#33CCCC" onMouseOver="previewColor('#33CCCC')" onClick="selectColor('#33CCCC')" height="10" width="10"></td>
  <td bgcolor="#33FFCC" onMouseOver="previewColor('#33FFCC')" onClick="selectColor('#33FFCC')" height="10" width="10"></td>
  <td bgcolor="#6600CC" onMouseOver="previewColor('#6600CC')" onClick="selectColor('#6600CC')" height="10" width="10"></td>
  <td bgcolor="#6633CC" onMouseOver="previewColor('#6633CC')" onClick="selectColor('#6633CC')" height="10" width="10"></td>
  <td bgcolor="#6666CC" onMouseOver="previewColor('#6666CC')" onClick="selectColor('#6666CC')" height="10" width="10"></td>
  <td bgcolor="#6699CC" onMouseOver="previewColor('#6699CC')" onClick="selectColor('#6699CC')" height="10" width="10"></td>
  <td bgcolor="#66CCCC" onMouseOver="previewColor('#66CCCC')" onClick="selectColor('#66CCCC')" height="10" width="10"></td>
  <td bgcolor="#66FFCC" onMouseOver="previewColor('#66FFCC')" onClick="selectColor('#66FFCC')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#FFFFFF" onMouseOver="previewColor('#FFFFFF')" onClick="selectColor('#FFFFFF')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#0000FF" onMouseOver="previewColor('#0000FF')" onClick="selectColor('#0000FF')" height="10" width="10"></td>
  <td bgcolor="#0033FF" onMouseOver="previewColor('#0033FF')" onClick="selectColor('#0033FF')" height="10" width="10"></td>
  <td bgcolor="#0066FF" onMouseOver="previewColor('#0066FF')" onClick="selectColor('#0066FF')" height="10" width="10"></td>
  <td bgcolor="#0099FF" onMouseOver="previewColor('#0099FF')" onClick="selectColor('#0099FF')" height="10" width="10"></td>
  <td bgcolor="#00CCFF" onMouseOver="previewColor('#00CCFF')" onClick="selectColor('#00CCFF')" height="10" width="10"></td>
  <td bgcolor="#00FFFF" onMouseOver="previewColor('#00FFFF')" onClick="selectColor('#00FFFF')" height="10" width="10"></td>
  <td bgcolor="#3300FF" onMouseOver="previewColor('#3300FF')" onClick="selectColor('#3300FF')" height="10" width="10"></td>
  <td bgcolor="#3333FF" onMouseOver="previewColor('#3333FF')" onClick="selectColor('#3333FF')" height="10" width="10"></td>
  <td bgcolor="#3366FF" onMouseOver="previewColor('#3366FF')" onClick="selectColor('#3366FF')" height="10" width="10"></td>
  <td bgcolor="#3399FF" onMouseOver="previewColor('#3399FF')" onClick="selectColor('#3399FF')" height="10" width="10"></td>
  <td bgcolor="#33CCFF" onMouseOver="previewColor('#33CCFF')" onClick="selectColor('#33CCFF')" height="10" width="10"></td>
  <td bgcolor="#33FFFF" onMouseOver="previewColor('#33FFFF')" onClick="selectColor('#33FFFF')" height="10" width="10"></td>
  <td bgcolor="#6600FF" onMouseOver="previewColor('#6600FF')" onClick="selectColor('#6600FF')" height="10" width="10"></td>
  <td bgcolor="#6633FF" onMouseOver="previewColor('#6633FF')" onClick="selectColor('#6633FF')" height="10" width="10"></td>
  <td bgcolor="#6666FF" onMouseOver="previewColor('#6666FF')" onClick="selectColor('#6666FF')" height="10" width="10"></td>
  <td bgcolor="#6699FF" onMouseOver="previewColor('#6699FF')" onClick="selectColor('#6699FF')" height="10" width="10"></td>
  <td bgcolor="#66CCFF" onMouseOver="previewColor('#66CCFF')" onClick="selectColor('#66CCFF')" height="10" width="10"></td>
  <td bgcolor="#66FFFF" onMouseOver="previewColor('#66FFFF')" onClick="selectColor('#66FFFF')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#FF0000" onMouseOver="previewColor('#FF0000')" onClick="selectColor('#FF0000')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#990000" onMouseOver="previewColor('#990000')" onClick="selectColor('#990000')" height="10" width="10"></td>
  <td bgcolor="#993300" onMouseOver="previewColor('#993300')" onClick="selectColor('#993300')" height="10" width="10"></td>
  <td bgcolor="#996600" onMouseOver="previewColor('#996600')" onClick="selectColor('#996600')" height="10" width="10"></td>
  <td bgcolor="#999900" onMouseOver="previewColor('#999900')" onClick="selectColor('#999900')" height="10" width="10"></td>
  <td bgcolor="#99CC00" onMouseOver="previewColor('#99CC00')" onClick="selectColor('#99CC00')" height="10" width="10"></td>
  <td bgcolor="#99FF00" onMouseOver="previewColor('#99FF00')" onClick="selectColor('#99FF00')" height="10" width="10"></td>
  <td bgcolor="#CC0000" onMouseOver="previewColor('#CC0000')" onClick="selectColor('#CC0000')" height="10" width="10"></td>
  <td bgcolor="#CC3300" onMouseOver="previewColor('#CC3300')" onClick="selectColor('#CC3300')" height="10" width="10"></td>
  <td bgcolor="#CC6600" onMouseOver="previewColor('#CC6600')" onClick="selectColor('#CC6600')" height="10" width="10"></td>
  <td bgcolor="#CC9900" onMouseOver="previewColor('#CC9900')" onClick="selectColor('#CC9900')" height="10" width="10"></td>
  <td bgcolor="#CCCC00" onMouseOver="previewColor('#CCCC00')" onClick="selectColor('#CCCC00')" height="10" width="10"></td>
  <td bgcolor="#CCFF00" onMouseOver="previewColor('#CCFF00')" onClick="selectColor('#CCFF00')" height="10" width="10"></td>
  <td bgcolor="#FF0000" onMouseOver="previewColor('#FF0000')" onClick="selectColor('#FF0000')" height="10" width="10"></td>
  <td bgcolor="#FF3300" onMouseOver="previewColor('#FF3300')" onClick="selectColor('#FF3300')" height="10" width="10"></td>
  <td bgcolor="#FF6600" onMouseOver="previewColor('#FF6600')" onClick="selectColor('#FF6600')" height="10" width="10"></td>
  <td bgcolor="#FF9900" onMouseOver="previewColor('#FF9900')" onClick="selectColor('#FF9900')" height="10" width="10"></td>
  <td bgcolor="#FFCC00" onMouseOver="previewColor('#FFCC00')" onClick="selectColor('#FFCC00')" height="10" width="10"></td>
  <td bgcolor="#FFFF00" onMouseOver="previewColor('#FFFF00')" onClick="selectColor('#FFFF00')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#00FF00" onMouseOver="previewColor('#00FF00')" onClick="selectColor('#00FF00')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#990033" onMouseOver="previewColor('#990033')" onClick="selectColor('#990033')" height="10" width="10"></td>
  <td bgcolor="#993333" onMouseOver="previewColor('#993333')" onClick="selectColor('#993333')" height="10" width="10"></td>
  <td bgcolor="#996633" onMouseOver="previewColor('#996633')" onClick="selectColor('#996633')" height="10" width="10"></td>
  <td bgcolor="#999933" onMouseOver="previewColor('#999933')" onClick="selectColor('#999933')" height="10" width="10"></td>
  <td bgcolor="#99CC33" onMouseOver="previewColor('#99CC33')" onClick="selectColor('#99CC33')" height="10" width="10"></td>
  <td bgcolor="#99FF33" onMouseOver="previewColor('#99FF33')" onClick="selectColor('#99FF33')" height="10" width="10"></td>
  <td bgcolor="#CC0033" onMouseOver="previewColor('#CC0033')" onClick="selectColor('#CC0033')" height="10" width="10"></td>
  <td bgcolor="#CC3333" onMouseOver="previewColor('#CC3333')" onClick="selectColor('#CC3333')" height="10" width="10"></td>
  <td bgcolor="#CC6633" onMouseOver="previewColor('#CC6633')" onClick="selectColor('#CC6633')" height="10" width="10"></td>
  <td bgcolor="#CC9933" onMouseOver="previewColor('#CC9933')" onClick="selectColor('#CC9933')" height="10" width="10"></td>
  <td bgcolor="#CCCC33" onMouseOver="previewColor('#CCCC33')" onClick="selectColor('#CCCC33')" height="10" width="10"></td>
  <td bgcolor="#CCFF33" onMouseOver="previewColor('#CCFF33')" onClick="selectColor('#CCFF33')" height="10" width="10"></td>
  <td bgcolor="#FF0033" onMouseOver="previewColor('#FF0033')" onClick="selectColor('#FF0033')" height="10" width="10"></td>
  <td bgcolor="#FF3333" onMouseOver="previewColor('#FF3333')" onClick="selectColor('#FF3333')" height="10" width="10"></td>
  <td bgcolor="#FF6633" onMouseOver="previewColor('#FF6633')" onClick="selectColor('#FF6633')" height="10" width="10"></td>
  <td bgcolor="#FF9933" onMouseOver="previewColor('#FF9933')" onClick="selectColor('#FF9933')" height="10" width="10"></td>
  <td bgcolor="#FFCC33" onMouseOver="previewColor('#FFCC33')" onClick="selectColor('#FFCC33')" height="10" width="10"></td>
  <td bgcolor="#FFFF33" onMouseOver="previewColor('#FFFF33')" onClick="selectColor('#FFFF33')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#0000FF" onMouseOver="previewColor('#0000FF')" onClick="selectColor('#0000FF')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#990066" onMouseOver="previewColor('#990066')" onClick="selectColor('#990066')" height="10" width="10"></td>
  <td bgcolor="#993366" onMouseOver="previewColor('#993366')" onClick="selectColor('#993366')" height="10" width="10"></td>
  <td bgcolor="#996666" onMouseOver="previewColor('#996666')" onClick="selectColor('#996666')" height="10" width="10"></td>
  <td bgcolor="#999966" onMouseOver="previewColor('#999966')" onClick="selectColor('#999966')" height="10" width="10"></td>
  <td bgcolor="#99CC66" onMouseOver="previewColor('#99CC66')" onClick="selectColor('#99CC66')" height="10" width="10"></td>
  <td bgcolor="#99FF66" onMouseOver="previewColor('#99FF66')" onClick="selectColor('#99FF66')" height="10" width="10"></td>
  <td bgcolor="#CC0066" onMouseOver="previewColor('#CC0066')" onClick="selectColor('#CC0066')" height="10" width="10"></td>
  <td bgcolor="#CC3366" onMouseOver="previewColor('#CC3366')" onClick="selectColor('#CC3366')" height="10" width="10"></td>
  <td bgcolor="#CC6666" onMouseOver="previewColor('#CC6666')" onClick="selectColor('#CC6666')" height="10" width="10"></td>
  <td bgcolor="#CC9966" onMouseOver="previewColor('#CC9966')" onClick="selectColor('#CC9966')" height="10" width="10"></td>
  <td bgcolor="#CCCC66" onMouseOver="previewColor('#CCCC66')" onClick="selectColor('#CCCC66')" height="10" width="10"></td>
  <td bgcolor="#CCFF66" onMouseOver="previewColor('#CCFF66')" onClick="selectColor('#CCFF66')" height="10" width="10"></td>
  <td bgcolor="#FF0066" onMouseOver="previewColor('#FF0066')" onClick="selectColor('#FF0066')" height="10" width="10"></td>
  <td bgcolor="#FF3366" onMouseOver="previewColor('#FF3366')" onClick="selectColor('#FF3366')" height="10" width="10"></td>
  <td bgcolor="#FF6666" onMouseOver="previewColor('#FF6666')" onClick="selectColor('#FF6666')" height="10" width="10"></td>
  <td bgcolor="#FF9966" onMouseOver="previewColor('#FF9966')" onClick="selectColor('#FF9966')" height="10" width="10"></td>
  <td bgcolor="#FFCC66" onMouseOver="previewColor('#FFCC66')" onClick="selectColor('#FFCC66')" height="10" width="10"></td>
  <td bgcolor="#FFFF66" onMouseOver="previewColor('#FFFF66')" onClick="selectColor('#FFFF66')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#FFFF00" onMouseOver="previewColor('#FFFF00')" onClick="selectColor('#FFFF00')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#990099" onMouseOver="previewColor('#990099')" onClick="selectColor('#990099')" height="10" width="10"></td>
  <td bgcolor="#993399" onMouseOver="previewColor('#993399')" onClick="selectColor('#993399')" height="10" width="10"></td>
  <td bgcolor="#996699" onMouseOver="previewColor('#996699')" onClick="selectColor('#996699')" height="10" width="10"></td>
  <td bgcolor="#999999" onMouseOver="previewColor('#999999')" onClick="selectColor('#999999')" height="10" width="10"></td>
  <td bgcolor="#99CC99" onMouseOver="previewColor('#99CC99')" onClick="selectColor('#99CC99')" height="10" width="10"></td>
  <td bgcolor="#99FF99" onMouseOver="previewColor('#99FF99')" onClick="selectColor('#99FF99')" height="10" width="10"></td>
  <td bgcolor="#CC0099" onMouseOver="previewColor('#CC0099')" onClick="selectColor('#CC0099')" height="10" width="10"></td>
  <td bgcolor="#CC3399" onMouseOver="previewColor('#CC3399')" onClick="selectColor('#CC3399')" height="10" width="10"></td>
  <td bgcolor="#CC6699" onMouseOver="previewColor('#CC6699')" onClick="selectColor('#CC6699')" height="10" width="10"></td>
  <td bgcolor="#CC9999" onMouseOver="previewColor('#CC9999')" onClick="selectColor('#CC9999')" height="10" width="10"></td>
  <td bgcolor="#CCCC99" onMouseOver="previewColor('#CCCC99')" onClick="selectColor('#CCCC99')" height="10" width="10"></td>
  <td bgcolor="#CCFF99" onMouseOver="previewColor('#CCFF99')" onClick="selectColor('#CCFF99')" height="10" width="10"></td>
  <td bgcolor="#FF0099" onMouseOver="previewColor('#FF0099')" onClick="selectColor('#FF0099')" height="10" width="10"></td>
  <td bgcolor="#FF3399" onMouseOver="previewColor('#FF3399')" onClick="selectColor('#FF3399')" height="10" width="10"></td>
  <td bgcolor="#FF6699" onMouseOver="previewColor('#FF6699')" onClick="selectColor('#FF6699')" height="10" width="10"></td>
  <td bgcolor="#FF9999" onMouseOver="previewColor('#FF9999')" onClick="selectColor('#FF9999')" height="10" width="10"></td>
  <td bgcolor="#FFCC99" onMouseOver="previewColor('#FFCC99')" onClick="selectColor('#FFCC99')" height="10" width="10"></td>
  <td bgcolor="#FFFF99" onMouseOver="previewColor('#FFFF99')" onClick="selectColor('#FFFF99')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#00FFFF" onMouseOver="previewColor('#00FFFF')" onClick="selectColor('#00FFFF')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#9900CC" onMouseOver="previewColor('#9900CC')" onClick="selectColor('#9900CC')" height="10" width="10"></td>
  <td bgcolor="#9933CC" onMouseOver="previewColor('#9933CC')" onClick="selectColor('#9933CC')" height="10" width="10"></td>
  <td bgcolor="#9966CC" onMouseOver="previewColor('#9966CC')" onClick="selectColor('#9966CC')" height="10" width="10"></td>
  <td bgcolor="#9999CC" onMouseOver="previewColor('#9999CC')" onClick="selectColor('#9999CC')" height="10" width="10"></td>
  <td bgcolor="#99CCCC" onMouseOver="previewColor('#99CCCC')" onClick="selectColor('#99CCCC')" height="10" width="10"></td>
  <td bgcolor="#99FFCC" onMouseOver="previewColor('#99FFCC')" onClick="selectColor('#99FFCC')" height="10" width="10"></td>
  <td bgcolor="#CC00CC" onMouseOver="previewColor('#CC00CC')" onClick="selectColor('#CC00CC')" height="10" width="10"></td>
  <td bgcolor="#CC33CC" onMouseOver="previewColor('#CC33CC')" onClick="selectColor('#CC33CC')" height="10" width="10"></td>
  <td bgcolor="#CC66CC" onMouseOver="previewColor('#CC66CC')" onClick="selectColor('#CC66CC')" height="10" width="10"></td>
  <td bgcolor="#CC99CC" onMouseOver="previewColor('#CC99CC')" onClick="selectColor('#CC99CC')" height="10" width="10"></td>
  <td bgcolor="#CCCCCC" onMouseOver="previewColor('#CCCCCC')" onClick="selectColor('#CCCCCC')" height="10" width="10"></td>
  <td bgcolor="#CCFFCC" onMouseOver="previewColor('#CCFFCC')" onClick="selectColor('#CCFFCC')" height="10" width="10"></td>
  <td bgcolor="#FF00CC" onMouseOver="previewColor('#FF00CC')" onClick="selectColor('#FF00CC')" height="10" width="10"></td>
  <td bgcolor="#FF33CC" onMouseOver="previewColor('#FF33CC')" onClick="selectColor('#FF33CC')" height="10" width="10"></td>
  <td bgcolor="#FF66CC" onMouseOver="previewColor('#FF66CC')" onClick="selectColor('#FF66CC')" height="10" width="10"></td>
  <td bgcolor="#FF99CC" onMouseOver="previewColor('#FF99CC')" onClick="selectColor('#FF99CC')" height="10" width="10"></td>
  <td bgcolor="#FFCCCC" onMouseOver="previewColor('#FFCCCC')" onClick="selectColor('#FFCCCC')" height="10" width="10"></td>
  <td bgcolor="#FFFFCC" onMouseOver="previewColor('#FFFFCC')" onClick="selectColor('#FFFFCC')" height="10" width="10"></td>
 </tr>
 <tr>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#FF00FF" onMouseOver="previewColor('#FF00FF')" onClick="selectColor('#FF00FF')" height="10" width="10"></td>
  <td bgcolor="#000000" onMouseOver="previewColor('#000000')" onClick="selectColor('#000000')" height="10" width="10"></td>
  <td bgcolor="#9900FF" onMouseOver="previewColor('#9900FF')" onClick="selectColor('#9900FF')" height="10" width="10"></td>
  <td bgcolor="#9933FF" onMouseOver="previewColor('#9933FF')" onClick="selectColor('#9933FF')" height="10" width="10"></td>
  <td bgcolor="#9966FF" onMouseOver="previewColor('#9966FF')" onClick="selectColor('#9966FF')" height="10" width="10"></td>
  <td bgcolor="#9999FF" onMouseOver="previewColor('#9999FF')" onClick="selectColor('#9999FF')" height="10" width="10"></td>
  <td bgcolor="#99CCFF" onMouseOver="previewColor('#99CCFF')" onClick="selectColor('#99CCFF')" height="10" width="10"></td>
  <td bgcolor="#99FFFF" onMouseOver="previewColor('#99FFFF')" onClick="selectColor('#99FFFF')" height="10" width="10"></td>
  <td bgcolor="#CC00FF" onMouseOver="previewColor('#CC00FF')" onClick="selectColor('#CC00FF')" height="10" width="10"></td>
  <td bgcolor="#CC33FF" onMouseOver="previewColor('#CC33FF')" onClick="selectColor('#CC33FF')" height="10" width="10"></td>
  <td bgcolor="#CC66FF" onMouseOver="previewColor('#CC66FF')" onClick="selectColor('#CC66FF')" height="10" width="10"></td>
  <td bgcolor="#CC99FF" onMouseOver="previewColor('#CC99FF')" onClick="selectColor('#CC99FF')" height="10" width="10"></td>
  <td bgcolor="#CCCCFF" onMouseOver="previewColor('#CCCCFF')" onClick="selectColor('#CCCCFF')" height="10" width="10"></td>
  <td bgcolor="#CCFFFF" onMouseOver="previewColor('#CCFFFF')" onClick="selectColor('#CCFFFF')" height="10" width="10"></td>
  <td bgcolor="#FF00FF" onMouseOver="previewColor('#FF00FF')" onClick="selectColor('#FF00FF')" height="10" width="10"></td>
  <td bgcolor="#FF33FF" onMouseOver="previewColor('#FF33FF')" onClick="selectColor('#FF33FF')" height="10" width="10"></td>
  <td bgcolor="#FF66FF" onMouseOver="previewColor('#FF66FF')" onClick="selectColor('#FF66FF')" height="10" width="10"></td>
  <td bgcolor="#FF99FF" onMouseOver="previewColor('#FF99FF')" onClick="selectColor('#FF99FF')" height="10" width="10"></td>
  <td bgcolor="#FFCCFF" onMouseOver="previewColor('#FFCCFF')" onClick="selectColor('#FFCCFF')" height="10" width="10"></td>
  <td bgcolor="#FFFFFF" onMouseOver="previewColor('#FFFFFF')" onClick="selectColor('#FFFFFF')" height="10" width="10"></td>
 </tr>
</table>
</center>
</body>
</html>

Added modules/wysiwyg/wysiwyg.tcl.































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
###
# Add hooks for openWYSIWYG
###

package require httpd::doc	;# Httpd_Redirect Httpd_ReturnData

set PWD [file dirname [file normalize [info script]]]

Doc_AddRoot /wysiwyg/buttons $PWD/buttons
Doc_AddRoot /wysiwyg/css $PWD/css
Doc_AddRoot /wysiwyg/icons $PWD/icons
Doc_AddRoot /wysiwyg/js $PWD/js
Doc_AddRoot /wysiwyg/popups $PWD/popups

package provide httpd::wysiwyg 0.1

Changes to sampleapp/snmp/snmp.tcl.

425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
	append result "<tr><td colspan=5><input type=submit value=\"$submit\">"
	append result "</tr>\n"
	append result </form>\n
    }
    append result </table>\n
}

# Get an item as a form element

proc Snmp_setMib {session mib} {
    upvar #0 Session:$session state

    foreach {num type value}  [lindex [$state(snmp) get $mib] 0] {}
    set names [lindex [mib tc $mib] 3]
    if {[llength $names] >1} {
    	append result "<select name=\"[mib name $mib]\">\n"
    	foreach name $names {
	    lassign-brent {choice index} $name
	    set s [expr {("$value" == "$choice") ? "SELECTED" : ""}]
	    append result "  <option value=$index$s>$choice\n"
	}
	append result "</select>"
    } else {
    	append result "<input name=\"[mib name $mib]\" value=\"$value\">"
    }







<
<








|







425
426
427
428
429
430
431


432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
	append result "<tr><td colspan=5><input type=submit value=\"$submit\">"
	append result "</tr>\n"
	append result </form>\n
    }
    append result </table>\n
}



proc Snmp_setMib {session mib} {
    upvar #0 Session:$session state

    foreach {num type value}  [lindex [$state(snmp) get $mib] 0] {}
    set names [lindex [mib tc $mib] 3]
    if {[llength $names] >1} {
    	append result "<select name=\"[mib name $mib]\">\n"
    	foreach name $names {
	    lassign $name choice index
	    set s [expr {("$value" == "$choice") ? "SELECTED" : ""}]
	    append result "  <option value=$index$s>$choice\n"
	}
	append result "</select>"
    } else {
    	append result "<input name=\"[mib name $mib]\" value=\"$value\">"
    }

Changes to sampleapp/sunscript/htmlutils.tcl.

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

proc Body {args} {
    global page
    set html ""
    if {[info exists page(head)]} {
	append html "[CloseTag]\n" ;# Should be HEAD
    }
    append html [eval {OpenTag body} $args]\n
    return $html
}


# End
# Close out all the open tags.  Especially useful for
# Tables that do not display at all if they are unclosed.







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

proc Body {args} {
    global page
    set html ""
    if {[info exists page(head)]} {
	append html "[CloseTag]\n" ;# Should be HEAD
    }
    append html [OpenTag body {*}$args]\n
    return $html
}


# End
# Close out all the open tags.  Especially useful for
# Tables that do not display at all if they are unclosed.

Deleted tclhttpd.spec.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
%define contentdir /usr/tclhttpd
Summary: Extensible Web+Application server written in Tcl.
Name: tclhttpd
Version: 3.5.1
Release: 0.fdr.5
Epoch: 0
License: BSD
Group: System Environment/Daemons
URL:            http://tclhttpd.sourceforge.net/
Source0:        http://prdownloads.sourceforge.net/tclhttpd/tclhttpd3.5.1.tar.gz
Patch0:		tclhttpd_fedora.1.patch
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: tcl tcllib expect
BuildRequires:  tcl-devel 
Prereq: /sbin/chkconfig, /usr/sbin/useradd

%description
TclHttpd is a Web server implemented in pure Tcl. It works out of the box as a
Web server, but is really designed to be a Tcl application server. It supports
HTML+Tcl templates, and is extensible in a variety of ways.

%prep
%setup -q -n %{name}%{version}
%patch -p1

%build

%configure --with-serverroot=%{contentdir}
make %{?_smp_mflags}

%install
make install DESTDIR=$RPM_BUILD_ROOT
install -p -D bin/redhat.init.tclhttpd $RPM_BUILD_ROOT/%{_sysconfdir}/init.d/tclhttpd
mkdir -p $RPM_BUILD_ROOT/var/run/tclhttpd

# Replace the numeric id in this configuration file with a name.  We don't
# know what numeric id it will end up with when it's created during
# the rpm installation.
sed -e 's/Config uid.*/Config uid tclhttpd/' -e 's/Config gid.*/Config gid tclhttpd/' < bin/tclhttpd.rc > $RPM_BUILD_ROOT/%{_prefix}/bin/tclhttpd.rc
# This cgi is precompiled and has some old libc dependencies.  I'm removing
# it until I find out what it's used for.
rm $RPM_BUILD_ROOT/%{contentdir}/htdocs/cgi-bin/env
ln -s ./httpd.tcl $RPM_BUILD_ROOT/%{_prefix}/bin/tclhttpd

%pre
# Add the "tclhttpd" user
%_sbindir/useradd -c "Tclhttpd" -s /sbin/nologin -r -d %{contentdir} tclhttpd 2> /dev/null || :

%post
if [ $1 -eq 1 ]; then
    /sbin/chkconfig --add tclhttpd
# No need to run ldconfig because the shared objects are only
# loaded by Tcl's package system, which doesn't require
# anything in the ld cache.
#    /sbin/ldconfig
fi

%preun
if [ $1 = 0 ]; then
    /sbin/service tclhttpd stop > /dev/null 2>&1
    /sbin/chkconfig --del tclhttpd
    rm -f /var/run/tclhttpd/tclhttpd.pid
fi

%postun
# No need to run ldconfig because the shared objects are only
# loaded by Tcl's package system, which doesn't require
# anything in the ld cache.
#    /sbin/ldconfig
# Clean up a turd that is often left behind

if [ $1 = 0 ]; then                                               # uninstalling
    %_sbindir/userdel tclhttpd
fi
rm -f /tmp/tclhttpd.default

%clean
rm -rf $RPM_BUILD_ROOT

%files
%defattr(-,tclhttpd,tclhttpd)
%{_libdir}/*.so
%{_libdir}/crypt1.0
%{_libdir}/limit1.0
%{_libdir}/%{name}%{version}
%{_bindir}/*
%{_mandir}/man1/*
%{contentdir}
/var/run/tclhttpd
%{_sysconfdir}/init.d/tclhttpd

%changelog
* Sun Oct 24 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.4
- Change package group in the specfile.  Add tcllib to dependency list.
  Remove tclhttpd user during uninstall.
* Wed Oct 6 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.3
- Fix bug in the /etc/init.d/tclhttpd startup script that was causing
  it to kill a random tclsh process during shutdown, and misreporting
  the status of tclhttpd.
* Tue Sep 21 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.2
- remove hardcoded path in the %build section of the rpm spec file.
* Sun Sep 12 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.1
- Initial rpm with a Fedora-compatible spec file.  Included patch
  for better /etc/init.d script behaviour.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































Added tclhttpd.spec.in.





















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
%define contentdir /usr/tclhttpd
Summary: Extensible Web+Application server written in Tcl.
Name: tclhttpd
Version: @PKG_MAJOR_VERSION@.@PKG_MINOR_VERSION@@PKG_PATCHLEVEL@
Release: @PKG_FEDORA_RELEASE@
Epoch: 0
License: BSD
Group: System Environment/Daemons
URL:            http://core.tcl.tk/tclhttpd
Source0:        http://fossil.etoyoc.com/fossil/tclhttpd/tarball/tclhttpd-4.0.0.tar.gz?uuid=4_0
Patch0:		tclhttpd_fedora.1.patch
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: tcl tcllib expect
BuildRequires:  tcl-devel 
Prereq: /sbin/chkconfig, /usr/sbin/useradd

%description
TclHttpd is a Web server implemented in pure Tcl. It works out of the box as a
Web server, but is really designed to be a Tcl application server. It supports
HTML+Tcl templates, and is extensible in a variety of ways.

%prep
%setup -q -n %{name}%{version}
%patch -p1

%build

%configure --with-serverroot=%{contentdir}
make %{?_smp_mflags}

%install
make install DESTDIR=$RPM_BUILD_ROOT
install -p -D bin/redhat.init.tclhttpd $RPM_BUILD_ROOT/%{_sysconfdir}/init.d/tclhttpd
mkdir -p $RPM_BUILD_ROOT/var/run/tclhttpd

# Replace the numeric id in this configuration file with a name.  We don't
# know what numeric id it will end up with when it's created during
# the rpm installation.
sed -e 's/Config uid.*/Config uid tclhttpd/' -e 's/Config gid.*/Config gid tclhttpd/' < bin/tclhttpd.rc > $RPM_BUILD_ROOT/%{_prefix}/bin/tclhttpd.rc
# This cgi is precompiled and has some old libc dependencies.  I'm removing
# it until I find out what it's used for.
rm $RPM_BUILD_ROOT/%{contentdir}/htdocs/cgi-bin/env
ln -s ./httpd.tcl $RPM_BUILD_ROOT/%{_prefix}/bin/tclhttpd

%pre
# Add the "tclhttpd" user
%_sbindir/useradd -c "Tclhttpd" -s /sbin/nologin -r -d %{contentdir} tclhttpd 2> /dev/null || :

%post
if [ $1 -eq 1 ]; then
    /sbin/chkconfig --add tclhttpd
# No need to run ldconfig because the shared objects are only
# loaded by Tcl's package system, which doesn't require
# anything in the ld cache.
#    /sbin/ldconfig
fi

%preun
if [ $1 = 0 ]; then
    /sbin/service tclhttpd stop > /dev/null 2>&1
    /sbin/chkconfig --del tclhttpd
    rm -f /var/run/tclhttpd/tclhttpd.pid
fi

%postun
# No need to run ldconfig because the shared objects are only
# loaded by Tcl's package system, which doesn't require
# anything in the ld cache.
#    /sbin/ldconfig
# Clean up a turd that is often left behind

if [ $1 = 0 ]; then                                               # uninstalling
    %_sbindir/userdel tclhttpd
fi
rm -f /tmp/tclhttpd.default

%clean
rm -rf $RPM_BUILD_ROOT

%files
%defattr(-,tclhttpd,tclhttpd)
%{_libdir}/*.so
%{_libdir}/crypt1.0
%{_libdir}/limit1.0
%{_libdir}/%{name}%{version}
%{_bindir}/*
%{_mandir}/man1/*
%{contentdir}
/var/run/tclhttpd
%{_sysconfdir}/init.d/tclhttpd

%changelog
* Sat May 28 2015 <yoda at etoyoc.com> - 0:4.0.0.fdr.1
- Utilizes Tcl8.6.
* Sun Oct 24 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.4
- Change package group in the specfile.  Add tcllib to dependency list.
  Remove tclhttpd user during uninstall.
* Wed Oct 6 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.3
- Fix bug in the /etc/init.d/tclhttpd startup script that was causing
  it to kill a random tclsh process during shutdown, and misreporting
  the status of tclhttpd.
* Tue Sep 21 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.2
- remove hardcoded path in the %build section of the rpm spec file.
* Sun Sep 12 2004 <wart at kobold.org> - 0:3.5.1-0.fdr.1
- Initial rpm with a Fedora-compatible spec file.  Included patch
  for better /etc/init.d script behaviour.