Megatest

Changes On Branch 2b412d7468ea58a3
Login

Changes In Branch v1.66 Excluding Merge-Ins

This is equivalent to a diff from f6dc7607a8 to 2b412d7468

2020-07-28
22:41
Pulled in v1.66 check-in: 2b506bbc72 user: matt tags: v1.66-captain-ulex
22:23
Merged v1.65 Leaf check-in: 2b412d7468 user: matt tags: v1.66
15:51
Do not exit on issues creating link tree. Continue on. If the links were not properly removed let's fix the removal process rather than bandaid here. check-in: e49d32d625 user: mrwellan tags: v1.65, v1.6557
2020-07-26
14:11
Merged in latest from v1.65 check-in: 7e9e931afb user: matt tags: v1.66
2020-05-19
09:09
Fixed dashboard crash due to runs2 tab check-in: e5c65818cc user: mrwellan tags: v1.66, v1.6602
2020-05-18
11:56
Fixed runs2 tab Leaf check-in: f6dc7607a8 user: mrwellan tags: v1.65-broken
2020-05-10
04:26
Make trim-trailing-spaces the default, updated manual, bumped version to v1.6548 check-in: 3bd95bc26b user: matt tags: v1.65-broken

Modified Makefile from [67a4a89dd1] to [0948aa4fa3].

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43







-
+







           sdb.scm rmt.scm api.scm subrun.scm portlogger.scm		\
           archive.scm env.scm diff-report.scm				\
           cgisetup/models/pgdb.scm

# module source files
# ftail.scm rmtmod.scm commonmod.scm removed
MSRCFILES = ducttape-lib.scm pkts.scm stml2.scm cookie.scm mutils.scm	\
            mtargs.scm commonmod.scm dbmod.scm
            mtargs.scm commonmod.scm dbmod.scm adjutant.scm

GUISRCF = dashboard-context-menu.scm dashboard-tests.scm		\
          dashboard-guimonitor.scm gutils.scm dcommon.scm tree.scm	\
          vg.scm

OFILES   = $(SRCFILES:%.scm=%.o)
GOFILES  = $(GUISRCF:%.scm=%.o)
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
59
60
61
62
63
64
65


66




67
68
69
70
71



72
73
74
75
76
77
78







-
-

-
-
-
-





-
-
-







DEPLOYHELPERS=$(addprefix deploytarg/,$(ADTLSCR))
MTESTHASH=$(shell fossil info|grep checkout:| awk '{print $$2}')

ifeq ($(MTESTHASH),)
$(error MTESTHASH is broken!)
endif

CSIPATH=$(shell which csi)
CKPATH=$(shell dirname $(shell dirname $(CSIPATH)))
ARCHSTR=$(shell if [[ -e /usr/bin/sw_vers ]]; then /usr/bin/sw_vers -productVersion; else lsb_release -sr; fi)
# ARCHSTR=$(shell bash -c "echo \$$MACHTYPE")

# if have csi on path use that, else use default
CHICKEN_PREFIX=$(or $(CKPATH),$(PREFIX)/$(ARCHSTR))

PNGFILES = $(shell cd docs/manual;ls *png)

all : $(PREFIX)/bin/.$(ARCHSTR) mtest dboard mtut tcmt

whatever :
	@echo "CHICKEN_PREFIX=$(CHICKEN_PREFIX)"

mtest: $(OFILES) readline-fix.scm megatest.o $(MOFILES) $(MOIMPFILES)
	csc $(CSCOPTS) $(OFILES) $(MOFILES) $(MOIMPFILES) megatest.o -o mtest

showmtesthash:
	@echo $(MTESTHASH)

dboard : $(OFILES) $(GOFILES) dashboard.scm $(MOFILES) $(MOIMPFILES)
120
121
122
123
124
125
126
127


128
129
130
131
132
133
134
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
126







-
+
+







        rpc-transport.o \
	runconfig.o \
	runs.o \
	server.o \
	tasks.o \
	tdb.o \
	tests.o \
	subrun.o
	subrun.o \
        ezsteps.o

#        mofiles/commonmod.o \

tcmt : $(TCMTOBJS) tcmt.scm
	csc $(CSCOPTS) $(TCMTOBJS) $(MOFILES) $(MOIMPFILES) tcmt.scm -o tcmt

# install documentation to $(PREFIX)/docs
176
177
178
179
180
181
182

183
184
185
186
187
188
189
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182







+








dcommon.o : run_records.scm

mofiles/stml2.o : mofiles/cookie.o

# special include based modules
mofiles/pkts.o      : pkts/pkts.scm
mofiles/stml2.o     : cookie.o
# mofiles/mtargs.o    : mtargs/mtargs.scm
# mofiles/mtconfigf.o : mtconfigf/mtconfigf.scm
# mofiles/ulex.o      : ulex/ulex.scm
mofiles/mutils.o    : mutils/mutils.scm
mofiles/cookie.o    : stml2/cookie.scm
mofiles/stml2.o     : stml2/stml2.scm

Modified NOTES from [77a2fe6f9e] to [7c075bb80d].

156
157
158
159
160
161
162




156
157
158
159
160
161
162
163
164
165
166







+
+
+
+
INFO: (0) Number non-cached queries 74289
INFO: (0) Average non-cached time   1055.09826488444 ms
INFO: (0) Server shutdown complete. Exiting

Start: 0 at Sun Apr 28 22:18:25 MST 2013
Max:  52 at Sun Apr 28 23:06:59 MST 2013
End:   6 at Sun Apr 28 23:47:51 MST 2013

========================================================================


Modified TODO from [5c126f9bbf] to [ff0b580779].

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

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
-
+




















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#  Copyright 2006-2017, Matthew Welland.
#  Copyright 2006-2020, Matthew Welland.
# 
# This file is part of Megatest.
# 
#     Megatest 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 3 of the License, or
#     (at your option) any later version.
# 
#     Megatest 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 Megatest.  If not, see <http://www.gnu.org/licenses/>.

NOTE: This file gets copied occasionally into the wiki as "Roadmap".
      Do not make changes in the wiki, they will be lost!

See the file "DONE" to see completed items.
FIXME
====

.dump
----------------
WARNING: disk disk0 at path "/mfs/tmp/archive" is not a directory - ignoring it.

Warning (#<thread: archive-bup-thread>): in thread: unbound variable: block-id

        Call history:

        common.scm:693: hash-table-ref/default    
        common.scm:694: current-seconds   
        common.scm:697: hash-table-set!   
        common.scm:2232: debug:print      
        common_records.scm:140: debug:debug-mode          
        common_records.scm:141: with-output-to-port       
        common.scm:2245: directory?       
        common.scm:2246: common:low-noise-print   
        common.scm:692: g2022     
        common.scm:692: g2022     
        common.scm:692: string-intersperse        
        common.scm:693: hash-table-ref/default    
        common.scm:694: current-seconds   
        common.scm:2261: debug:print      
        common_records.scm:140: debug:debug-mode          
        archive.scm:125: debug:print            <--
INFO: (0) Estimating disk space usage for scriptinc/: 184

Error: uncaught exception: #<condition: (exn runtime)>

        Call history:

        common.scm:1299: ##sys#get-keyword        
        common.scm:1299: call-with-current-continuation   
        common.scm:1299: with-exception-handler   
        common.scm:1299: ##sys#call-with-values   
        common.scm:1304: thunk    
        common.scm:1310: file-exists?     
        common.scm:1299: k2554    
        common.scm:1299: g2558    
        runs.scm:2438: common:get-disk-space-used         
        common.scm:2128: conc     
        common.scm:2128: with-input-from-pipe     
        runs.scm:2438: debug:print-info   
        common_records.scm:235: debug:debug-mode          
        common_records.scm:236: port?     
        common_records.scm:236: with-output-to-port       
        runs.scm:2443: thread-join!             <--
Press any key to continue
----------------

TODO
====

WW15
. fill newview matrix with data, filter pipeline gui elements
. improve [script], especially indent handling

Added adjutant.scm version [419fdc41ba].



































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
;;======================================================================
;; Copyright 2017, Matthew Welland.
;; 
;; This file is part of Megatest.
;; 
;;     Megatest 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 3 of the License, or
;;     (at your option) any later version.
;; 
;;     Megatest 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 Megatest.  If not, see <http://www.gnu.org/licenses/>.

;;======================================================================

(declare (unit adjutant))

(module adjutant
	*
	
(import scheme chicken data-structures extras files)
(import (prefix sqlite3 sqlite3:) posix typed-records srfi-18 srfi-69
	md5 message-digest
	regex srfi-1)

(define (adjutant-run)
  (print "Running the adjutant!"))

)

Modified chicken.makefile from [9f1e7d5923] to [4ef647f9d5].

17
18
19
20
21
22
23









24
25
26
27
28
29
30
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39







+
+
+
+
+
+
+
+
+







#     along with Megatest.  If not, see <http://www.gnu.org/licenses/>.


#======================================================================
# Chicken build
#======================================================================

# CHICKEN_BIN_DIR=$(shell dirname $(shell which csi))
# if have csi on path use that, else use default
# CSIPATH=$(shell which csi)
# CKPATH=$(shell dirname $(shell dirname $(CSIPATH)))
sCHICKEN_PREFIX=$(or $(CKPATH),$(PREFIX)/bin/.$(ARCHSTR))

whatever :
	@echo "CHICKEN_PREFIX=$(CHICKEN_PREFIX)"

tgz-$(USER)/postgresql-9.6.4.tar.gz :
	mkdir -p tgz-$(USER)
	wget -c https://ftp.postgresql.org/pub/source/v9.6.4/postgresql-9.6.4.tar.gz
	mv postgresql-9.6.4.tar.gz tgz-$(USER)/

tgz-$(USER)/sqlite-autoconf-3090200.tar.gz :
	mkdir -p tgz-$(USER)
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
108
109
110
111
112
113
114

115
116
117
118
119
120
121

122
123
124
125
126
127
128
129







-







-
+







	cd build-$(USER)/chicken-4.13.0;make PLATFORM=linux PREFIX=$(CHICKEN_PREFIX) install

ALL_CKBIN=chicken chicken-bind chicken-bug chicken-dump			\
chicken-install chicken-profile chicken-sqlite3 chicken-status		\
chicken-uninstall csc csi feathers nanocat sqlite3 vacuumdb logpro	\
refdb

# CHICKEN_BIN_DIR=$(shell dirname $(shell which csi))
CKBIN_WRAPPERS=$(addprefix $(PREFIX)/bin/,$(ALL_CKBIN))

$(PREFIX)/bin/% : $(CHICKEN_PREFIX)/bin/% $(CHICKEN_PREFIX)/bin/csi $(EGGSTARG2)
	utils/mk_wrapper_tool $(PREFIX) $* $(PREFIX)/bin/$*
	chmod a+x $(PREFIX)/bin/$*

$(PREFIX)/bin :
	mkdir -p $(PREFIX)/bin
	mkdir -p $(PREFIX)/bin $(CHICKEN_PREFIX)/bin

chicken : $(PREFIX)/bin $(CHICKEN_PREFIX)/bin/csi  binwrappers
	@echo "Fake target to build prefix chicken"

binwrappers : $(CKBIN_WRAPPERS)

postgresql.done : $(CHICKEN_PREFIX)/bin/pg_config
141
142
143
144
145
146
147
148
149


149
150
151
152
153
154
155


156
157







-
-
+
+

%.done :
	$(CHICKEN_PREFIX)/bin/chicken-install $* > $*.done

build-$(USER)/eggs-installed/%.done : $(CHICKEN_PREFIX)/bin/csi $(EGGS)
	$(CHICKEN_PREFIX)/bin/chicken-install $* > build-$(USER)/eggs-installed/$*.done



build-clean :
	rm -rf build-$(USER) bin

Modified common.scm from [e484b86e7d] to [6dfe1234b3].

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
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







+
+
+
+

-
+

-
+













-
+







   (read (open-input-string (z3:decode-buffer (base64:base64-decode instr))))))

;; dot-locking egg seems not to work, using this for now
;; if lock is older than expire-time then remove it and try again
;; to get the lock
;;
(define (common:simple-file-lock fname #!key (expire-time 300))
  (let ((fmod-time (handle-exceptions
		       ext
		     (current-seconds)
		     (file-modification-time fname))))
    (if (common:file-exists? fname)
	(if (> (- (current-seconds)(file-modification-time fname)) expire-time)
	(if (> (- (current-seconds) fmod-time) expire-time)
	    (begin
              (handle-exceptions exn #f (delete-file* fname))	
	      (handle-exceptions exn #f (delete-file* fname))	
	      (common:simple-file-lock fname expire-time: expire-time))
	    #f)
	(let ((key-string (conc (get-host-name) "-" (current-process-id))))
	  (with-output-to-file fname
	    (lambda ()
	      (print key-string)))
	  (thread-sleep! 0.25)
	  (if (common:file-exists? fname)
	      (handle-exceptions exn
                #f 
                (with-input-from-file fname
	  	  (lambda ()
		    (equal? key-string (read-line)))))
	      #f))))
	      #f)))))

(define (common:simple-file-lock-and-wait fname #!key (expire-time 300))
  (let ((end-time (+ expire-time (current-seconds))))
    (let loop ((got-lock (common:simple-file-lock fname expire-time: expire-time)))
      (if got-lock
	  #t
	  (if (> end-time (current-seconds))
1731
1732
1733
1734
1735
1736
1737






1738

1739
1740
1741
1742
1743
1744
1745
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747

1748
1749
1750
1751
1752
1753
1754
1755







+
+
+
+
+
+
-
+







		 (file-read-access? fullpath))
	    (handle-exceptions
	     exn
	     #f
	     (debug:print 2 *default-log-port* "reading file " fullpath)
	     (let ((real-age (- (current-seconds)(file-change-time fullpath)))) 
	       (if (< real-age age)
		   (handle-exceptions
		       exn
		     (begin
		       (debug:print-info 1 *default-log-port* " removing bad file " fullpath)
		       (delete-file* fullpath)
		       #f)
		   (with-input-from-file fullpath read)
		     (with-input-from-file fullpath read))
		   (begin
		     (debug:print-info 2 *default-log-port* "file " fullpath " is too old (" real-age" seconds) to trust, skipping reading it")
		     #f))))
	    (begin
	      (debug:print 2 *default-log-port* "not reading file " fullpath)
	      #f)))
      #f))
2042
2043
2044
2045
2046
2047
2048


2049

2050
2051
2052
2053
2054
2055
2056
2052
2053
2054
2055
2056
2057
2058
2059
2060

2061
2062
2063
2064
2065
2066
2067
2068







+
+
-
+







(define (common:wait-for-cpuload maxload-in numcpus-in waitdelay #!key (count 1000) (msg #f)(remote-host #f)(force-maxload #f)(num-tries 5))
  (let* ((loadavg (common:get-cpu-load remote-host))
	 (numcpus (if (<= 1 numcpus-in) ;; not possible to have zero.  If we get 1, it's possible that we got the previous default, and we should check again
		      (common:get-num-cpus remote-host)
		      numcpus-in))
	 (maxload (if force-maxload
		      maxload-in
		      (if (number? maxload-in)
			  (max maxload-in 0.5)
		      (max maxload-in 0.5))) ;; so maxload must be greater than 0.5 for now BUG - FIXME?
			  0.5))) ;; so maxload must be greater than 0.5 for now BUG - FIXME?
	 (first   (car loadavg))
	 (next    (cadr loadavg))
	 (adjmaxload (* maxload (max 1 numcpus))) ;; possible bug where
					       ;; numcpus (or could be
					       ;; maxload) is zero,
					       ;; crude fallback is to
					       ;; at least use 1
2188
2189
2190
2191
2192
2193
2194

2195
2196

2197
2198
2199
2200
2201
2202
2203
2200
2201
2202
2203
2204
2205
2206
2207
2208

2209
2210
2211
2212
2213
2214
2215
2216







+

-
+







	  dirpath)))

;; check space in dbdir and in megatest dir
;; returns: ok/not dbspace required-space
;;
(define (common:check-db-dir-space)
  (let* ((required (string->number 
                    ;; default is 1GB (or actually a billion bytes) This is the number of 1 kB blocks.
		    (or (configf:lookup *configdat* "setup" "dbdir-space-required")
			"100000")))
			"1000000")))
	 (dbdir    (common:get-db-tmp-area)) ;; (db:get-dbdir))
	 (tdbspace (common:check-space-in-dir dbdir required))
	 (mdbspace (common:check-space-in-dir *toppath* required)))
    (sort (list tdbspace mdbspace) (lambda (a b)
				     (< (cadr a)(cadr b))))))
    
;; check available space in dbdir, exit if insufficient
2212
2213
2214
2215
2216
2217
2218
2219

2220


2221


2222
2223
2224
2225
2226
2227
2228
2225
2226
2227
2228
2229
2230
2231

2232
2233
2234
2235

2236
2237
2238
2239
2240
2241
2242
2243
2244







-
+

+
+
-
+
+







	(begin
	  (debug:print-error 0 *default-log-port* "Insufficient space in " dbdir ", require " required ", have " dbspace  ", exiting now.")
	  (exit 1)))))
  
;; paths is list of lists ((name path) ... )
;;
(define (common:get-disk-with-most-free-space disks minsize)
  (let ((best     #f)
  (let* ((best     #f)
	(bestsize 0)
        (default-min-inodes-string "1000000")
        (default-min-inodes (string->number default-min-inodes-string))
        (min-inodes (or (string->number (if (configf:lookup *configdat* "setup" "min_inodes") (configf:lookup *configdat* "setup" "min_inodes") "0")) 0)))
        (min-inodes (or (string->number (if (configf:lookup *configdat* "setup" "min_inodes") (configf:lookup *configdat* "setup" "min_inodes") default-min-inodes-string)) default-min-inodes)))

    (for-each 
     (lambda (disk-num)
       (let* ((dirpath    (cadr (assoc disk-num disks)))
	      (freespc    (cond
			   ((not (directory? dirpath))
			    (if (common:low-noise-print 300 "disks not a dir " disk-num)
				(debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not a directory - ignoring it."))
2250
2251
2252
2253
2254
2255
2256

2257
2258
2259
2260
2261
2262
2263
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280







+







			    (if (common:low-noise-print 300 "disks not a proper path " disk-num)
				(debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not a fully qualified path - ignoring it."))
			    -1)
			   (else
			    (get-free-inodes dirpath))))
             ;;(free-inodes (get-free-inodes dirpath))
             )
             (debug:print 2 *default-log-port* "INFO: disk " disk-num " path " dirpath " free space " freespc " free inodes " free-inodes)
	 (if (and (> freespc bestsize)(> free-inodes min-inodes ))
	     (begin
	       (set! best     (cons disk-num dirpath))
	       (set! bestsize freespc)))
        ;;(print "Processing: " disk-num " bestsize: " bestsize " best: " best " freespc: " freespc " min-inodes: " min-inodes " free-inodes: " free-inodes)
      ))
     (map car disks))

Modified configure from [b4a1e571de] to [08e182d3ee].

14
15
16
17
18
19
20







21
22
23
24
25
26
27
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34







+
+
+
+
+
+
+







#     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 Megatest.  If not, see <http://www.gnu.org/licenses/>.

# Configure the build

if [[ "$1"x == "x" ]];then
    PREFIX=$PWD
else
    PREFIX=$1
fi


#======================================================================
# Configure stuff needed for eggs
#======================================================================

function configure_dependencies () {

56
57
58
59
60
61
62









63
64
65
66
67




68
69

70





71


72


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







+
+
+
+
+
+
+
+
+





+
+
+
+


+
-
+
+
+
+
+

+
+

+
+

echo "" > makefile.inc

#======================================================================
# Do we need Chicken?
#======================================================================

if [[ -e /usr/bin/sw_vers ]]; then
    ARCHSTR=$(/usr/bin/sw_vers -productVersion)
else
    ARCHSTR=$(lsb_release -sr)
fi

echo "CHICKEN_PREFIX=$PREFIX/.$ARCHSTR" >> makefile.inc
CHICKEN_PREFIX=$PREFIX/bin/.$ARCHSTR

if [[ ! $(type csi) ]];then
    echo "Chicken build needed."
    echo "BUILD_CHICKEN=yes" >> makefile.inc
    configure_dependencies
    echo "include chicken.makefile" >> makefile.inc
else
    echo "CSIPATH=$(which csi)" >> makefile.inc
    CSIPATH=$(which csi)
    echo "CKPATH=$(dirname $(dirname $CSIPATH))" >> makefile.inc
fi

# Make setup scripts
echo "All done creating makefile.inc, feel free to edit it!"
echo "#!/bin/bash" > setup.sh
echo "export PATH=$CHICKEN_PREFIX/bin:\$PATH" >> setup.sh
echo "export LD_LIBRARY_PATH=$CHICKEN_PREFIX/lib" >> setup.sh
echo 'exec "$@"' >> setup.sh
chmod a+x setup.sh

echo "setenv PATH $CHICKEN_PREFIX/bin:\$PATH" > setup.csh
echo "setenv LD_LIBRARY_PATH $CHICKEN_PREFIX/lib" >> setup.csh

echo "All done creating makefile.inc, feel free to edit it!"
echo "run \"setup.sh bash\" or source setup.csh to get PATH and LD_LIBRARY_PATH adjusted"

Modified dashboard.scm from [fe89207a20] to [683033e99e].

1482
1483
1484
1485
1486
1487
1488
1489

1490
1491
1492
1493
1494
1495
1496
1482
1483
1484
1485
1486
1487
1488

1489
1490
1491
1492
1493
1494
1495
1496







-
+







	 (tests-draw-state (make-hash-table)) ;; use for keeping state of the test canvas
	 (test-patterns-textbox  #f))
    (hash-table-set! tests-draw-state 'first-time #t)
    ;; (hash-table-set! tests-draw-state 'scalef 1)
    (tests:get-full-data test-names test-records '() all-tests-registry)
    (set! sorted-testnames (tests:sort-by-priority-and-waiton test-records))
    
    ;; refer to (dboard:tabcodat-keys tabdat), (dboard:tabdat-dbkeys tabdat) for keys
    ;; refer to (dboard:tabdat-keys tabdat), (dboard:tabdat-dbkeys tabdat) for keys
    (let* ((result
	    (iup:vbox
	     (dcommon:command-execution-control tabdat)
	     (iup:split
	      #:orientation "VERTICAL" ;; "HORIZONTAL"
	      #:value 200
	      ;; 
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
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







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+






-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
+
+
+
+


-
-
-
-
-
-
+
+
+
+
+
+







	 (btn-height      (dboard:tabdat-runs-btn-height runs-dat))
	 (btn-fontsz      (dboard:tabdat-runs-btn-fontsz runs-dat))
	 (cell-width      (dboard:tabdat-runs-cell-width runs-dat)))
    ;; controls (along bottom)
    ;; (set! controls (dboard:make-controls commondat runs-dat))
    
    ;; create the left most column for the run key names and the test names 
    (set! lftlst (list (iup:hbox
			(iup:label) ;; (iup:valuator)
			(apply iup:vbox 
			       (map (lambda (x)		
				      (let ((res (iup:hbox #:expand "HORIZONTAL"
							   (iup:label x #:size (conc 40 btn-height) #:fontsize btn-fontsz #:expand "NO") ;; "HORIZONTAL")
							   (iup:textbox #:size (conc 35 btn-height) #:fontsize btn-fontsz #:value "%" #:expand "NO" ;; "HORIZONTAL"
									#:action (lambda (obj unk val)
										   ;; each field (field name is "x" var) live updates
										   ;; the search filter as it is typed
										   (dboard:tabdat-target-set! runs-dat #f) ;; ensure the fields text boxes are used and not the info from the tree
										   (mark-for-update runs-dat)
										   (update-search commondat runs-dat x val))))))
					(set! i (+ i 1))
					res))
				    keynames)))))
    (set! lftlst
	  (list (iup:hbox
		 (iup:label) ;; (iup:valuator)
		 (apply iup:vbox 
			(map (lambda (x)		
			       (let ((res (iup:hbox
					   #:expand "HORIZONTAL"
					   (iup:label x
						      #:size (conc 40 btn-height)
						      #:fontsize btn-fontsz
						      #:expand "NO") ;; "HORIZONTAL")
					   (iup:textbox
					    #:size (conc 35 btn-height)
					    #:fontsize btn-fontsz
					    #:value "%"
					    #:expand "NO" ;; "HORIZONTAL"
					    #:action (lambda (obj unk val)
						       ;; each field
						       ;; (field name is "x" var) live updates
						       ;; the search filter as it is typed
						       (dboard:tabdat-target-set! runs-dat #f)
						       ;; ensure fields text boxes are used
						       ;; and not the info from the tree
						       (mark-for-update runs-dat)
						       (update-search commondat runs-dat x val))))))
				 (set! i (+ i 1))
				 res))
			     keynames)))))
    (let loop ((testnum  0)
	       (res      '()))
      (cond
       ((>= testnum ntests)
	;; now lftlst will be an hbox with the test keys and the test name labels
	(set! lftlst
	      (append lftlst
		      (list (iup:hbox
			     #:expand "HORIZONTAL"
			     (iup:valuator
			      #:valuechanged_cb (lambda (obj)
						  (let ((val (string->number (iup:attribute obj "VALUE")))
							(oldmax  (string->number (iup:attribute obj "MAX")))
							(newmax  (* 10 (length (dboard:tabdat-all-test-names runs-dat)))))
						    (dboard:commondat-please-update-set! commondat #t)
						    (dboard:tabdat-start-test-offset-set! runs-dat (inexact->exact (round (/ val 10))))
						    (debug:print 6 *default-log-port* "(dboard:tabdat-start-test-offset runs-dat) "
								 (dboard:tabdat-start-test-offset runs-dat) " val: " val
								 " newmax: " newmax " oldmax: " oldmax)
						    (if (< val 10)
							(iup:attribute-set! obj "MAX" newmax))
						    ))
			      #:expand "VERTICAL" 
			      #:orientation "VERTICAL"
			      #:min 0
			      #:step 0.01)
			     (apply iup:vbox (reverse res)))))))
	      (append
	       lftlst
	       (list
		(iup:hbox
		 #:expand "HORIZONTAL"
		 (iup:valuator
		  #:valuechanged_cb
		  (lambda (obj)
		    (let ((val (string->number (iup:attribute obj "VALUE")))
			  (oldmax  (string->number (iup:attribute obj "MAX")))
			  (newmax  (* 10 (length (dboard:tabdat-all-test-names runs-dat)))))
		      (dboard:commondat-please-update-set! commondat #t)
		      (dboard:tabdat-start-test-offset-set! runs-dat
							    (inexact->exact (round (/ val 10))))
		      (debug:print 6 *default-log-port*
				   "(dboard:tabdat-start-test-offset runs-dat) "
				   (dboard:tabdat-start-test-offset runs-dat) " val: " val
				   " newmax: " newmax " oldmax: " oldmax)
		      (if (< val 10)
			  (iup:attribute-set! obj "MAX" newmax))
		      ))
		  #:expand "VERTICAL" 
		  #:orientation "VERTICAL"
		  #:min 0
		  #:step 0.01)
		 (apply iup:vbox (reverse res)))))))
       (else
	(let ((labl  (iup:button "" ;; the testname labels
				 #:flat "YES" 
				 #:alignment "ALEFT"
	(let ((labl  (iup:button
		      "" ;; the testname labels
		      #:flat "YES" 
		      #:alignment "ALEFT"
					; #:image img1
					; #:impress img2
				 #:size  (conc cell-width btn-height)
				 #:expand  "HORIZONTAL"
				 #:fontsize btn-fontsz
				 #:action (lambda (obj)
					    (mark-for-update runs-dat)
					    (toggle-hide testnum (dboard:commondat-uidat commondat)))))) ;; (iup:attribute obj "TITLE"))))
		      #:size  (conc cell-width btn-height)
		      #:expand  "HORIZONTAL"
		      #:fontsize btn-fontsz
		      #:action (lambda (obj)
				 (mark-for-update runs-dat)
				 (toggle-hide testnum (dboard:commondat-uidat commondat)))))) 
	  (vector-set! lftcol testnum labl)
	  (loop (+ testnum 1)(cons labl res))))))
    ;; These are the headers for each row
    (let loop ((runnum  0)
	       (keynum  0)
	       (keyvec  (make-vector nkeys))
	       (res    '()))
2919
2920
2921
2922
2923
2924
2925
2926

2927
2928
2929
2930
2931
2932
2933
2937
2938
2939
2940
2941
2942
2943

2944
2945
2946
2947
2948
2949
2950
2951







-
+







			    (apply iup:hbox (reverse hdrlst))
			    (apply iup:hbox (reverse bdylst))
			    (dashboard:runs-horizontal-slider runs-dat))))
			 controls
			 ))
	     (views-cfgdat (common:load-views-config))
	     (additional-tabnames '())
	     (tab-start-num       6)   ;; DON'T FORGET TO UPDATE THIS WHEN CHANGING THE STANDARD TABS BELOW
	     (tab-start-num       5)   ;; DON'T FORGET TO UPDATE THIS WHEN CHANGING THE STANDARD TABS BELOW
	     ;; (data (dboard:tabdat-init (make-d:data)))
	     (additional-views 	;; process views-dat
	      (let ((tab-num tab-start-num)
		    (result  '()))
		(for-each
		 (lambda (view-name)
		   (debug:print 0 *default-log-port* "Adding view " view-name)
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
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







-
-
+
+
-
-
-
+
+
-




-
-
-
-
+
+
+
+















-
-
-
-
+
+
+
+







						 (let* ((tab-num (dboard:commondat-curr-tab-num commondat))
							(tabdat  (dboard:common-get-tabdat commondat tab-num: tab-num)))
						   (dboard:commondat-please-update-set! commondat #t)
						   (dboard:tabdat-layout-update-ok-set! tabdat #t)))
					       "tabchangepos"))
			  (dashboard:summary commondat stats-dat tab-num: 0)
			  runs-view
			  (make-runs-view commondat runs2-dat 2)
			  (dashboard:runs-summary commondat onerun-dat tab-num: 3)
			  ;; (make-runs-view commondat runs2-dat 2)
			  (dashboard:runs-summary commondat onerun-dat tab-num: 2)
			  ;; (dashboard:new-view db data new-view-dat tab-num: 3)
			  (dashboard:run-controls commondat runcontrols-dat tab-num: 4)
			  (dashboard:run-times commondat runtimes-dat tab-num: 5)
			  (dashboard:run-controls commondat runcontrols-dat tab-num: 3)
			  (dashboard:run-times commondat runtimes-dat tab-num: 4)
			  ;; (dashboard:runs-summary commondat onerun-dat tab-num: 4)
			  additional-views)))
	;; (set! (iup:callback tabs tabchange-cb:) (lambda (a b c)(print "SWITCHED TO TAB: " a " " b " " c)))
	(iup:attribute-set! tabs "TABTITLE0" "Summary")
	(iup:attribute-set! tabs "TABTITLE1" "Runs")
	(iup:attribute-set! tabs "TABTITLE2" "Runs2")
	(iup:attribute-set! tabs "TABTITLE3" "Run Summary")
	(iup:attribute-set! tabs "TABTITLE4" "Run Control")
	(iup:attribute-set! tabs "TABTITLE5" "Run Times")
	;; (iup:attribute-set! tabs "TABTITLE2" "Runs2")
	(iup:attribute-set! tabs "TABTITLE2" "Run Summary")
	(iup:attribute-set! tabs "TABTITLE3" "Run Control")
	(iup:attribute-set! tabs "TABTITLE4" "Run Times")
	;; (iup:attribute-set! tabs "TABTITLE3" "New View")
	;; (iup:attribute-set! tabs "TABTITLE4" "Run Control")

	;; set the tab names for user added tabs
	(for-each
	 (lambda (tab-info)
	   (iup:attribute-set! tabs (conc "TABTITLE" (car tab-info)) (cdr tab-info)))
	 additional-tabnames)
	
	(iup:attribute-set! tabs "BGCOLOR" "190 190 190")
	;; make the iup tabs object available (for changing color for example)
	(dboard:commondat-hide-not-hide-tabs-set! commondat tabs)
	;; now set up the tabdat lookup
	(dboard:common-set-tabdat! commondat 0 stats-dat)
	(dboard:common-set-tabdat! commondat 1 runs-dat)
	(dboard:common-set-tabdat! commondat 2 onerun-dat)
	(dboard:common-set-tabdat! commondat 3 runcontrols-dat)
	(dboard:common-set-tabdat! commondat 4 runs2-dat)
	(dboard:common-set-tabdat! commondat 5 runtimes-dat)
	;;(dboard:common-set-tabdat! commondat 2 runs2-dat)
	(dboard:common-set-tabdat! commondat 2 onerun-dat)
	(dboard:common-set-tabdat! commondat 3 runcontrols-dat)
	(dboard:common-set-tabdat! commondat 4 runtimes-dat)

	(iup:vbox
	 tabs
	 ;; controls
	 ))))
    (vector keycol lftcol header runsvec)))

Modified db.scm from [2247f17f91] to [1abf27c71c].

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
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







-
+







-
+








-
+







	;; archive disk areas, cached info from [archive-disks]
	(sqlite3:execute db "CREATE TABLE IF NOT EXISTS archive_disks (
                                id INTEGER PRIMARY KEY,
                                archive_area_name TEXT,
                                disk_path TEXT,
                                last_df INTEGER DEFAULT -1,
                                last_df_time TIMESTAMP DEFAULT (strftime('%s','now')),
                                creation_time TIMESTAMP DEFAULT (strftime('%','now')));")
                                creation_time TIMESTAMP DEFAULT (strftime('%s','now')));")
	;; individual bup (or tar) data chunks
	(sqlite3:execute db "CREATE TABLE IF NOT EXISTS archive_blocks (
                                id INTEGER PRIMARY KEY,
                                archive_disk_id INTEGER,
                                disk_path TEXT,
                                last_du INTEGER DEFAULT -1,
                                last_du_time TIMESTAMP DEFAULT (strftime('%s','now')),
                                creation_time TIMESTAMP DEFAULT (strftime('%','now')));")
                                creation_time TIMESTAMP DEFAULT (strftime('%s','now')));")
	;; tests allocated to what chunks. reusing a chunk for a test/item_path is very efficient
	;; NB// the per run/test recording of where the archive is stored is done in the test
	;;      record. 
	(sqlite3:execute db "CREATE TABLE IF NOT EXISTS archive_allocations (
                                id INTEGER PRIMARY KEY,
                                archive_block_id INTEGER,
                                testname TEXT,
                                item_path TEXT,
                                creation_time TIMESTAMP DEFAULT (strftime('%','now')));")
                                creation_time TIMESTAMP DEFAULT (strftime('%s','now')));")
	;; move this clean up call somewhere else
	(sqlite3:execute db "DELETE FROM tasks_queue WHERE state='done' AND creation_time < ?;" (- (current-seconds)(* 24 60 60))) ;; remove older than 24 hrs
	(sqlite3:execute db (conc "CREATE INDEX IF NOT EXISTS runs_index ON runs (runname" (if havekeys "," "") keystr ");"))
	;; (sqlite3:execute db "CREATE VIEW runs_tests AS SELECT * FROM runs INNER JOIN tests ON runs.id=tests.run_id;")
	(sqlite3:execute db "CREATE TABLE IF NOT EXISTS extradat (id INTEGER PRIMARY KEY, run_id INTEGER, key TEXT, val TEXT);")
	(sqlite3:execute db "CREATE TABLE IF NOT EXISTS metadat (id INTEGER PRIMARY KEY, var TEXT, val TEXT,
                                  CONSTRAINT metadat_constraint UNIQUE (var));")
1696
1697
1698
1699
1700
1701
1702
1703

1704
1705
1706
1707
1708
1709
1710
1696
1697
1698
1699
1700
1701
1702

1703
1704
1705
1706
1707
1708
1709
1710







-
+







                (set! toplevels   (cons (list test-id run-dir uname testname item-path run-id) toplevels))
                (debug:print-info 0 *default-log-port* "Found old toplevel test in RUNNING state, test-id=" test-id))
              (begin
                (debug:print-info 0 *default-log-port* "Found old test in REMOTEHOSTSTART state, test-id=" test-id" exceeded running-deadtime "running-deadtime" now="(current-seconds)" event-time="event-time" run-duration="run-duration)
                (set! incompleted (cons (list test-id run-dir uname testname item-path run-id) incompleted)))))
        db
        "SELECT id,rundir,uname,testname,item_path,event_time,run_duration FROM tests WHERE run_id=? AND (strftime('%s','now') - event_time) > (run_duration + ?) AND state IN ('REMOTEHOSTSTART');"
        run-id remotehoststart-deadtime) ;; default time 230 seconds.
        run-id remotehoststart-deadtime) ;; default time 230 seconds

       ;; in LAUNCHED for more than one day. Could be long due to job queues TODO/BUG: Need override for this in config
       ;;
       ;; (db:delay-if-busy dbdat)
       (sqlite3:for-each-row
        (lambda (test-id run-dir uname testname item-path)
          (if (and (equal? uname "n/a")
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
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







+



-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-







              ;;      			(or (not dbexists) ;; if no file then something wrong - mark as incomplete
              ;;      			    (> (- (current-seconds)(file-modification-time tdatpath)) 600)))) ;; no change in 10 minutes to testdat.db - she's dead Jim
              ;;      		    incompleted))
              (min-incompleted-ids (map car incompleted)) ;; do 'em all
              (all-ids             (append min-incompleted-ids (map car oldlaunched))))
         (if (> (length all-ids) 0)
             (begin
	       ;; (launch:is-test-alive "localhost" 435)
               (debug:print 0 *default-log-port* "WARNING: Marking test(s); " (string-intersperse (map conc all-ids) ", ") " as DEAD")
               (for-each
                  (lambda (test-id)
                    (let* (
                      (run-dir (db:test-get-rundir-from-test-id dbstruct run-id test-id))
                      (result (db:get-status-from-final-status-file run-dir)))
                    (if (and (list? result) (> (length result) 1) (equal? "PASS" (cadr result)) (equal? "COMPLETED" (car result))) 
                      (begin
                        (debug:print 0 *default-log-port* "INFO: test " test-id " actually passed, so marking PASS not DEAD")
                        (db:set-state-status-and-roll-up-items dbstruct run-id test-id 'foo "COMPLETED" "PASS" "Test stopped responding but it has PASSED; marking it PASS in the DB.")
                    (let* (;; (run-dir (db:test-get-rundir-from-test-id dbstruct run-id test-id))
			   (tinfo   (db:get-test-info-by-id dbstruct run-id test-id))
			   (run-dir (db:test-get-rundir     tinfo))
			   (host    (db:test-get-host       tinfo))
			   (pid     (db:test-get-process_id tinfo))
			   (result (db:get-status-from-final-status-file run-dir)))
		      (if (and (list? result) (> (length result) 1) (equal? "PASS" (cadr result)) (equal? "COMPLETED" (car result))) 
			  (begin
			    (debug:print 0 *default-log-port* "INFO: test " test-id " actually passed, so marking PASS not DEAD")
			    (db:set-state-status-and-roll-up-items dbstruct run-id test-id 'foo "COMPLETED" "PASS"
                      )
                      (begin
                      (debug:print 0 *default-log-port* "INFO: test " test-id " final state/status is not COMPLETED/PASS. It is " result)
                      (db:set-state-status-and-roll-up-items dbstruct run-id test-id 'foo "COMPLETED" "DEAD" "Test stopped responding while in RUNNING or REMOTEHOSTSTART; presumed dead.")
								   "Test stopped responding but it has PASSED; marking it PASS in the DB."))
			  (let ((is-alive (launch:is-test-alive host pid)))
			    (if is-alive
				(debug:print 0 *default-log-port* "INFO: test " test-id " on host " host " has a process on pid " pid ", NOT setting to DEAD.")
				(begin
				  (debug:print 0 *default-log-port* "INFO: test " test-id " final state/status is not COMPLETED/PASS. It is " result)
				  (db:set-state-status-and-roll-up-items dbstruct run-id test-id 'foo "COMPLETED" "DEAD"
                      )
                     )
                    )
                  )
                  all-ids)
             )
         )
									 "Test stopped responding while in RUNNING or REMOTEHOSTSTART; presumed dead.")))))))
		  all-ids)
	       ;;call end of eud of run detection for posthook
	       (launch:end-of-run-check run-id)
	       )))))))

       )
     )
   )
 )
)

;; ALL REPLACED BY THE BLOCK ABOVE
;;
;; 	    (sqlite3:execute 
;; 	     db
;; 	     (conc "UPDATE tests SET state='INCOMPLETE' WHERE run_id=? AND id IN (" 
;; 		   (string-intersperse (map conc all-ids) ",")

Modified dcommon.scm from [ada970eba5] to [30bf3c6504].

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
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








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







    ;; (iup:attribute-set! general-matrix "2:0" "Area")
    ;; (iup:attribute-set! general-matrix "2:1" *toppath*)
    ;; Megatest version
    (iup:attribute-set! general-matrix "2:0" "Version")
    (iup:attribute-set! general-matrix "2:1" (conc megatest-version "-" (substring megatest-fossil-hash 0 4)))

    general-matrix))

(define (dcommon:stats-updater commondat tabdat stats-matrix)
  (if (and (iup:ihandle? stats-matrix)
	   (dashboard:database-changed? commondat tabdat context-key: 'run-stats))
      (let* ((changed      #f)
	     (run-stats    (rmt:get-run-stats))
	     (indices      (common:sparse-list-generate-index run-stats)) ;;  proc: set-cell))
	     (row-indices  (car indices))
	     (col-indices  (cadr indices))
	     (max-row      (if (null? row-indices) 1 (common:max (map cadr row-indices))))
	     (max-col      (if (null? col-indices) 1 
			       (common:max (map cadr col-indices))))
	     (max-visible  (max (- (dboard:tabdat-num-tests tabdat) 15) 3))
	     (max-col-vis  (if (> max-col 10) 10 max-col))
	     (numrows      1)
	     (numcols      1))
	(iup:attribute-set! stats-matrix "CLEARVALUE" "CONTENTS")
	(iup:attribute-set! stats-matrix "NUMCOL" max-col )
	(iup:attribute-set! stats-matrix "NUMLIN" (if (< max-row max-visible) max-visible max-row)) ;; min of 20
	(iup:attribute-set! stats-matrix "NUMCOL_VISIBLE" max-col-vis)
	(iup:attribute-set! stats-matrix "NUMLIN_VISIBLE" (if (> max-row max-visible) max-visible max-row))
	(print "row-indices: " row-indices " col-indices: " col-indices)
	;; Row labels
	(for-each (lambda (ind)
		    (let* ((name (car ind))
			   (num  (cadr ind))
			   (key  (conc num ":0")))
		      (if (not (equal? (iup:attribute stats-matrix key) name))
			  (begin
			    (set! changed #t)
			    (iup:attribute-set! stats-matrix key name)))))
		  row-indices)

	;; Col labels
	(for-each (lambda (ind)
		    (let* ((name (car ind))
			   (num  (cadr ind))
			   (key  (conc "0:" num)))
		      (if (not (equal? (iup:attribute stats-matrix key) name))
			  (begin
			    (set! changed #t)
			    (iup:attribute-set! stats-matrix key name)))))
		  col-indices)

	;; Cell contents
	(for-each (lambda (entry)
		    (let* ((row-name (car entry))
			   (col-name (cadr entry))
			   (value    (caddr entry))
			   (row-num  (cadr (assoc row-name row-indices)))
			   (col-num  (cadr (assoc col-name col-indices)))
			   (key      (conc row-num ":" col-num)))
		      (if (not (equal? (iup:attribute stats-matrix key) value))
			  (begin
			    (set! changed #t)
			    (iup:attribute-set! stats-matrix key value)))))
		  run-stats)
	(if changed (iup:attribute-set! stats-matrix "REDRAW" "ALL")))))


(define (dcommon:run-stats commondat tabdat #!key (tab-num #f))
  (let* ((stats-matrix (iup:matrix expand: "YES"))
	 (changed      #f)
	 (stats-updater (lambda ()
			 (if (dashboard:database-changed? commondat tabdat context-key: 'run-stats)
			     (let* ((run-stats    (rmt:get-run-stats))
				    (indices      (common:sparse-list-generate-index run-stats)) ;;  proc: set-cell))
				    (row-indices  (car indices))
				    (col-indices  (cadr indices))
				    (max-row      (if (null? row-indices) 1 (common:max (map cadr row-indices))))
				    (max-col      (if (null? col-indices) 1 
						      (common:max (map cadr col-indices))))
				    (max-visible  (max (- (dboard:tabdat-num-tests tabdat) 15) 3))
				    (max-col-vis  (if (> max-col 10) 10 max-col))
				    (numrows      1)
				    (numcols      1))
			       (iup:attribute-set! stats-matrix "CLEARVALUE" "CONTENTS")
			       (iup:attribute-set! stats-matrix "NUMCOL" max-col )
			       (iup:attribute-set! stats-matrix "NUMLIN" (if (< max-row max-visible) max-visible max-row)) ;; min of 20
			       (iup:attribute-set! stats-matrix "NUMCOL_VISIBLE" max-col-vis)
			       (iup:attribute-set! stats-matrix "NUMLIN_VISIBLE" (if (> max-row max-visible) max-visible max-row))

			  (dcommon:stats-updater commondat tabdat stats-matrix))))
			       ;; Row labels
			       (for-each (lambda (ind)
					   (let* ((name (car ind))
						  (num  (cadr ind))
						  (key  (conc num ":0")))
					     (if (not (equal? (iup:attribute stats-matrix key) name))
						 (begin
						   (set! changed #t)
						   (iup:attribute-set! stats-matrix key name)))))
					 row-indices)

			       ;; Col labels
			       (for-each (lambda (ind)
					   (let* ((name (car ind))
						  (num  (cadr ind))
						  (key  (conc "0:" num)))
					     (if (not (equal? (iup:attribute stats-matrix key) name))
						 (begin
						   (set! changed #t)
						   (iup:attribute-set! stats-matrix key name)))))
					 col-indices)

			       ;; Cell contents
			       (for-each (lambda (entry)
					   (let* ((row-name (car entry))
						  (col-name (cadr entry))
						  (value    (caddr entry))
						  (row-num  (cadr (assoc row-name row-indices)))
						  (col-num  (cadr (assoc col-name col-indices)))
						  (key      (conc row-num ":" col-num)))
					     (if (not (equal? (iup:attribute stats-matrix key) value))
						 (begin
						   (set! changed #t)
						   (iup:attribute-set! stats-matrix key value)))))
					 run-stats)
			       (if changed (iup:attribute-set! stats-matrix "REDRAW" "ALL")))
                             ))))
    ;; (dboard:commondat-please-update-set! commondat #t) ;; force redraw on first pass 
    ;; (mark-for-update tabdat)
    ;; (stats-updater)
    (dboard:commondat-add-updater commondat stats-updater tab-num: tab-num)
    ;; (set! dashboard:update-summary-tab updater)
    (iup:attribute-set! stats-matrix "WIDTHDEF" "40")
    (iup:vbox

Modified docs/manual/installation.txt from [73f4fcba67] to [93bb208a2d].

18
19
20
21
22
23
24


25
26
27

















28







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







+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
Installation
------------

Dependencies
~~~~~~~~~~~~

Chicken scheme and a number of "eggs" are required for building
Megatest. In the v1.66 and beyond assistance to create the build
system is built into the Makefile.
Megatest. See the script installall.sh in the utils directory of the
source distribution for an automated way to install everything
needed for building Megatest on Linux.

.Installation steps (overview)
-------------------------------------
./configure
make chicken
setup.sh make -j install
-------------------------------------

Or install the needed build system manually:

. Chicken scheme from http://call-cc.org
. IUP from http://webserver2.tecgraf.puc-rio.br/iup/
. CD from http://webserver2.tecgraf.puc-rio.br/cd/
. IM from https://webserver2.tecgraf.puc-rio.br/im/
. ffcall from http://webserver2.tecgraf.puc-rio.br/iup/
. Nanomsg from https://nanomsg.org/ (NOTE: Plan is to eliminate nanomsg dependency).
. Needed eggs (look at the eggs lists in the Makefile)

Then follow these steps:

.Installation steps (self-built chicken scheme build system)
-------------------------------------
./configure
make -j install
-------------------------------------

Modified docs/manual/megatest_manual.html from [ad2b2421c3] to [815cb0cf69].

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
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







-
-
+
+













-
+







</script>
</head>
<body class="book">
<div id="header">
<h1>The Megatest Users Manual</h1>
<span id="author">Matt Welland</span><br>
<span id="email" class="monospaced">&lt;<a href="mailto:matt@kiatoa.com">matt@kiatoa.com</a>&gt;</span><br>
<span id="revnumber">version 1.0,</span>
<span id="revdate">April 2012</span>
<span id="revnumber">version 1.5,</span>
<span id="revdate">June 2020</span>
<div id="toc">
  <div id="toctitle">Table of Contents</div>
  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="_preface">Preface</h2>
<div class="sectionbody">
<div class="paragraph"><p>This book is organised as three sub-books; getting started, writing tests and reference.</p></div>
<div class="listingblock">
<div class="title">License</div>
<div class="content monospaced">
<pre>    Copyright 2006-2017, Matthew Welland.
<pre>    Copyright 2006-2020, Matthew Welland.

    This document is part of Megatest.

    Megatest 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 3 of the License, or
    (at your option) any later version.
807
808
809
810
811
812
813
814

815
816
817
818
819
820
821
807
808
809
810
811
812
813

814
815
816
817
818
819
820
821







-
+







<h2 id="_why_megatest">Why Megatest?</h2>
<div class="sectionbody">
<div class="paragraph"><p>The Megatest project was started for two reasons, the first was an
immediate and pressing need for a generalized tool to manage a suite
of regression tests and the second was the fact that I had written or
maintained several such tools at different companies over the years. I
thought a single open source tool, flexible enough to meet the needs
of any team doing continuous integrating and or running a complex
of any team doing continuous integration and or running a complex
suite of tests for release qualification would solve some problems for
me and for others.</p></div>
<div class="literalblock">
<div class="content monospaced">
<pre>-- Matt Welland, original author of the Megatest tool suite.</pre>
</div></div>
</div>
953
954
955
956
957
958
959

































































































































































































































































































































































































































































































960
961
962
963
964
965
966
967
968
969






















































970
971
972
973
974
975
976
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







<div class="imageblock">
<div class="content">
<img src="megatest-system-architecture.png" alt="Static">
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_todo_road_map">TODO / Road Map</h2>
<div class="sectionbody">
<div class="paragraph"><p>Note: This road-map is a wish list and not a formal plan. Items are in
rough priority but are subject to change. Development is driven by
user requests, developer "itch" and bug reports. Please contact
<a href="mailto:matt@kiatoa.com">matt@kiatoa.com</a> with requests or bug reports. Requests from inside
Intel generally take priority.</p></div>
<div class="paragraph"><p>Dashboard and runs</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Multi-area dashboard view
</p>
</li>
</ol></div>
<div class="paragraph"><p>Tests Support</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME
</p>
</li>
<li>
<p>
Improve [script], especially indent handling
</p>
</li>
</ol></div>
<div class="paragraph"><p>Scalability</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Overflow database methodology - combine the best of the v1.63
  multi-db approach and the current db-in-tmp approach (currently
  slowness can be seen when number of tests in a db goes over 50-100k,
  with the overflow db it will be able to handle 1000&#8217;s of runs with
  50-100k tests per run). High priority - goal is to complete this by
  20Q3.
</p>
</li>
</ol></div>
<div class="paragraph"><p>Mtutils/CI</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Enable mtutil calls from dashboard (for remote control)
</p>
</li>
<li>
<p>
Logs browser (esp. for surfacing mtutil related activities)
</p>
</li>
<li>
<p>
Embed ftfplan for distributed automation, completed activities trigger QA runs which trigger deployment etc.
</p>
</li>
<li>
<p>
Jenkins junit XML support [DONE]
</p>
</li>
<li>
<p>
Add output flushing in teamcity support
</p>
</li>
</ol></div>
<div class="paragraph"><p>Build system</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
./configure &#8658; ubuntu, sles11, sles12, rh7 [WIP]
</p>
</li>
<li>
<p>
Switch to using simple runs query everywhere
</p>
</li>
<li>
<p>
Add end_time to runs and add a rollup call that sets state, status and end_time
</p>
</li>
</ol></div>
<div class="paragraph"><p>Code refactoring/quality/performance</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Switch to scsh-process pipeline management for job execution/control
</p>
</li>
<li>
<p>
Use call-with-environment-variables where possible.
</p>
</li>
</ol></div>
<div class="paragraph"><p>Migration to inmem db and or overflow db</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Re-work the dbstruct data structure?
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
[ run-id.db inmemdb last-mod last-read last-sync inuse ]
</p>
</li>
</ol></div>
</li>
</ol></div>
<div class="paragraph"><p>Some ideas for Megatest 2.0</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Aggressive megatest.config and runconfig.config caching.
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
Cache the configs in $MT_RUNPATH
</p>
</li>
<li>
<p>
Following invocations of –run, -rerun* will calculate the new config but only overwrite the cached file IF changed
</p>
</li>
</ol></div>
</li>
<li>
<p>
If the cached file changes ALL existing tests go from COMPLETED &#8594; STALE, I’m not sure what to do about RUNNING tests
</p>
</li>
<li>
<p>
!VARS in runconfigs are not exported to the environment. They are accessed via rget as if the ! was not there.
</p>
</li>
<li>
<p>
Per test copy commands (example is incomplete).
</p>
</li>
</ol></div>
<div class="listingblock">
<div class="content monospaced">
<pre>[testcopy]
%/iind% unison SRC DEST
% cp –r SRC DEST</pre>
</div></div>
<div class="paragraph"><p>Add ability to move runs to other Areas (overlaps with overflow db system)</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
allow shrinking megatest.db data by moving runs to an alternate
  Megatest area with same keys.
</p>
</li>
<li>
<p>
add param -destination [area|path]. when specified runs are copied to new
  area and removed from local db.
</p>
</li>
<li>
<p>
the data move would involve these steps
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
copy the run data to destination area megatest.db
</p>
</li>
<li>
<p>
mark the run records as deleted, do not remove the run data on disk
</p>
</li>
</ol></div>
</li>
<li>
<p>
accessing the data would be by running dashboard in the satellite area
</p>
</li>
<li>
<p>
future versions of Megatest dashboard should support displaying areas in a
  merged way.
</p>
</li>
<li>
<p>
some new controls would be supported in the config
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
[setup] &#8658; allow-runs [no|yes]  &#8656;= used to disallow runs
</p>
</li>
<li>
<p>
[setup] &#8658; auto-migrate=[areaname|path]  &#8656;= used to automatically
   migrate data to a satellite area.
</p>
</li>
</ol></div>
</li>
</ol></div>
<div class="paragraph"><p>Eliminate ties to homehost (part of overflow db system)</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Server creates captain pkt
</p>
</li>
<li>
<p>
Create a lock in the db
</p>
</li>
<li>
<p>
Relinquish db when done
</p>
</li>
</ol></div>
<div class="paragraph"><p>Tasks - better management of run manager processes etc.</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
adjutant queries tasks table for next action <span class="red">[Migrate into mtutil]</span>
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
Task table used for tracking runner process <span class="red">[Replaced by mtutil]</span>
</p>
</li>
<li>
<p>
Task table used for jobs to run <span class="red">[Replaced by mtutil]</span>
</p>
</li>
<li>
<p>
Task table used for queueing runner actions (remove runs,
   cleanRunExecute, etc)  <span class="red">[Replaced by mtutil</span>]
</p>
</li>
</ol></div>
</li>
<li>
<p>
adjutant (server/task dispatch/execution manager)
</p>
</li>
</ol></div>
<div class="paragraph"><p>Stale propagation</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Mark dependent tests for clean/rerun -rerun-downstream
</p>
</li>
<li>
<p>
On run start check for defunct tests in RUNNING, LAUNCHED or REMOTEHOSTSTART and correct or notify
</p>
</li>
<li>
<p>
Fix: refresh of gui sometimes fails on last item (race condition?)
</p>
</li>
</ol></div>
<div class="paragraph"><p>Bin list</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Rerun step and or subsequent steps from gui [DONE?]
</p>
</li>
<li>
<p>
Refresh test area files from gui
</p>
</li>
<li>
<p>
Clean and re-run button
</p>
</li>
<li>
<p>
Clean up STATE and STATUS handling.
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
Dashboard and Test control panel are reverse order - choose and fix
</p>
</li>
<li>
<p>
Move seldom used states and status to drop down selector
</p>
</li>
</ol></div>
</li>
<li>
<p>
Access test control panel when clicking on Run Summary tests
</p>
</li>
<li>
<p>
Feature: -generate-index-tree
</p>
</li>
<li>
<p>
Change specifing of state and status to use STATE1/STATUS1,STATE2/STATUS2
</p>
</li>
<li>
<p>
rest api available for use with Perl, Ruby etc. scripts
</p>
</li>
<li>
<p>
megatest.config setup entries for:
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
run launching (e.g. /bin/sh %CMD% &gt; /dev/null)
</p>
</li>
<li>
<p>
browser "konqueror %FNAME%
</p>
</li>
</ol></div>
</li>
<li>
<p>
refdb: Add export of csv, json and sexp
</p>
</li>
<li>
<p>
Convert to using call-with-environment-variables where possible. Should allow handling of parallel runs in same process.
</p>
</li>
<li>
<p>
Re-work text interface wizards. Several bugs on record. Possibly convert to gui based.
</p>
</li>
<li>
<p>
Add to testconfig requirements section; launchlimiter scriptname, calls scriptname to check if ok to launch test
</p>
</li>
<li>
<p>
Refactor Run Summary view, currently very clumsy
</p>
</li>
<li>
<p>
Add option to show steps in Run Summary view
</p>
</li>
<li>
<p>
Refactor guis for resizeablity
</p>
</li>
<li>
<p>
Add filters to Run Summary view and Run Control view
</p>
</li>
<li>
<p>
Add to megatest.config or testconfig; rerunok STATE/STATUS,STATE/STATUS&#8230;
</p>
</li>
<li>
<p>
Launch gates for diskspace; /path/one&gt;1G,/path/two&gt;200M,/tmp&gt;5G,#{scheme <strong>toppath</strong>}&gt;1G
</p>
</li>
<li>
<p>
Tool tips
</p>
</li>
<li>
<p>
Filters on Run Summary, Summary and Run Control panel
</p>
</li>
<li>
<p>
Built in log viewer (partially implemented)
</p>
</li>
<li>
<p>
Refactor the test control panel
   Help and documentation
</p>
</li>
<li>
<p>
Complete the user manual (I’ve been working on this lately).
</p>
</li>
<li>
<p>
Online help in the gui
   Streamlined install
</p>
</li>
<li>
<p>
Deployed or static build
</p>
</li>
<li>
<p>
Added option to compile IUP (needed for VMs)
</p>
</li>
<li>
<p>
Server side run launching
</p>
</li>
<li>
<p>
Wizards for creating tests, regression areas (current ones are text only and limited).
</p>
</li>
<li>
<p>
Fully functional built in web service (currently you can browse runs but it is very simplistic).
</p>
</li>
<li>
<p>
Gui panels for editing megatest.config and runconfigs.config
</p>
</li>
<li>
<p>
Fully isolated tests (no use of NFS to see regression area files)
</p>
</li>
<li>
<p>
Windows version
</p>
</li>
</ol></div>
</div>
</div>
<div class="sect1">
<h2 id="_installation">Installation</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_dependencies">Dependencies</h3>
<div class="paragraph"><p>Chicken scheme and a number of "eggs" are required for building
Megatest. See the script installall.sh in the utils directory of the
source distribution for an automated way to install everything
needed for building Megatest on Linux.</p></div>
Megatest. In the v1.66 and beyond assistance to create the build
system is built into the Makefile.</p></div>
<div class="listingblock">
<div class="title">Installation steps (overview)</div>
<div class="content monospaced">
<pre>./configure
make chicken
setup.sh make -j install</pre>
</div></div>
<div class="paragraph"><p>Or install the needed build system manually:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Chicken scheme from <a href="http://call-cc.org">http://call-cc.org</a>
</p>
</li>
<li>
<p>
IUP from <a href="http://webserver2.tecgraf.puc-rio.br/iup/">http://webserver2.tecgraf.puc-rio.br/iup/</a>
</p>
</li>
<li>
<p>
CD from <a href="http://webserver2.tecgraf.puc-rio.br/cd/">http://webserver2.tecgraf.puc-rio.br/cd/</a>
</p>
</li>
<li>
<p>
IM from <a href="https://webserver2.tecgraf.puc-rio.br/im/">https://webserver2.tecgraf.puc-rio.br/im/</a>
</p>
</li>
<li>
<p>
ffcall from <a href="http://webserver2.tecgraf.puc-rio.br/iup/">http://webserver2.tecgraf.puc-rio.br/iup/</a>
</p>
</li>
<li>
<p>
Nanomsg from <a href="https://nanomsg.org/">https://nanomsg.org/</a> (NOTE: Plan is to eliminate nanomsg dependency).
</p>
</li>
<li>
<p>
Needed eggs (look at the eggs lists in the Makefile)
</p>
</li>
</ol></div>
<div class="paragraph"><p>Then follow these steps:</p></div>
<div class="listingblock">
<div class="title">Installation steps (self-built chicken scheme build system)</div>
<div class="content monospaced">
<pre>./configure
make -j install</pre>
</div></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_getting_started">Getting Started</h2>
<div class="sectionbody">
<div class="listingblock">
2054
2055
2056
2057
2058
2059
2060






















2061
2062
2063
2064
2065
2066
2067
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







# tabled
[itemstable]
A x y
B 1 2

# Yields x/1 y/2</pre>
</div></div>
<div class="listingblock">
<div class="title">Or use files</div>
<div class="content monospaced">
<pre>[itemopts]
slash path/to/file/with/items
# or
space path/to/file/with/items</pre>
</div></div>
<div class="listingblock">
<div class="title">File format for / delimited</div>
<div class="content monospaced">
<pre>key1/key2/key3
val1/val2/val2
...</pre>
</div></div>
<div class="listingblock">
<div class="title">File format for space delimited</div>
<div class="content monospaced">
<pre>key1 key2 key3
val1 val2 val2
...</pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_requirements_section">Requirements section</h3>
<div class="listingblock">
<div class="title">Header</div>
<div class="content monospaced">
<pre>[requirements]</pre>
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
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







-
-
-
+
+
+
+
+
+
+
+
+


















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







<h3 id="_disks">Disks</h3>
<div class="paragraph"><p>A disks section in testconfig will override the disks section in
megatest.config. This can be used to allocate disks on a per-test or per item
basis.</p></div>
</div>
<div class="sect2">
<h3 id="_controlled_waiver_propagation">Controlled waiver propagation</h3>
<div class="paragraph"><p>If test is FAIL and previous test in run with same MT_TARGET is WAIVED then apply the following rules from the testconfig:
If a waiver check is specified in the testconfig apply the check and if it passes then set this FAIL to WAIVED</p></div>
<div class="paragraph"><p>Waiver check has two parts, 1) a list of waiver, rulename, filepatterns and 2) the rulename script spec (note that "diff" and "logpro" are predefined)</p></div>
<div class="paragraph"><p>If test is FAIL and previous test in run with same MT_TARGET is WAIVED
or if the test/itempath is listed under the matching target in the
waivers roll forward file (see below for file spec) then apply the
following rules from the testconfig: If a waiver check is specified in
the testconfig apply the check and if it passes then set this FAIL to
WAIVED</p></div>
<div class="paragraph"><p>Waiver check has two parts, 1) a list of waiver, rulename,
filepatterns and 2) the rulename script spec (note that "diff" and
"logpro" are predefined)</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>###### EXAMPLE FROM testconfig #########
# matching file(s) will be diff'd with previous run and logpro applied
# if PASS or WARN result from logpro then WAIVER state is set
#
[waivers]
# logpro_file    rulename      input_glob
waiver_1         logpro        lookittmp.log

[waiver_rules]

# This builtin rule is the default if there is no &lt;waivername&gt;.logpro file
# diff   diff %file1% %file2%

# This builtin rule is applied if a &lt;waivername&gt;.logpro file exists
# logpro diff %file1% %file2% | logpro %waivername%.logpro %waivername%.html</pre>
</div></div>
<div class="sect3">
<h4 id="_waiver_roll_forward_files">Waiver roll-forward files</h4>
<div class="paragraph"><p>To transfer waivers from one Megatest area to another it is possible
to dump waivers into a file and reference that file in another area.</p></div>
<div class="listingblock">
<div class="title">Dumping the waivers</div>
<div class="content monospaced">
<pre>megatest -list-waivers -runname %-a &gt; mywaivers.dat</pre>
</div></div>
<div class="listingblock">
<div class="title">Referencing the saved waivers</div>
<div class="content monospaced">
<pre># In megatest.config, all files listed will be loaded - recomended to use
# variables to select directorys to minimize what gets loaded.
[setup]
waivers-dirs /path/to/waiver/files /another/path/to/waiver/files</pre>
</div></div>
<div class="listingblock">
<div class="title">Waiver files format</div>
<div class="content monospaced">
<pre>[the/target/here]
# comments are fine
testname1/itempath A comment about why it was waived
testname2          A comment for a non-itemized test</pre>
</div></div>
</div>
</div>
<div class="sect2">
<h3 id="_ezsteps">Ezsteps</h3>
<div class="listingblock">
<div class="title">Example ezsteps with logpro rules</div>
<div class="content monospaced">
<pre>[ezsteps]
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
3421
3422
3423
3424
3425
3426
3427


































































































































































































































































































































































3428
3429
3430
3431
3432
3433
3434
3435
3436
3437



3438
3439
3440
3441
3442
3443
3444







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-










-
-
-
+
+
+




<div class="sectionbody">
<div class="imageblock graphviz">
<div class="content">
<img src="server.png" alt="server.png">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_road_map">Road Map</h2>
<div class="sectionbody">
<div class="paragraph"><p>Note 1: This road-map continues to evolve and subject to change without notice.</p></div>
<div class="sect2">
<h3 id="_here_is_a_smattering_of_ideas_for_megatest_2_0">Here is a smattering of ideas for Megatest 2.0</h3>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME
</p>
</li>
</ol></div>
<div class="listingblock">
<div class="content monospaced">
<pre>[db]
api legacy|new</pre>
</div></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
One big lesson from the 1.63-1.65 generation was that the main.db, 1.db … model was really good at scaling. I’d like to combine that model with the current also-very-good model. Obviously this is a disruptive change. I think making the old model the default and the new model an option for at least one generation would be fair.
</p>
</li>
<li>
<p>
Rigorous megatest.config and runconfig.config caching.
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
Cache the configs in $MT_RUNPATH
</p>
</li>
<li>
<p>
Following invocations of –run, -rerun* will calculate the new config but only overwrite the cached file IF changed
</p>
</li>
</ol></div>
</li>
<li>
<p>
If the cached file changes ALL existing tests go from COMPLETED &#8594; STALE, I’m not sure what to do about RUNNING tests
</p>
</li>
<li>
<p>
!VARS in runconfigs are not exported to the environment. They are accessed via rget as if the ! was not there.
</p>
</li>
<li>
<p>
Per test copy commands (crude example below is not correct).
</p>
</li>
</ol></div>
<div class="listingblock">
<div class="content monospaced">
<pre>[testcopy]
%/iind% unison SRC DEST
% cp –r SRC DEST</pre>
</div></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Test management via pkts (optional?)
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
Control pkt types: run, kill, rerunclean, clean, archive, status?
</p>
</li>
<li>
<p>
Status pkt types: ack, step, status_change
</p>
</li>
</ol></div>
</li>
<li>
<p>
Add nanomsg as a transport option
.
</p>
</li>
</ol></div>
</div>
<div class="sect2">
<h3 id="_rfc_m01_add_ability_to_move_runs_to_other_areas">RFC M01: Add ability to move runs to other Areas</h3>
<div class="paragraph"><p><strong>Purpose</strong>: allow shrinking megatest.db data by moving runs to an alternate
 Megatest area with same keys.</p></div>
<div class="paragraph"><p><strong>Method</strong>: extend db sync to take a different megatest area as a destination.</p></div>
<div class="paragraph"><p><strong>Design</strong>:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
add param -destination [area|path]. when specified runs are copied to new
  area and removed from local db.
</p>
</li>
<li>
<p>
the data move would involve these steps
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
copy the run data to destination area megatest.db
</p>
</li>
<li>
<p>
mark the run records as deleted, do not remove the run data on disk
</p>
</li>
</ol></div>
</li>
<li>
<p>
accessing the data would be by running dashboard in the satellite area
</p>
</li>
<li>
<p>
future versions of Megatest dashboard should support displaying areas in a
  merged way.
</p>
</li>
<li>
<p>
some new controls would be supported in the config
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
[setup] &#8658; allow-runs [no|yes]  &#8656;= used to disallow runs
</p>
</li>
<li>
<p>
[setup] &#8658; auto-migrate=[areaname|path]  &#8656;= used to automatically
   migrate data to a satellite area.
</p>
</li>
</ol></div>
</li>
</ol></div>
<div class="paragraph"><p><strong>Branch</strong>: This work is taking place on branch v1.65-reduce-records</p></div>
</div>
<div class="sect2">
<h3 id="_rfc_m02_move_data_into_completed_runs_db">RFC M02: Move data into completed-runs.db</h3>
<div class="paragraph"><p><strong>Purpose</strong>: shrink megatest.db data to enable lower load and higher performance.</p></div>
<div class="paragraph"><p><strong>Method</strong>: add a completed-runs.db and automatically move runs data from megatest.db to that db</p></div>
<div class="paragraph"><p><strong>Design</strong>:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
completed-runs.db is a full megatest database with complete schema
</p>
</li>
<li>
<p>
the data move would involve these steps
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
copy the run data to completed-runs.db
</p>
</li>
<li>
<p>
remove the run data, first from /tmp/…/megatest.db and /tmp/…/megatest_ref.db, followed by megatest.db
</p>
</li>
</ol></div>
</li>
<li>
<p>
accessing the data would be unchanged for most operations.
</p>
</li>
<li>
<p>
a mode -full-db will be added which when specified would attach the completed-runs.db to megatest.db before doing the query
</p>
</li>
<li>
<p>
mechanisms for moving runs to/from the megatest.db would be added
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
-reduce-records &#8658; move runs to completed-runs.db
</p>
</li>
<li>
<p>
-restore-records &#8658; move runs from completed-runs.db to megatest.db
</p>
</li>
</ol></div>
</li>
</ol></div>
<div class="paragraph"><p><strong>Branch</strong>: This work is taking place on branch v1.65-reduce-records</p></div>
</div>
<div class="sect2">
<h3 id="_rfc_m03_automatic_homehost_migrations">RFC M03: Automatic homehost migrations</h3>
<div class="paragraph"><p><strong>Purpose</strong>: Automatically migrate homehost.</p></div>
<div class="paragraph"><p><strong>Method</strong>: Check that there are no tests running, launched or remotehoststart in past ½ hour then if not on homehost migrate the db to current host</p></div>
<div class="paragraph"><p><strong>Design</strong>:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Check that the system is quiescent, i.e. that there are no runs in flight or recently run
</p>
</li>
<li>
<p>
Create a lock
</p>
</li>
<li>
<p>
Migrate the /tmp cache db to the current host
</p>
</li>
<li>
<p>
Update the .homehost file
</p>
</li>
<li>
<p>
Remove the lock
</p>
</li>
</ol></div>
<div class="paragraph"><p><strong>Branch</strong>: This work not yet started</p></div>
</div>
<div class="sect2">
<h3 id="_architecture_refactor">Architecture Refactor</h3>
<div class="sect3">
<h4 id="_goals">Goals</h4>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Reduce load on the file system. Sqlite3 files on network filesystem can be
  a burden. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Reduce number of servers and frequency of start/stop. This is mostly an
  issue of clutter but also a reduction in "moving parts". <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Coalesce activities to a single home host where possible. Give the user
  feedback that they have started the dashboard on a host other than the
  home host. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Reduce number of processes involved in managing running tests.
</p>
</li>
</ol></div>
</div>
<div class="sect3">
<h4 id="_changes_needed">Changes Needed</h4>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
ACID compliant db will be on /tmp and synced to megatest.db with a five
  second max delay. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Read/writes to db for processes on homehost will go direct to /tmp
  megatest.db file. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Read/wites fron non-homehost processes will go through one server. Bulk
  reads (e.g. for dashboard or list-runs) will be cached on the current host
  in /tmp and synced from the home megatest.db in the testsuite area. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Db syncs rely on the target db file timestame minus some margin. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Since bulk reads do not use the server we can switch to simple RPC for the
  network transport. <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Test running manager process extended to manage multiple running tests.
</p>
</li>
</ol></div>
</div>
</div>
<div class="sect2">
<h3 id="_current_items">Current Items</h3>
<div class="sect3">
<h4 id="_ww05_migrate_to_inmem_db">ww05 - migrate to inmem-db</h4>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Switch to inmem db with fast sync to on disk db&#8217;s <span class="green">[DONE]</span>
</p>
</li>
<li>
<p>
Server polls tasks table for next action
</p>
<div class="olist loweralpha"><ol class="loweralpha">
<li>
<p>
Task table used for tracking runner process <span class="red">[Replaced by mtutil]</span>
</p>
</li>
<li>
<p>
Task table used for jobs to run <span class="red">[Replaced by mtutil]</span>
</p>
</li>
<li>
<p>
Task table used for queueing runner actions (remove runs,
   cleanRunExecute, etc)  <span class="red">[Replaced by mtutil</span>]
</p>
</li>
</ol></div>
</li>
</ol></div>
<div class="paragraph"><p>shifting, note that the preceding blank line is needed.</p></div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_index">Index</h2>
<div class="sectionbody">
</div>
</div>
</div>
<div id="footnotes"><hr></div>
<div id="footer">
<div id="footer-text">
Version 1.0<br>
Last updated
 2020-05-06 12:11:12 UTC
Version 1.5<br>
Last updated 2020-07-22 14:21:46 PDT
 2020-06-29 20:32:05 MST
</div>
</div>
</body>
</html>

Modified docs/manual/megatest_manual.txt from [2589d78a96] to [69ab724537].

1
2
3
4

5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23



-
+











-
+







The Megatest Users Manual
=========================
Matt Welland <matt@kiatoa.com>
v1.0, April 2012
v1.5, June 2020
:doctype: book


[preface]
Preface
-------

This book is organised as three sub-books; getting started, writing tests and reference.

.License
----------------------------
    Copyright 2006-2017, Matthew Welland.
    Copyright 2006-2020, Matthew Welland.

    This document is part of Megatest.

    Megatest 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 3 of the License, or
    (at your option) any later version.
36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50







-
+







-------------

The Megatest project was started for two reasons, the first was an
immediate and pressing need for a generalized tool to manage a suite
of regression tests and the second was the fact that I had written or
maintained several such tools at different companies over the years. I
thought a single open source tool, flexible enough to meet the needs
of any team doing continuous integrating and or running a complex
of any team doing continuous integration and or running a complex
suite of tests for release qualification would solve some problems for
me and for others.

 -- Matt Welland, original author of the Megatest tool suite.

Megatest Design Philosophy
--------------------------
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
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







+
+










+



-









-
+

-
+







which can launch jobs on local and remote Linux hosts. Currently
megatest uses the network filesystem to call home to your master
sqlite3 database. Megatest has been used with the Intel Netbatch and
lsf (also known as openlava) batch systems and it should be
straightforward to use it with other similar systems.

include::overview.txt[]

include::plan.txt[]

include::installation.txt[]

include::getting_started.txt[]

include::study_plan.txt[]

// :leveloffset: 0

include::writing_tests.txt[]

include::howto.txt[]

include::reference.txt[]


Megatest Internals
------------------

["graphviz", "server.png"]
----------------------------------------------------------------------
include::server.dot[]
----------------------------------------------------------------------

include::plan.txt[]
// include::plan.txt[]
// to allow the getting_started.txt to be a stand-alone document use level
shifting, note that the preceding blank line is needed.
// shifting, note that the preceding blank line is needed.
// :leveloffset: 2


// [appendix]
// Example Appendix
// ================
// One or more optional appendixes go here at section level zero.

Modified docs/manual/plan.txt from [660a99057c] to [b8930eff65].

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






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
-
-
-















-
+

+
+
-
+
+
+
+
+
+

+
-
-
+
+
+
+


+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




-
+





-
-
-
-
-
+
-
-
+
-

-
-
+
+
-
-
-
-
-













-
-
+
-
-

-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
-

-
-
-
+
-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+




+

+

+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
+
+
+
Road Map
--------

// This file is part of Megatest.
// 
//     Megatest 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 3 of the License, or
//     (at your option) any later version.
// 
//     Megatest 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 Megatest.  If not, see <http://www.gnu.org/licenses/>.

// Copyright 2006-2012, Matthew Welland.
// Copyright 2006-2020, Matthew Welland.

TODO / Road Map
---------------
Note 1: This road-map continues to evolve and subject to change without notice.

Note: This road-map is a wish list and not a formal plan. Items are in
rough priority but are subject to change. Development is driven by
user requests, developer "itch" and bug reports. Please contact
matt@kiatoa.com with requests or bug reports. Requests from inside
Intel generally take priority.

Dashboard and runs
Here is a smattering of ideas for Megatest 2.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

. Multi-area dashboard view

Tests Support

. Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME
. Improve [script], especially indent handling
----------------
[db]
api legacy|new
----------------
. One big lesson from the 1.63-1.65 generation was that the main.db, 1.db … model was really good at scaling. I’d like to combine that model with the current also-very-good model. Obviously this is a disruptive change. I think making the old model the default and the new model an option for at least one generation would be fair.
.   Rigorous megatest.config and runconfig.config caching.

Scalability

. Overflow database methodology - combine the best of the v1.63
  multi-db approach and the current db-in-tmp approach (currently
  slowness can be seen when number of tests in a db goes over 50-100k,
  with the overflow db it will be able to handle 1000's of runs with
  50-100k tests per run). High priority - goal is to complete this by
  20Q3.

Mtutils/CI

. Enable mtutil calls from dashboard (for remote control)
. Logs browser (esp. for surfacing mtutil related activities)
. Embed ftfplan for distributed automation, completed activities trigger QA runs which trigger deployment etc.
. Jenkins junit XML support [DONE]
. Add output flushing in teamcity support

Build system

. ./configure => ubuntu, sles11, sles12, rh7 [WIP]
. Switch to using simple runs query everywhere
. Add end_time to runs and add a rollup call that sets state, status and end_time

Code refactoring/quality/performance

. Switch to scsh-process pipeline management for job execution/control
. Use call-with-environment-variables where possible.

Migration to inmem db and or overflow db

. Re-work the dbstruct data structure?
.. [ run-id.db inmemdb last-mod last-read last-sync inuse ]

Some ideas for Megatest 2.0

.   Aggressive megatest.config and runconfig.config caching.
..  Cache the configs in $MT_RUNPATH
..  Following invocations of –run, -rerun* will calculate the new config but only overwrite the cached file IF changed
. If the cached file changes ALL existing tests go from COMPLETED -> STALE, I’m not sure what to do about RUNNING tests
. !VARS in runconfigs are not exported to the environment. They are accessed via rget as if the ! was not there.
. Per test copy commands (crude example below is not correct).
. Per test copy commands (example is incomplete).
----------------
[testcopy]
%/iind% unison SRC DEST
% cp –r SRC DEST
----------------
.	Test management via pkts (optional?)
..	Control pkt types: run, kill, rerunclean, clean, archive, status?
..	Status pkt types: ack, step, status_change
.	Add nanomsg as a transport option
.	


RFC M01: Add ability to move runs to other Areas
Add ability to move runs to other Areas (overlaps with overflow db system)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*Purpose*: allow shrinking megatest.db data by moving runs to an alternate
 Megatest area with same keys.
. allow shrinking megatest.db data by moving runs to an alternate
  Megatest area with same keys.

*Method*: extend db sync to take a different megatest area as a destination.

*Design*:

. add param -destination [area|path]. when specified runs are copied to new
  area and removed from local db.
. the data move would involve these steps
.. copy the run data to destination area megatest.db
.. mark the run records as deleted, do not remove the run data on disk
. accessing the data would be by running dashboard in the satellite area
. future versions of Megatest dashboard should support displaying areas in a
  merged way.
. some new controls would be supported in the config
.. [setup] => allow-runs [no|yes]  <== used to disallow runs
.. [setup] => auto-migrate=[areaname|path]  <== used to automatically
   migrate data to a satellite area.

*Branch*: This work is taking place on branch v1.65-reduce-records

Eliminate ties to homehost (part of overflow db system)
RFC M02: Move data into completed-runs.db
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*Purpose*: shrink megatest.db data to enable lower load and higher performance.

. Server creates captain pkt
*Method*: add a completed-runs.db and automatically move runs data from megatest.db to that db

*Design*:

. completed-runs.db is a full megatest database with complete schema
. the data move would involve these steps
.. copy the run data to completed-runs.db
.. remove the run data, first from /tmp/…/megatest.db and /tmp/…/megatest_ref.db, followed by megatest.db
. accessing the data would be unchanged for most operations.
. a mode -full-db will be added which when specified would attach the completed-runs.db to megatest.db before doing the query
. mechanisms for moving runs to/from the megatest.db would be added
.. -reduce-records => move runs to completed-runs.db
.. -restore-records => move runs from completed-runs.db to megatest.db

*Branch*: This work is taking place on branch v1.65-reduce-records

RFC M03: Automatic homehost migrations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*Purpose*: Automatically migrate homehost.

*Method*: Check that there are no tests running, launched or remotehoststart in past ½ hour then if not on homehost migrate the db to current host

*Design*:

. Check that the system is quiescent, i.e. that there are no runs in flight or recently run
. Create a lock
. Create a lock in the db
. Migrate the /tmp cache db to the current host
. Update the .homehost file
. Remove the lock

. Relinquish db when done
*Branch*: This work not yet started

Architecture Refactor
~~~~~~~~~~~~~~~~~~~~~

Tasks - better management of run manager processes etc.
Goals
^^^^^

. Reduce load on the file system. Sqlite3 files on network filesystem can be
  a burden. [green]#[DONE]#
. Reduce number of servers and frequency of start/stop. This is mostly an
  issue of clutter but also a reduction in "moving parts". [green]#[DONE]#
. Coalesce activities to a single home host where possible. Give the user
  feedback that they have started the dashboard on a host other than the
  home host. [green]#[DONE]#
. Reduce number of processes involved in managing running tests.

Changes Needed
^^^^^^^^^^^^^^

. ACID compliant db will be on /tmp and synced to megatest.db with a five
  second max delay. [green]#[DONE]#
. Read/writes to db for processes on homehost will go direct to /tmp
  megatest.db file. [green]#[DONE]#
. Read/wites fron non-homehost processes will go through one server. Bulk
  reads (e.g. for dashboard or list-runs) will be cached on the current host
  in /tmp and synced from the home megatest.db in the testsuite area. [green]#[DONE]#
. Db syncs rely on the target db file timestame minus some margin. [green]#[DONE]#
. Since bulk reads do not use the server we can switch to simple RPC for the
  network transport. [green]#[DONE]#
. Test running manager process extended to manage multiple running tests.

Current Items
~~~~~~~~~~~~~

ww05 - migrate to inmem-db
^^^^^^^^^^^^^^^^^^^^^^^^^^

. Switch to inmem db with fast sync to on disk db's [green]#[DONE]#
. Server polls tasks table for next action
. adjutant queries tasks table for next action [red]#[Migrate into mtutil]#
.. Task table used for tracking runner process [red]#[Replaced by mtutil]#
.. Task table used for jobs to run [red]#[Replaced by mtutil]#
.. Task table used for queueing runner actions (remove runs,
   cleanRunExecute, etc)  [red]#[Replaced by mtutil#]
. adjutant (server/task dispatch/execution manager)  

Stale propagation

 . Mark dependent tests for clean/rerun -rerun-downstream
 . On run start check for defunct tests in RUNNING, LAUNCHED or REMOTEHOSTSTART and correct or notify
 . Fix: refresh of gui sometimes fails on last item (race condition?)
// ww32
// ~~~~
// 
// . Rerun step and or subsequent steps from gui
// . Refresh test area files from gui
// . Clean and re-run button
// . Clean up STATE and STATUS handling.
// .. Dashboard and Test control panel are reverse order - choose and fix
// .. Move seldom used states and status to drop down selector
// . Access test control panel when clicking on Run Summary tests
// . Feature: -generate-index-tree
// . Change specifing of state and status to use STATE1/STATUS1,STATE2/STATUS2
// 
 
Bin list

 . Rerun step and or subsequent steps from gui [DONE?]
 . Refresh test area files from gui
 . Clean and re-run button
 . Clean up STATE and STATUS handling.
 .. Dashboard and Test control panel are reverse order - choose and fix
 .. Move seldom used states and status to drop down selector
 . Access test control panel when clicking on Run Summary tests
 . Feature: -generate-index-tree
 . Change specifing of state and status to use STATE1/STATUS1,STATE2/STATUS2
 
// ww33
// ~~~~
// 
// . http api available for use with Perl, Ruby etc. scripts
// . megatest.config setup entries for:
// .. run launching (e.g. /bin/sh %CMD% > /dev/null)
// .. browser "konqueror %FNAME%
 . rest api available for use with Perl, Ruby etc. scripts
 . megatest.config setup entries for:
 .. run launching (e.g. /bin/sh %CMD% > /dev/null)
 .. browser "konqueror %FNAME%
// 
// ww34
// ~~~~
// 
// . Mark dependent tests for clean/rerun -rerun-downstream
// . On run start check for defunct tests in RUNNING, LAUNCHED or REMOTEHOSTSTART and correct or notify
// . Fix: refresh of gui sometimes fails on last item (race condition?)
// 
// ww35
// ~~~~
// 
// . refdb: Add export of csv, json and sexp
// . Convert to using call-with-environment-variables where possible. Should allow handling of parallel runs in same process.
// . Re-work text interface wizards. Several bugs on record. Possibly convert to gui based.
// . Add to testconfig requirements section; launchlimiter scriptname, calls scriptname to check if ok to launch test
// . Refactor Run Summary view, currently very clumsy
// . Add option to show steps in Run Summary view
// 
// ww36
// ~~~~

 . refdb: Add export of csv, json and sexp
 . Convert to using call-with-environment-variables where possible. Should allow handling of parallel runs in same process.
// 
// . Refactor guis for resizeablity
// . Add filters to Run Summary view and Run Control view
// . Add to megatest.config or testconfig; rerunok STATE/STATUS,STATE/STATUS...
// . Launch gates for diskspace; /path/one>1G,/path/two>200M,/tmp>5G,#{scheme *toppath*}>1G
 . Re-work text interface wizards. Several bugs on record. Possibly convert to gui based.
 . Add to testconfig requirements section; launchlimiter scriptname, calls scriptname to check if ok to launch test
 . Refactor Run Summary view, currently very clumsy
 . Add option to show steps in Run Summary view
  . Refactor guis for resizeablity
 . Add filters to Run Summary view and Run Control view
 . Add to megatest.config or testconfig; rerunok STATE/STATUS,STATE/STATUS...
 . Launch gates for diskspace; /path/one>1G,/path/two>200M,/tmp>5G,#{scheme *toppath*}>1G
// 
// Bin List
// ~~~~~~~~
// 
// .	Quality improvements
// ..	Server stutters occasionally
// ..	Large number of items or tests still has some issues.
// ..	Code refactoring
// ..	Replace remote process with true API using json (supports Web app also)
// .	Streamline the gui
// ..	Everything resizable
// ..	Less clutter
// ..	Tool tips
// ..	Filters on Run Summary, Summary and Run Control panel
// ..	Built in log viewer (partially implemented)
// ..	Refactor the test control panel
// .	Help and documentation
// ..	Complete the user manual (I’ve been working on this lately).
// ..	Online help in the gui
// .	Streamlined install
// ..	Deployed version (download a location independent ready to run binary bundle)
 . Tool tips
 . Filters on Run Summary, Summary and Run Control panel
 . Built in log viewer (partially implemented)
 . Refactor the test control panel
   Help and documentation
 . Complete the user manual (I’ve been working on this lately).
 . Online help in the gui
   Streamlined install
 . Deployed or static build
// ..	Install Makefile (in progress, needed for Mike to install on VMs)
// ..	Added option to compile IUP (needed for VMs)
// .	Server side run launching
 . Added option to compile IUP (needed for VMs)
 . Server side run launching
// .	Support for re-running, cleaning etc. of individual steps (ezsteps makes this very easy to implement).
// .	Launch process needs built in daemonizing (easy to do, just need to test it thoroughly).
// .	Wizards for creating tests, regression areas (current ones are text only and limited).
// .	Fully functional built in web service (currently you can browse runs but it is very simplistic).
 . Wizards for creating tests, regression areas (current ones are text only and limited).
 . Fully functional built in web service (currently you can browse runs but it is very simplistic).
// .	Wildcards in runconfigs: e.g. [p1271/9/%/%]
// .	Gui panels for editing megatest.config and runconfigs.config
// .	Fully isolated tests (no use of NFS to see regression area files)
// .	Windows version
 . Gui panels for editing megatest.config and runconfigs.config
 . Fully isolated tests (no use of NFS to see regression area files)
 . Windows version

Modified docs/manual/reference.txt from [d257a69331] to [6aa04b6eea].

322
323
324
325
326
327
328





















329
330
331
332
333
334
335
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







[itemstable]
A x y
B 1 2

# Yields x/1 y/2
------------------

.Or use files
------------------
[itemopts]
slash path/to/file/with/items
# or
space path/to/file/with/items
------------------

.File format for / delimited
------------------
key1/key2/key3
val1/val2/val2
...
------------------

.File format for space delimited
------------------
key1 key2 key3
val1 val2 val2
...
------------------

Requirements section
~~~~~~~~~~~~~~~~~~~~

.Header
-------------------
[requirements]
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
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







-
-
+
+
+
+
+
+

-
+
+
+



















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







A disks section in testconfig will override the disks section in
megatest.config. This can be used to allocate disks on a per-test or per item
basis.

Controlled waiver propagation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If test is FAIL and previous test in run with same MT_TARGET is WAIVED then apply the following rules from the testconfig:
If a waiver check is specified in the testconfig apply the check and if it passes then set this FAIL to WAIVED
If test is FAIL and previous test in run with same MT_TARGET is WAIVED
or if the test/itempath is listed under the matching target in the
waivers roll forward file (see below for file spec) then apply the
following rules from the testconfig: If a waiver check is specified in
the testconfig apply the check and if it passes then set this FAIL to
WAIVED

Waiver check has two parts, 1) a list of waiver, rulename, filepatterns and 2) the rulename script spec (note that "diff" and "logpro" are predefined)
Waiver check has two parts, 1) a list of waiver, rulename,
filepatterns and 2) the rulename script spec (note that "diff" and
"logpro" are predefined)

-----------------
###### EXAMPLE FROM testconfig #########
# matching file(s) will be diff'd with previous run and logpro applied
# if PASS or WARN result from logpro then WAIVER state is set
#
[waivers]
# logpro_file    rulename      input_glob
waiver_1         logpro        lookittmp.log

[waiver_rules]

# This builtin rule is the default if there is no <waivername>.logpro file
# diff   diff %file1% %file2%

# This builtin rule is applied if a <waivername>.logpro file exists
# logpro diff %file1% %file2% | logpro %waivername%.logpro %waivername%.html
-----------------

Waiver roll-forward files
^^^^^^^^^^^^^^^^^^^^^^^^^

To transfer waivers from one Megatest area to another it is possible
to dump waivers into a file and reference that file in another area.

.Dumping the waivers
---------------------------
megatest -list-waivers -runname %-a > mywaivers.dat
---------------------------

.Referencing the saved waivers
---------------------------
# In megatest.config, all files listed will be loaded - recomended to use
# variables to select directorys to minimize what gets loaded.
[setup]
waivers-dirs /path/to/waiver/files /another/path/to/waiver/files
---------------------------

.Waiver files format
---------------------------
[the/target/here]
# comments are fine
testname1/itempath A comment about why it was waived
testname2          A comment for a non-itemized test 
---------------------------

Ezsteps
~~~~~~~

.Example ezsteps with logpro rules
-----------------
[ezsteps]
lookittmp   ls /tmp

Modified docs/manual/server.png from [43882638fe] to [da85cb6703].

cannot compute difference between binary files

Added docs/manual/subrun-opt-stuff.fig version [118dffbc3b].

































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#FIG 3.2  Produced by xfig version 3.2.5-alpha5
Landscape
Center
Inches
Letter  
100.00
Single
-2
1200 2
6 150 5475 1650 9675
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 150 5475 1650 5475 1650 9675 150 9675 150 5475
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 225 5550 1575 5550 1575 6075 225 6075 225 5550
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 225 6150 1575 6150 1575 6675 225 6675 225 6150
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 225 6750 1575 6750 1575 7275 225 7275 225 6750
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 225 7350 1575 7350 1575 7875 225 7875 225 7350
-6
6 3900 5550 5400 9750
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 3900 5550 5400 5550 5400 9750 3900 9750 3900 5550
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 3975 5625 5325 5625 5325 6150 3975 6150 3975 5625
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 3975 6225 5325 6225 5325 6750 3975 6750 3975 6225
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 3975 6825 5325 6825 5325 7350 3975 7350 3975 6825
2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 3975 7425 5325 7425 5325 7950 3975 7950 3975 7425
-6
6 8325 5700 9525 9825
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 8325 6000 9525 6000 9525 6825 8325 6825 8325 6000
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 8325 6900 9525 6900 9525 7725 8325 7725 8325 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 8325 7800 9525 7800 9525 8625 8325 8625 8325 7800
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 8325 8700 9525 8700 9525 9525 8325 9525 8325 8700
4 0 0 50 -1 0 12 0.0000 4 120 405 8475 5850 tests\001
4 0 0 50 -1 0 12 0.0000 4 165 600 8400 6375 startup\001
4 0 0 50 -1 0 12 0.0000 4 195 375 8400 7275 opt1\001
4 0 0 50 -1 0 12 0.0000 4 195 375 8400 8025 opt2\001
4 0 0 50 -1 0 12 0.0000 4 195 585 8400 9075 opt1v2\001
4 0 0 50 -1 0 12 0.0000 4 15 180 8775 9825 ...\001
-6
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 4800 450 6000 450 6000 1275 4800 1275 4800 450
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 1050 2100 2250 2100 2250 2925 1050 2925 1050 2100
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 2925 2100 4125 2100 4125 2925 2925 2925 2925 2100
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 4950 2100 6150 2100 6150 2925 4950 2925 4950 2100
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 7200 2100 8400 2100 8400 2925 7200 2925 7200 2100
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 9375 2100 10575 2100 10575 2925 9375 2925 9375 2100
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 2025 4050 3225 4050 3225 4875 2025 4875 2025 4050
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 6525 3975 7725 3975 7725 4800 6525 4800 6525 3975
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 5400 1275 1500 2100
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 5325 1275 3525 2100
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 5325 1275 5475 2100
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 5250 1275 7800 2100
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 5325 1275 9900 2100
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 1650 2925 2550 4050
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 3525 2925 2550 4050
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 3525 2925 7050 3975
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 5550 2925 6975 3975
2 2 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5
	 750 1650 10875 1650 10875 3450 750 3450 750 1650
2 1 0 1 0 7 50 -1 -1 3.000 0 0 -1 1 0 3
	0 0 1.00 60.00 120.00
	 1050 2700 450 2700 450 5550
2 1 0 1 0 7 50 -1 -1 3.000 0 0 -1 1 0 3
	0 0 1.00 60.00 120.00
	 4125 2700 4650 2700 4650 5550
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 2100 5475 3300 5475 3300 8700 2100 8700 2100 5475
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
	 2175 6000 3225 6000 3225 6525 2175 6525 2175 6000
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 1500 6375 2325 6300
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 4200 6525 3000 6225
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 7800 2925 7050 3975
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
	0 0 1.00 60.00 120.00
	 9975 2925 7125 3900
4 0 0 50 -1 0 12 0.0000 4 165 600 4875 975 startup\001
4 0 0 50 -1 0 12 0.0000 4 15 180 5325 2550 ...\001
4 0 0 50 -1 0 12 0.0000 4 195 2100 900 675 p1278/2/cpdk_r0.5/none\001
4 0 0 50 -1 0 12 0.0000 4 150 675 150 2475 subruns\001
4 0 0 50 -1 0 12 0.0000 4 195 585 2175 4500 opt1v2\001
4 0 0 50 -1 0 12 0.0000 4 195 375 1200 2625 opt1\001
4 0 0 50 -1 0 12 0.0000 4 195 375 3150 2550 opt2\001
4 0 0 50 -1 0 12 0.0000 4 150 2100 3075 150 SUBRUN for Multistack\001
4 0 0 50 -1 0 12 0.0000 4 150 225 300 6375 ftc\001
4 0 0 50 -1 0 12 0.0000 4 150 225 4050 6450 ftc\001
4 0 0 50 -1 0 12 0.0000 4 195 2220 600 5250 p1278/2/cpdk_r0.5/x-opt1\001
4 0 0 50 -1 0 12 0.0000 4 195 2220 4800 5325 p1278/2/cpdk_r0.5/y-opt2\001

Added example2/rx.v version [936aacf70e].










































































































































































































































































































































































































































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
//
// Filename: 	rxuartlite.v
//
// Project:	wbuart32, a full featured UART with simulator
//
// Purpose:	Receive and decode inputs from a single UART line.
//
//
//	To interface with this module, connect it to your system clock,
//	and a UART input.  Set the parameter to the number of clocks per
//	baud.  When data becomes available, the o_wr line will be asserted
//	for one clock cycle.
//
//	This interface only handles 8N1 serial port communications.  It does
//	not handle the break, parity, or frame error conditions.
//
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2020, Gisselquist Technology, LLC
//
// This program is free software (firmware): 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 3 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 MERCHANTIBILITY 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.  (It's in the $(ROOT)/doc directory.  Run make with no
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype	none
//
`define	RXUL_BIT_ZERO		4'h0
`define	RXUL_BIT_ONE		4'h1
`define	RXUL_BIT_TWO		4'h2
`define	RXUL_BIT_THREE		4'h3
`define	RXUL_BIT_FOUR		4'h4
`define	RXUL_BIT_FIVE		4'h5
`define	RXUL_BIT_SIX		4'h6
`define	RXUL_BIT_SEVEN		4'h7
`define	RXUL_STOP		4'h8
`define	RXUL_WAIT		4'h9
`define	RXUL_IDLE		4'hf

module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
	parameter			TIMER_BITS = 10;
`ifdef	FORMAL
	parameter  [(TIMER_BITS-1):0]	CLOCKS_PER_BAUD = 16; // Necessary for formal proof
`else
	parameter  [(TIMER_BITS-1):0]	CLOCKS_PER_BAUD = 868;	// 115200 MBaud at 100MHz
`endif
	localparam			TB = TIMER_BITS;
	input	wire		i_clk;
	input	wire		i_uart_rx;
	output	reg		o_wr;
	output	reg	[7:0]	o_data;


	wire	[(TB-1):0]	half_baud;
	reg	[3:0]		state;

	assign	half_baud = { 1'b0, CLOCKS_PER_BAUD[(TB-1):1] };
	reg	[(TB-1):0]	baud_counter;
	reg			zero_baud_counter;


	// Since this is an asynchronous receiver, we need to register our
	// input a couple of clocks over to avoid any problems with 
	// metastability.  We do that here, and then ignore all but the
	// ck_uart wire.
	reg	q_uart, qq_uart, ck_uart;
	initial	q_uart  = 1'b1;
	initial	qq_uart = 1'b1;
	initial	ck_uart = 1'b1;
	always @(posedge i_clk)
		{ ck_uart, qq_uart, q_uart } <= { qq_uart, q_uart, i_uart_rx };

	// Keep track of the number of clocks since the last change.
	//
	// This is used to determine if we are in either a break or an idle
	// condition, as discussed further below.
	reg	[(TB-1):0]	chg_counter;
	initial	chg_counter = {(TB){1'b1}};
	always @(posedge i_clk)
	if (qq_uart != ck_uart)
		chg_counter <= 0;
	else if (chg_counter != { (TB){1'b1} })
		chg_counter <= chg_counter + 1;

	// Are we in the middle of a baud iterval?  Specifically, are we
	// in the middle of a start bit?  Set this to high if so.  We'll use
	// this within our state machine to transition out of the IDLE
	// state.
	reg	half_baud_time;
	initial	half_baud_time = 0;
	always @(posedge i_clk)
		half_baud_time <= (!ck_uart)&&(chg_counter >= half_baud-1'b1-1'b1);


	initial	state = `RXUL_IDLE;
	always @(posedge i_clk)
	if (state == `RXUL_IDLE)
	begin // Idle state, independent of baud counter
		// By default, just stay in the IDLE state
		state <= `RXUL_IDLE;
		if ((!ck_uart)&&(half_baud_time))
			// UNLESS: We are in the center of a valid
			// start bit
			state <= `RXUL_BIT_ZERO;
	end else if ((state >= `RXUL_WAIT)&&(ck_uart))
		state <= `RXUL_IDLE;
	else if (zero_baud_counter)
	begin
		if (state <= `RXUL_STOP)
			// Data arrives least significant bit first.
			// By the time this is clocked in, it's what
			// you'll have.
			state <= state + 1;
	end

	// Data bit capture logic.
	//
	// This is drastically simplified from the state machine above, based
	// upon: 1) it doesn't matter what it is until the end of a captured
	// byte, and 2) the data register will flush itself of any invalid
	// data in all other cases.  Hence, let's keep it real simple.
	reg	[7:0]	data_reg;
	always @(posedge i_clk)
	if ((zero_baud_counter)&&(state != `RXUL_STOP))
		data_reg <= { qq_uart, data_reg[7:1] };

	// Our data bit logic doesn't need nearly the complexity of all that
	// work above.  Indeed, we only need to know if we are at the end of
	// a stop bit, in which case we copy the data_reg into our output
	// data register, o_data, and tell others (for one clock) that data is
	// available.
	//
	initial	o_wr = 1'b0;
	initial	o_data = 8'h00;
	always @(posedge i_clk)
	if ((zero_baud_counter)&&(state == `RXUL_STOP)&&(ck_uart))
	begin
		o_wr   <= 1'b1;
		o_data <= data_reg;
	end else
		o_wr   <= 1'b0;

	// The baud counter
	//
	// This is used as a "clock divider" if you will, but the clock needs
	// to be reset before any byte can be decoded.  In all other respects,
	// we set ourselves up for CLOCKS_PER_BAUD counts between baud
	// intervals.
	initial	baud_counter = 0;
	always @(posedge i_clk)
	if (((state==`RXUL_IDLE))&&(!ck_uart)&&(half_baud_time))
		baud_counter <= CLOCKS_PER_BAUD-1'b1;
	else if (state == `RXUL_WAIT)
		baud_counter <= 0;
	else if ((zero_baud_counter)&&(state < `RXUL_STOP))
		baud_counter <= CLOCKS_PER_BAUD-1'b1;
	else if (!zero_baud_counter)
		baud_counter <= baud_counter-1'b1;

	// zero_baud_counter
	//
	// Rather than testing whether or not (baud_counter == 0) within our
	// (already too complicated) state transition tables, we use
	// zero_baud_counter to pre-charge that test on the clock
	// before--cleaning up some otherwise difficult timing dependencies.
	initial	zero_baud_counter = 1'b1;
	always @(posedge i_clk)
	if ((state == `RXUL_IDLE)&&(!ck_uart)&&(half_baud_time))
		zero_baud_counter <= 1'b0;
	else if (state == `RXUL_WAIT)
		zero_baud_counter <= 1'b1;
	else if ((zero_baud_counter)&&(state < `RXUL_STOP))
		zero_baud_counter <= 1'b0;
	else if (baud_counter == 1)
		zero_baud_counter <= 1'b1;

`ifdef	FORMAL
`define	FORMAL_VERILATOR
`else
`ifdef	VERILATOR
`define	FORMAL_VERILATOR
`endif
`endif

`ifdef	FORMAL
`define ASSUME	assume
`define ASSERT	assert
`ifdef	VERIFIC
	(* gclk *) wire	gbl_clk;
	global clocking @(posedge gbl_clk); endclocking
`endif


	localparam	F_CKRES = 10;

	(* anyseq *) wire	f_tx_start;
	(* anyconst *) wire	[(F_CKRES-1):0]	f_tx_step;
	reg			f_tx_zclk;
	reg	[(TB-1):0]	f_tx_timer;
	wire	[7:0]		f_rx_newdata;
	reg	[(TB-1):0]	f_tx_baud;
	wire			f_tx_zbaud;

	wire	[(TB-1):0]	f_max_baud_difference;
	reg	[(TB-1):0]	f_baud_difference;
	reg	[(TB+3):0]	f_tx_count, f_rx_count;
	(* anyseq *) wire	[7:0]		f_tx_data;



	wire			f_txclk;
	reg	[1:0]		f_rx_clock;
	reg	[(F_CKRES-1):0]	f_tx_clock;
	reg			f_past_valid, f_past_valid_tx;

	initial	f_past_valid = 1'b0;
	always @(posedge i_clk)
		f_past_valid <= 1'b1;

	initial	f_rx_clock = 3'h0;
	always @($global_clock)
		f_rx_clock <= f_rx_clock + 1'b1;

	always @(*)
		assume(i_clk == f_rx_clock[1]);
	///////////////////////////////////////////////////////////
	//
	//
	// Generate a transmitted signal
	//
	//
	///////////////////////////////////////////////////////////
	// First, calculate the transmit clock
	localparam [(F_CKRES-1):0] F_MIDSTEP = { 2'b01, {(F_CKRES-2){1'b0}} };
	//
	// Need to allow us to slip by half a baud clock over 10 baud intervals
	//
	// (F_STEP / (2^F_CKRES)) * (CLOCKS_PER_BAUD)*10 < CLOCKS_PER_BAUD/2
	// F_STEP * 2 * 10 < 2^F_CKRES
	localparam [(F_CKRES-1):0] F_HALFSTEP= F_MIDSTEP/32;
	localparam [(F_CKRES-1):0] F_MINSTEP = F_MIDSTEP - F_HALFSTEP + 1;
	localparam [(F_CKRES-1):0] F_MAXSTEP = F_MIDSTEP + F_HALFSTEP - 1;
	initial assert(F_MINSTEP <= F_MIDSTEP);
	initial assert(F_MIDSTEP <= F_MAXSTEP);
	//	assume((f_tx_step >= F_MINSTEP)&&(f_tx_step <= F_MAXSTEP));
	//
	//
	always @(*) assume((f_tx_step == F_MINSTEP)
			||(f_tx_step == F_MIDSTEP)
			||(f_tx_step == F_MAXSTEP));
	always @($global_clock)
		f_tx_clock <= f_tx_clock + f_tx_step;
	assign	f_txclk = f_tx_clock[F_CKRES-1];
	// 
	initial	f_past_valid_tx = 1'b0;
	always @(posedge f_txclk)
		f_past_valid_tx <= 1'b1;
	initial	assume(i_uart_rx);
	//////////////////////////////////////////////
	//
	//
	// Build a simulated transmitter
	//
	//
	//////////////////////////////////////////////
	//
	// First, the simulated timing generator
	// parameter	TIMER_BITS = 10;
	// parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868;
	// localparam	TB = TIMER_BITS;
	always @(*)
	if (f_tx_busy)
		assume(!f_tx_start);
	initial	f_tx_baud = 0;
	always @(posedge f_txclk)
	if ((f_tx_zbaud)&&((f_tx_busy)||(f_tx_start)))
		f_tx_baud <= CLOCKS_PER_BAUD-1'b1;
	else if (!f_tx_zbaud)
		f_tx_baud <= f_tx_baud - 1'b1;
	always @(*)
		`ASSERT(f_tx_baud < CLOCKS_PER_BAUD);
	always @(*)
	if (!f_tx_busy)
		`ASSERT(f_tx_baud == 0);
	assign	f_tx_zbaud = (f_tx_baud == 0);
	// But only if we aren't busy
	initial	assume(f_tx_data == 0);
	always @(posedge f_txclk)
	if ((!f_tx_zbaud)||(f_tx_busy)||(!f_tx_start))
		assume(f_tx_data == $past(f_tx_data));
	// Force the data to change on a clock only
	always @($global_clock)
	if ((f_past_valid)&&(!$rose(f_txclk)))
		assume($stable(f_tx_data));
	else if (f_tx_busy)
		assume($stable(f_tx_data));
	//
	always @($global_clock)
	if ((!f_past_valid)||(!$rose(f_txclk)))
	begin
		assume($stable(f_tx_start));
		assume($stable(f_tx_data));
	end
	//
	//
	//
	reg	[9:0]	f_tx_reg;
	reg		f_tx_busy;
	// Here's the transmitter itself (roughly)
	initial	f_tx_busy   = 1'b0;
	initial	f_tx_reg    = 0;
	always @(posedge f_txclk)
	if (!f_tx_zbaud)
	begin
		`ASSERT(f_tx_busy);
	end else begin
		f_tx_reg  <= { 1'b0, f_tx_reg[9:1] };
		if (f_tx_start)
			f_tx_reg <= { 1'b1, f_tx_data, 1'b0 };
	end
	// Create a busy flag that we'll use
	always @(*)
	if (!f_tx_zbaud)
		f_tx_busy <= 1'b1;
	else if (|f_tx_reg)
		f_tx_busy <= 1'b1;
	else
		f_tx_busy <= 1'b0;
	//
	// Tie the TX register to the TX data
	always @(posedge f_txclk)
	if (f_tx_reg[9])
		`ASSERT(f_tx_reg[8:0] == { f_tx_data, 1'b0 });
	else if (f_tx_reg[8])
		`ASSERT(f_tx_reg[7:0] == f_tx_data[7:0] );
	else if (f_tx_reg[7])
		`ASSERT(f_tx_reg[6:0] == f_tx_data[7:1] );
	else if (f_tx_reg[6])
		`ASSERT(f_tx_reg[5:0] == f_tx_data[7:2] );
	else if (f_tx_reg[5])
		`ASSERT(f_tx_reg[4:0] == f_tx_data[7:3] );
	else if (f_tx_reg[4])
		`ASSERT(f_tx_reg[3:0] == f_tx_data[7:4] );
	else if (f_tx_reg[3])
		`ASSERT(f_tx_reg[2:0] == f_tx_data[7:5] );
	else if (f_tx_reg[2])
		`ASSERT(f_tx_reg[1:0] == f_tx_data[7:6] );
	else if (f_tx_reg[1])
		`ASSERT(f_tx_reg[0] == f_tx_data[7]);
	// Our counter since we start
	initial	f_tx_count = 0;
	always @(posedge f_txclk)
	if (!f_tx_busy)
		f_tx_count <= 0;
	else
		f_tx_count <= f_tx_count + 1'b1;
	always @(*)
	if (f_tx_reg == 10'h0)
		assume(i_uart_rx);
	else
		assume(i_uart_rx == f_tx_reg[0]);
	//
	// Make sure the absolute transmit clock timer matches our state
	//
	always @(posedge f_txclk)
	if (!f_tx_busy)
	begin
		if ((!f_past_valid_tx)||(!$past(f_tx_busy)))
			`ASSERT(f_tx_count == 0);
	end else if (f_tx_reg[9])
		`ASSERT(f_tx_count ==
				    CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[8])
		`ASSERT(f_tx_count ==
				2 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[7])
		`ASSERT(f_tx_count ==
				3 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[6])
		`ASSERT(f_tx_count ==
				4 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[5])
		`ASSERT(f_tx_count ==
				5 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[4])
		`ASSERT(f_tx_count ==
				6 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[3])
		`ASSERT(f_tx_count ==
				7 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[2])
		`ASSERT(f_tx_count ==
				8 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[1])
		`ASSERT(f_tx_count ==
				9 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else if (f_tx_reg[0])
		`ASSERT(f_tx_count ==
				10 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	else
		`ASSERT(f_tx_count ==
				11 * CLOCKS_PER_BAUD -1 -f_tx_baud);
	///////////////////////////////////////
	//
	// Receiver
	//
	///////////////////////////////////////
	//
	// Count RX clocks since the start of the first stop bit, measured in
	// rx clocks
	initial	f_rx_count = 0;
	always @(posedge i_clk)
	if (state == `RXUL_IDLE)
		f_rx_count = (!ck_uart) ? (chg_counter+2) : 0;
	else
		f_rx_count <= f_rx_count + 1'b1;
	always @(posedge i_clk)
	if (state == 0)
		`ASSERT(f_rx_count
				== half_baud + (CLOCKS_PER_BAUD-baud_counter));
	else if (state == 1)
		`ASSERT(f_rx_count == half_baud + 2 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 2)
		`ASSERT(f_rx_count == half_baud + 3 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 3)
		`ASSERT(f_rx_count == half_baud + 4 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 4)
		`ASSERT(f_rx_count == half_baud + 5 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 5)
		`ASSERT(f_rx_count == half_baud + 6 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 6)
		`ASSERT(f_rx_count == half_baud + 7 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 7)
		`ASSERT(f_rx_count == half_baud + 8 * CLOCKS_PER_BAUD
					- baud_counter);
	else if (state == 8)
		`ASSERT((f_rx_count == half_baud + 9 * CLOCKS_PER_BAUD
					- baud_counter)
			||(f_rx_count == half_baud + 10 * CLOCKS_PER_BAUD
					- baud_counter));
	always @(*)
		`ASSERT( ((!zero_baud_counter)
				&&(state == `RXUL_IDLE)
				&&(baud_counter == 0))
			||((zero_baud_counter)&&(baud_counter == 0))
			||((!zero_baud_counter)&&(baud_counter != 0)));
	always @(posedge i_clk)
	if (!f_past_valid)
		`ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0)
			&&(zero_baud_counter));
	always @(*)
	begin
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h2);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h4);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h5);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h6);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h9);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'ha);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hb);
		`ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hd);
	end
	always @(posedge i_clk)
	if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)&&($past(ck_uart)))
		`ASSERT(state == `RXUL_IDLE);
	always @(posedge i_clk)
	if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)
			&&(($past(state) != `RXUL_IDLE)||(state == `RXUL_IDLE)))
		`ASSERT(zero_baud_counter);
	// Calculate an absolute value of the difference between the two baud
	// clocks
	always @(posedge i_clk)
	if ((f_past_valid)&&($past(state)==`RXUL_IDLE)&&(state == `RXUL_IDLE))
	begin
		`ASSERT(($past(ck_uart))
			||(chg_counter <=
				{ 1'b0, CLOCKS_PER_BAUD[(TB-1):1] }));
	end
	always @(posedge f_txclk)
	if (!f_past_valid_tx)
		`ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0)
			&&(zero_baud_counter)&&(!f_tx_busy));
	wire	[(TB+3):0]	f_tx_count_two_clocks_ago;
	assign	f_tx_count_two_clocks_ago = f_tx_count - 2;
	always @(*)
	if (f_tx_count >= f_rx_count + 2)
		f_baud_difference = f_tx_count_two_clocks_ago - f_rx_count;
	else
		f_baud_difference = f_rx_count - f_tx_count_two_clocks_ago;
	localparam	F_SYNC_DLY = 8;
	reg	[(TB+4+F_CKRES-1):0]	f_sub_baud_difference;
	reg	[F_CKRES-1:0]	ck_tx_clock;
	reg	[((F_SYNC_DLY-1)*F_CKRES)-1:0]	q_tx_clock;
	reg	[TB+3:0]	ck_tx_count;
	reg	[(F_SYNC_DLY-1)*(TB+4)-1:0]	q_tx_count;
	initial	q_tx_count = 0;
	initial	ck_tx_count = 0;
	initial	q_tx_clock = 0;
	initial	ck_tx_clock = 0;
	always @($global_clock)
		{ ck_tx_clock, q_tx_clock } <= { q_tx_clock, f_tx_clock };
	always @($global_clock)
		{ ck_tx_count, q_tx_count } <= { q_tx_count, f_tx_count };
	reg	[TB+4+F_CKRES-1:0]	f_ck_tx_time, f_rx_time;
	always @(*)
		f_ck_tx_time = { ck_tx_count, !ck_tx_clock[F_CKRES-1],
						ck_tx_clock[F_CKRES-2:0] };
	always @(*)
		f_rx_time = { f_rx_count, !f_rx_clock[1], f_rx_clock[0],
						{(F_CKRES-2){1'b0}} };
	reg	[TB+4+F_CKRES-1:0]	f_signed_difference;
	always @(*)
		f_signed_difference = f_ck_tx_time - f_rx_time;
	always @(*)
	if (f_signed_difference[TB+4+F_CKRES-1])
		f_sub_baud_difference = -f_signed_difference;
	else
		f_sub_baud_difference =  f_signed_difference;
	always @($global_clock)
	if (state == `RXUL_WAIT)
		`ASSERT((!f_tx_busy)||(f_tx_reg[9:1] == 0));
	always @($global_clock)
	if (state == `RXUL_IDLE)
	begin
		`ASSERT((!f_tx_busy)||(f_tx_reg[9])||(f_tx_reg[9:1]==0));
		if (!ck_uart)
			;//`PHASE_TWO_ASSERT((f_rx_count < 4)||(f_sub_baud_difference <= ((CLOCKS_PER_BAUD<<F_CKRES)/20)));
		else
			`ASSERT((f_tx_reg[9:1]==0)||(f_tx_count < (3 + CLOCKS_PER_BAUD/2)));
	end else if (state == 0)
		`ASSERT(f_sub_baud_difference
				<=  2 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 1)
		`ASSERT(f_sub_baud_difference
				<=  3 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 2)
		`ASSERT(f_sub_baud_difference
				<=  4 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 3)
		`ASSERT(f_sub_baud_difference
				<=  5 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 4)
		`ASSERT(f_sub_baud_difference
				<=  6 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 5)
		`ASSERT(f_sub_baud_difference
				<=  7 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 6)
		`ASSERT(f_sub_baud_difference
				<=  8 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 7)
		`ASSERT(f_sub_baud_difference
				<=  9 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	else if (state == 8)
		`ASSERT(f_sub_baud_difference
				<= 10 * ((CLOCKS_PER_BAUD<<F_CKRES)/20));
	always @(posedge i_clk)
	if (o_wr)
		`ASSERT(o_data == $past(f_tx_data,4));
	// always @(posedge i_clk)
	// if ((zero_baud_counter)&&(state != 4'hf)&&(CLOCKS_PER_BAUD > 6))
		// assert(i_uart_rx == ck_uart);
	// Make sure the data register matches
	always @(posedge i_clk)
	// if ((f_past_valid)&&(state != $past(state)))
	begin
		if (state == 4'h0)
			`ASSERT(!data_reg[7]);
		if (state == 4'h1)
			`ASSERT((data_reg[7]
				== $past(f_tx_data[0]))&&(!data_reg[6]));
		if (state == 4'h2)
			`ASSERT(data_reg[7:6]
					== $past(f_tx_data[1:0]));
		if (state == 4'h3)
			`ASSERT(data_reg[7:5] == $past(f_tx_data[2:0]));
		if (state == 4'h4)
			`ASSERT(data_reg[7:4] == $past(f_tx_data[3:0]));
		if (state == 4'h5)
			`ASSERT(data_reg[7:3] == $past(f_tx_data[4:0]));
		if (state == 4'h6)
			`ASSERT(data_reg[7:2] == $past(f_tx_data[5:0]));
		if (state == 4'h7)
			`ASSERT(data_reg[7:1] == $past(f_tx_data[6:0]));
		if (state == 4'h8)
			`ASSERT(data_reg[7:0] == $past(f_tx_data[7:0]));
	end
	////////////////////////////////////////////////////////////////////////
	//
	// Cover properties
	//
	////////////////////////////////////////////////////////////////////////
	//
	always @(posedge i_clk)
		cover(o_wr); // Step 626, takes about 20mins
	always @(posedge i_clk)
	begin
		cover(!ck_uart);
		cover((f_past_valid)&&($rose(ck_uart)));               //  82
		cover((zero_baud_counter)&&(state == `RXUL_BIT_ZERO)); // 110
		cover((zero_baud_counter)&&(state == `RXUL_BIT_ONE));  // 174
		cover((zero_baud_counter)&&(state == `RXUL_BIT_TWO));  // 238
		cover((zero_baud_counter)&&(state == `RXUL_BIT_THREE));// 302
		cover((zero_baud_counter)&&(state == `RXUL_BIT_FOUR)); // 366
		cover((zero_baud_counter)&&(state == `RXUL_BIT_FIVE)); // 430
		cover((zero_baud_counter)&&(state == `RXUL_BIT_SIX));  // 494
		cover((zero_baud_counter)&&(state == `RXUL_BIT_SEVEN));// 558
		cover((zero_baud_counter)&&(state == `RXUL_STOP));     // 622
		cover((zero_baud_counter)&&(state == `RXUL_WAIT));     // 626
	end
`endif
`ifdef	FORMAL_VERILATOR
	// FORMAL properties which can be tested via Verilator as well as
	// Yosys FORMAL
	always @(*)
		assert((state == 4'hf)||(state <= `RXUL_WAIT));
	always @(*)
		assert(zero_baud_counter == (baud_counter == 0)? 1'b1:1'b0);
	always @(*)
		assert(baud_counter <= CLOCKS_PER_BAUD-1'b1);
`endif
endmodule

Added example2/tx.v version [de68cf6199].



















































































































































































































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

////////////////////////////////////////////////////////////////////////////////
//
// Filename: 	txuartlite.v
//
// Project:	wbuart32, a full featured UART with simulator
//
// Purpose:	Transmit outputs over a single UART line.  This particular UART
//		implementation has been extremely simplified: it does not handle
//	generating break conditions, nor does it handle anything other than the
//	8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol.
//
//	To interface with this module, connect it to your system clock, and
//	pass it the byte of data you wish to transmit.  Strobe the i_wr line
//	high for one cycle, and your data will be off.  Wait until the 'o_busy'
//	line is low before strobing the i_wr line again--this implementation
//	has NO BUFFER, so strobing i_wr while the core is busy will just
//	get ignored.  The output will be placed on the o_txuart output line.
//
//	(I often set both data and strobe on the same clock, and then just leave
//	them set until the busy line is low.  Then I move on to the next piece
//	of data.)
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2020, Gisselquist Technology, LLC
//
// This program is free software (firmware): 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 3 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 MERCHANTIBILITY 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.  (It's in the $(ROOT)/doc directory.  Run make with no
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype	none
//
`define	TXUL_BIT_ZERO	4'h0
`define	TXUL_BIT_ONE	4'h1
`define	TXUL_BIT_TWO	4'h2
`define	TXUL_BIT_THREE	4'h3
`define	TXUL_BIT_FOUR	4'h4
`define	TXUL_BIT_FIVE	4'h5
`define	TXUL_BIT_SIX	4'h6
`define	TXUL_BIT_SEVEN	4'h7
`define	TXUL_STOP	4'h8
`define	TXUL_IDLE	4'hf
//
//
module txuartlite(i_clk, i_wr, i_data, o_uart_tx, o_busy);
	parameter	[4:0]	TIMING_BITS = 5'd24;
	localparam		TB = TIMING_BITS;
	parameter	[(TB-1):0]	CLOCKS_PER_BAUD = 8; // 24'd868;
	input	wire		i_clk;
	input	wire		i_wr;
	input	wire	[7:0]	i_data;
	// And the UART input line itself
	output	reg		o_uart_tx;
	// A line to tell others when we are ready to accept data.  If
	// (i_wr)&&(!o_busy) is ever true, then the core has accepted a byte
	// for transmission.
	output	wire		o_busy;

	reg	[(TB-1):0]	baud_counter;
	reg	[3:0]	state;
	reg	[7:0]	lcl_data;
	reg		r_busy, zero_baud_counter;

	// Big state machine controlling: r_busy, state
	// {{{
	//
	initial	r_busy = 1'b1;
	initial	state  = `TXUL_IDLE;
	always @(posedge i_clk)
	begin
		if (!zero_baud_counter)
			// r_busy needs to be set coming into here
			r_busy <= 1'b1;
		else if (state > `TXUL_STOP)	// STATE_IDLE
		begin
			state <= `TXUL_IDLE;
			r_busy <= 1'b0;
			if ((i_wr)&&(!r_busy))
			begin	// Immediately start us off with a start bit
				r_busy <= 1'b1;
				state <= `TXUL_BIT_ZERO;
			end
		end else begin
			// One clock tick in each of these states ...
			r_busy <= 1'b1;
			if (state <=`TXUL_STOP) // start bit, 8-d bits, stop-b
				state <= state + 1'b1;
			else
				state <= `TXUL_IDLE;
		end
	end
	// }}}

	// o_busy
	// {{{
	//
	// This is a wire, designed to be true is we are ever busy above.
	// originally, this was going to be true if we were ever not in the
	// idle state.  The logic has since become more complex, hence we have
	// a register dedicated to this and just copy out that registers value.
	assign	o_busy = (r_busy);
	// }}}


	// lcl_data
	// {{{
	//
	// This is our working copy of the i_data register which we use
	// when transmitting.  It is only of interest during transmit, and is
	// allowed to be whatever at any other time.  Hence, if r_busy isn't
	// true, we can always set it.  On the one clock where r_busy isn't
	// true and i_wr is, we set it and r_busy is true thereafter.
	// Then, on any zero_baud_counter (i.e. change between baud intervals)
	// we simple logically shift the register right to grab the next bit.
	initial	lcl_data = 8'hff;
	always @(posedge i_clk)
		if ((i_wr)&&(!r_busy))
			lcl_data <= i_data;
		else if (zero_baud_counter)
			lcl_data <= { 1'b1, lcl_data[7:1] };
	// }}}

	// o_uart_tx
	// {{{
	//
	// This is the final result/output desired of this core.  It's all
	// centered about o_uart_tx.  This is what finally needs to follow
	// the UART protocol.
	//
	initial	o_uart_tx = 1'b1;
	always @(posedge i_clk)
		if ((i_wr)&&(!r_busy))
			o_uart_tx <= 1'b0;	// Set the start bit on writes
		else if (zero_baud_counter)	// Set the data bit.
			o_uart_tx <= lcl_data[0];
	// }}}

	// Baud counter
	// {{{
	// All of the above logic is driven by the baud counter.  Bits must last
	// CLOCKS_PER_BAUD in length, and this baud counter is what we use to
	// make certain of that.
	//
	// The basic logic is this: at the beginning of a bit interval, start
	// the baud counter and set it to count CLOCKS_PER_BAUD.  When it gets
	// to zero, restart it.
	//
	// However, comparing a 28'bit number to zero can be rather complex--
	// especially if we wish to do anything else on that same clock.  For
	// that reason, we create "zero_baud_counter".  zero_baud_counter is
	// nothing more than a flag that is true anytime baud_counter is zero.
	// It's true when the logic (above) needs to step to the next bit.
	// Simple enough?
	//
	// I wish we could stop there, but there are some other (ugly)
	// conditions to deal with that offer exceptions to this basic logic.
	//
	// 1. When the user has commanded a BREAK across the line, we need to
	// wait several baud intervals following the break before we start
	// transmitting, to give any receiver a chance to recognize that we are
	// out of the break condition, and to know that the next bit will be
	// a stop bit.
	//
	// 2. A reset is similar to a break condition--on both we wait several
	// baud intervals before allowing a start bit.
	//
	// 3. In the idle state, we stop our counter--so that upon a request
	// to transmit when idle we can start transmitting immediately, rather
	// than waiting for the end of the next (fictitious and arbitrary) baud
	// interval.
	//
	// When (i_wr)&&(!r_busy)&&(state == `TXUL_IDLE) then we're not only in
	// the idle state, but we also just accepted a command to start writing
	// the next word.  At this point, the baud counter needs to be reset
	// to the number of CLOCKS_PER_BAUD, and zero_baud_counter set to zero.
	//
	// The logic is a bit twisted here, in that it will only check for the
	// above condition when zero_baud_counter is false--so as to make
	// certain the STOP bit is complete.
	initial	zero_baud_counter = 1'b1;
	initial	baud_counter = 0;
	always @(posedge i_clk)
	begin
		zero_baud_counter <= (baud_counter == 1);
		if (state == `TXUL_IDLE)
		begin
			baud_counter <= 0;
			zero_baud_counter <= 1'b1;
			if ((i_wr)&&(!r_busy))
			begin
				baud_counter <= CLOCKS_PER_BAUD - 1'b1;
				zero_baud_counter <= 1'b0;
			end
		end else if ((zero_baud_counter)&&(state == 4'h9))
		begin
			baud_counter <= 0;
			zero_baud_counter <= 1'b1;
		end else if (!zero_baud_counter)
			baud_counter <= baud_counter - 1'b1;
		else
			baud_counter <= CLOCKS_PER_BAUD - 1'b1;
	end
	// }}}
//
//
// FORMAL METHODS
//
//
//
`ifdef	FORMAL

`ifdef	TXUARTLITE
`define	ASSUME	assume
`else
`define	ASSUME	assert
`endif

	// Setup
	// {{{
	reg	f_past_valid, f_last_clk;

	initial	f_past_valid = 1'b0;
	always @(posedge i_clk)
		f_past_valid <= 1'b1;

	initial	`ASSUME(!i_wr);
	always @(posedge i_clk)
		if ((f_past_valid)&&($past(i_wr))&&($past(o_busy)))
		begin
			`ASSUME(i_wr   == $past(i_wr));
			`ASSUME(i_data == $past(i_data));
		end
	// }}}

	// Check the baud counter
	// {{{
	always @(posedge i_clk)
		assert(zero_baud_counter == (baud_counter == 0));

	always @(posedge i_clk)
		if ((f_past_valid)&&($past(baud_counter != 0))&&($past(state != `TXUL_IDLE)))
			assert(baud_counter == $past(baud_counter - 1'b1));

	always @(posedge i_clk)
		if ((f_past_valid)&&(!$past(zero_baud_counter))&&($past(state != `TXUL_IDLE)))
			assert($stable(o_uart_tx));

	reg	[(TB-1):0]	f_baud_count;
	initial	f_baud_count = 1'b0;
	always @(posedge i_clk)
		if (zero_baud_counter)
			f_baud_count <= 0;
		else
			f_baud_count <= f_baud_count + 1'b1;

	always @(posedge i_clk)
		assert(f_baud_count < CLOCKS_PER_BAUD);

	always @(posedge i_clk)
		if (baud_counter != 0)
			assert(o_busy);
	// }}}

	reg	[9:0]	f_txbits;
	// {{{
	initial	f_txbits = 0;
	always @(posedge i_clk)
		if (zero_baud_counter)
			f_txbits <= { o_uart_tx, f_txbits[9:1] };

	always @(posedge i_clk)
	if ((f_past_valid)&&(!$past(zero_baud_counter))
			&&(!$past(state==`TXUL_IDLE)))
		assert(state == $past(state));

	reg	[3:0]	f_bitcount;
	initial	f_bitcount = 0;
	always @(posedge i_clk)
		if ((!f_past_valid)||(!$past(f_past_valid)))
			f_bitcount <= 0;
		else if ((state == `TXUL_IDLE)&&(zero_baud_counter))
			f_bitcount <= 0;
		else if (zero_baud_counter)
			f_bitcount <= f_bitcount + 1'b1;

	always @(posedge i_clk)
		assert(f_bitcount <= 4'ha);

	reg	[7:0]	f_request_tx_data;
	always @(posedge i_clk)
		if ((i_wr)&&(!o_busy))
			f_request_tx_data <= i_data;

	wire	[3:0]	subcount;
	assign	subcount = 10-f_bitcount;
	always @(posedge i_clk)
		if (f_bitcount > 0)
			assert(!f_txbits[subcount]);

	always @(posedge i_clk)
		if (f_bitcount == 4'ha)
		begin
			assert(f_txbits[8:1] == f_request_tx_data);
			assert( f_txbits[9]);
		end

	always @(posedge i_clk)
		assert((state <= `TXUL_STOP + 1'b1)||(state == `TXUL_IDLE));

	always @(posedge i_clk)
	if ((f_past_valid)&&($past(f_past_valid))&&($past(o_busy)))
		cover(!o_busy);
	// }}}

`endif	// FORMAL
`ifdef	VERIFIC_SVA
	reg	[7:0]	fsv_data;

	//
	// Grab a copy of the data any time we are sent a new byte to transmit
	// We'll use this in a moment to compare the item transmitted against
	// what is supposed to be transmitted
	//
	always @(posedge i_clk)
		if ((i_wr)&&(!o_busy))
			fsv_data <= i_data;

	//
	// One baud interval
	// {{{
	//
	// 1. The UART output is constant at DAT
	// 2. The internal state remains constant at ST
	// 3. CKS = the number of clocks per bit.
	//
	// Everything stays constant during the CKS clocks with the exception
	// of (zero_baud_counter), which is *only* raised on the last clock
	// interval
	sequence	BAUD_INTERVAL(CKS, DAT, SR, ST);
		((o_uart_tx == DAT)&&(state == ST)
			&&(lcl_data == SR)
			&&(!zero_baud_counter))[*(CKS-1)]
		##1 (o_uart_tx == DAT)&&(state == ST)
			&&(lcl_data == SR)
			&&(zero_baud_counter);
	endsequence
	// }}}

	//
	// One byte transmitted
	// {{{
	//
	// DATA = the byte that is sent
	// CKS  = the number of clocks per bit
	//
	sequence	SEND(CKS, DATA);
		BAUD_INTERVAL(CKS, 1'b0, DATA, 4'h0)
		##1 BAUD_INTERVAL(CKS, DATA[0], {{(1){1'b1}},DATA[7:1]}, 4'h1)
		##1 BAUD_INTERVAL(CKS, DATA[1], {{(2){1'b1}},DATA[7:2]}, 4'h2)
		##1 BAUD_INTERVAL(CKS, DATA[2], {{(3){1'b1}},DATA[7:3]}, 4'h3)
		##1 BAUD_INTERVAL(CKS, DATA[3], {{(4){1'b1}},DATA[7:4]}, 4'h4)
		##1 BAUD_INTERVAL(CKS, DATA[4], {{(5){1'b1}},DATA[7:5]}, 4'h5)
		##1 BAUD_INTERVAL(CKS, DATA[5], {{(6){1'b1}},DATA[7:6]}, 4'h6)
		##1 BAUD_INTERVAL(CKS, DATA[6], {{(7){1'b1}},DATA[7:7]}, 4'h7)
		##1 BAUD_INTERVAL(CKS, DATA[7], 8'hff, 4'h8)
		##1 BAUD_INTERVAL(CKS, 1'b1, 8'hff, 4'h9);
	endsequence
	// }}}

	//
	// Transmit one byte
	// {{{
	// Once the byte is transmitted, make certain we return to
	// idle
	//
	assert property (
		@(posedge i_clk)
		(i_wr)&&(!o_busy)
		|=> ((o_busy) throughout SEND(CLOCKS_PER_BAUD,fsv_data))
		##1 (!o_busy)&&(o_uart_tx)&&(zero_baud_counter));
	// }}}

	// {{{
	assume property (
		@(posedge i_clk)
		(i_wr)&&(o_busy) |=>
			(i_wr)&&(o_busy)&&($stable(i_data)));

	//
	// Make certain that o_busy is true any time zero_baud_counter is
	// non-zero
	//
	always @(*)
		assert((o_busy)||(zero_baud_counter) );

	// If and only if zero_baud_counter is true, baud_counter must be zero
	// Insist on that relationship here.
	always @(*)
		assert(zero_baud_counter == (baud_counter == 0));

	// To make certain baud_counter stays below CLOCKS_PER_BAUD
	always @(*)
		assert(baud_counter < CLOCKS_PER_BAUD);

	//
	// Insist that we are only ever in a valid state
	always @(*)
		assert((state <= `TXUL_STOP+1'b1)||(state == `TXUL_IDLE));
	// }}}

`endif // Verific SVA
endmodule

Modified ezsteps.scm from [b166d59095] to [5de5d166c7].

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
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







-
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


















-
+
+







;; 
;;     You should have received a copy of the GNU General Public License
;;     along with Megatest.  If not, see <http://www.gnu.org/licenses/>.
;;

;;  strftime('%m/%d/%Y %H:%M:%S','now','localtime')

(use srfi-1 posix regex srfi-69 directory-utils)
(use srfi-1 posix regex srfi-69 directory-utils call-with-environment-variables posix-extras
     z3 csv typed-records pathname-expand matchable)

(declare (unit ezsteps))
(declare (uses db))
(declare (uses common))
(declare (uses items))
(declare (uses runconfig))
;; (declare (uses sdb))
;; (declare (uses filedb))

(include "common_records.scm")
(include "key_records.scm")
(include "db_records.scm")
(include "run_records.scm")


;;(rmt:get-test-info-by-id run-id test-id) -> testdat

;; TODO: deprecate me in favor of ezsteps.scm
;;
(define (launch:runstep ezstep run-id test-id exit-info m tal testconfig all-steps-dat)
  (let* ((stepname       (car ezstep))  ;; do stuff to run the step
	 (stepinfo       (cadr ezstep))
	;; (let ((info (cadr ezstep)))
	;; 		   (if (proc? info) "" info)))
	;; (stepproc       (let ((info (cadr ezstep)))
	;; 		   (if (proc? info) info #f)))
	 (stepparts      (string-match (regexp "^(\\{([^\\}\\{]*)\\}\\s*|)(.*)$") stepinfo))
	 (stepparams     (if (and (list? stepparts)
				  (> (length stepparts) 1))
			     (list-ref stepparts 2)
			     #f)) ;; for future use, {VAR=1,2,3}, run step for each
	 (paramparts     (if (string? stepparams)
			     (map (lambda (x)(string-split x "=")) (string-split-fields "[^;]*=[^;]*" stepparams))
			     '()))
	 (subrun         (alist-ref "subrun" paramparts equal?))
	 (stepcmd        (if (and (list? stepparts)
				  (> (length stepparts) 2))
			     (list-ref stepparts 3)
			     (conc "# error, no command for step "stepname)))
	 (script         "") ; "#!/bin/bash\n") ;; yep, we depend on bin/bash FIXME!!!\
	 (logpro-file    (conc stepname ".logpro"))
	 (html-file      (conc stepname ".html"))
	 (dat-file       (conc stepname ".dat"))
	 (tconfig-logpro (configf:lookup testconfig "logpro" stepname))
	 (logpro-used    (common:file-exists? logpro-file)))
    (setenv "MT_STEP_NAME" stepname)
    (hash-table-set! all-steps-dat stepname `((params . ,paramparts)))
    (debug:print 0 *default-log-port* "stepparts: " stepparts ", stepparams: " stepparams
                 ", paramparts: " paramparts ", subrun: " subrun ", stepcmd: " stepcmd)

    
    (if (and tconfig-logpro
	     (not logpro-used)) ;; no logpro file found but have a defn in the testconfig
	(begin
	  (with-output-to-file logpro-file
	    (lambda ()
	      (print ";; logpro file extracted from testconfig\n"
		     ";;")
	      (print tconfig-logpro)))
	  (set! logpro-used #t)))
    
    ;; NB// can safely assume we are in test-area directory
    (debug:print 4 *default-log-port* "ezsteps:\n stepname: " stepname " stepinfo: " stepinfo " stepparts: " stepparts
		 " stepparams: " stepparams " stepcmd: " stepcmd)
    
    ;; ;; first source the previous environment
    ;; (let ((prev-env (conc ".ezsteps/" prevstep (if (string-search (regexp "csh") 
    ;;      							 (get-environment-variable "SHELL")) ".csh" ".sh"))))
    ;;   (if (and prevstep (common:file-exists? prev-env))
    ;;       (set! script (conc script "source " prev-env))))
    
    ;; call the command using mt_ezstep
    ;; (set! script (conc "mt_ezstep " stepname " " (if prevstep prevstep "x") " " stepcmd))
    
    (debug:print 4 *default-log-port* "script: " script)
    (rmt:teststep-set-status! run-id test-id stepname "start" "-" #f #f)
    ;; now launch the actual process
    (call-with-environment-variables 
     (list (cons "PATH" (conc (get-environment-variable "PATH") ":.")))
     (lambda () ;; (process-run "/bin/bash" "-c" "exec ls -l /tmp/foobar > /tmp/delme-more.log 2>&1")
       (let* ((cmd (conc stepcmd " > " stepname ".log 2>&1")) ;; >outfile 2>&1 
	      (pid #f))
	 (let ((proc (lambda ()
		       (set! pid (process-run "/bin/bash" (list "-c" cmd))))))
	   (if subrun
               (begin
                 (debug:print-info 0 *default-log-port* "Running without MT_.* environment variables.")
                 (common:without-vars proc "^MT_.*"))
	       (proc)))
	 
         (with-output-to-file "Makefile.ezsteps"
           (lambda ()
             (print stepname ".log :")
             (print "\t" cmd)
             (if (common:file-exists? (conc stepname ".logpro"))
                 (print "\tlogpro " stepname ".logpro " stepname ".html < " stepname ".log"))
             (print)
             (print stepname " : " stepname ".log")
             (print))
           #:append)

	 (rmt:test-set-top-process-pid run-id test-id pid)
	 (let processloop ((i 0))
	   (let-values (((pid-val exit-status exit-code)(process-wait pid #t)))
		       (mutex-lock! m)
		       (launch:einf-pid-set!         exit-info pid)         ;; (vector-set! exit-info 0 pid)
		       (launch:einf-exit-status-set! exit-info exit-status) ;; (vector-set! exit-info 1 exit-status)
		       (launch:einf-exit-code-set!   exit-info exit-code)   ;; (vector-set! exit-info 2 exit-code)
		       (mutex-unlock! m)
		       (if (eq? pid-val 0)
			   (begin
			     (thread-sleep! 2)
			     (processloop (+ i 1))))
		       )))))
    (debug:print-info 0 *default-log-port* "step " stepname " completed with exit code " (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2))
    ;; now run logpro if needed
    (if logpro-used
	(let* ((logpro-exe (or (getenv "LOGPRO_EXE") "logpro"))
               (pid        (process-run (conc "/bin/sh -c '"logpro-exe" "logpro-file " " (conc stepname ".html") " < " stepname ".log > /dev/null'"))))
	  (let processloop ((i 0))
	    (let-values (((pid-val exit-status exit-code)(process-wait pid #t)))
			(mutex-lock! m)
			;; (make-launch:einf pid: pid exit-status: exit-status exit-code: exit-code)
			(launch:einf-pid-set!         exit-info pid)         ;; (vector-set! exit-info 0 pid)
			(launch:einf-exit-status-set! exit-info exit-status) ;; (vector-set! exit-info 1 exit-status)
			(launch:einf-exit-code-set!   exit-info exit-code)   ;; (vector-set! exit-info 2 exit-code)
			(mutex-unlock! m)
			(if (eq? pid-val 0)
			    (begin
			      (thread-sleep! 2)
			      (processloop (+ i 1)))))
	    (debug:print-info 0 *default-log-port* "logpro for step " stepname " exited with code " (launch:einf-exit-code exit-info))))) ;; (vector-ref exit-info 2)))))
    
    (let ((exinfo (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2))
	  (logfna (if logpro-used (conc stepname ".html") ""))
	  (comment #f))
      (if logpro-used
	  (let ((datfile (conc stepname ".dat")))
	    ;; load the .dat file into the test_data table if it exists
	    (if (common:file-exists? datfile)
		(set! comment (launch:load-logpro-dat run-id test-id stepname)))
	    (rmt:test-set-log! run-id test-id (conc stepname ".html"))))
      (rmt:teststep-set-status! run-id test-id stepname "end" exinfo comment logfna))
    ;; set the test final status
    (let* ((process-exit-status (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2))
	   (this-step-status (cond
			      ((and (eq? process-exit-status 2) logpro-used) 'warn)   ;; logpro 2 = warnings
			      ((and (eq? process-exit-status 3) logpro-used) 'check)  ;; logpro 3 = check
			      ((and (eq? process-exit-status 4) logpro-used) 'waived) ;; logpro 4 = waived
			      ((and (eq? process-exit-status 5) logpro-used) 'abort)  ;; logpro 5 = abort
			      ((and (eq? process-exit-status 6) logpro-used) 'skip)   ;; logpro 6 = skip
			      ((eq? process-exit-status 0)                   'pass)   ;; logpro 0 = pass
			      (else 'fail)))
	   (overall-status   (cond
			      ((eq? (launch:einf-rollup-status exit-info) 2) 'warn) ;; rollup-status (vector-ref exit-info 3)
			      ((eq? (launch:einf-rollup-status exit-info) 0) 'pass) ;; (vector-ref exit-info 3)
			      (else 'fail)))
	   (next-status      (cond 
			      ((eq? overall-status 'pass) this-step-status)
			      ((eq? overall-status 'warn)
			       (if (eq? this-step-status 'fail) 'fail 'warn))
			      ((eq? overall-status 'abort) 'abort)
			      (else 'fail)))
	   (next-state       ;; "RUNNING") ;; WHY WAS THIS CHANGED TO NOT USE (null? tal) ??
	    (cond
	     ((null? tal) ;; more to run?
	      "COMPLETED")
	     (else "RUNNING"))))
      (debug:print 4 *default-log-port* "Exit value received: " (launch:einf-exit-code exit-info) " logpro-used: " logpro-used 
		   " this-step-status: " this-step-status " overall-status: " overall-status 
		   " next-status: " next-status " rollup-status: "  (launch:einf-rollup-status exit-info)) ;; (vector-ref exit-info 3))
      (case next-status
	((warn)
	 (launch:einf-rollup-status-set! exit-info 2) ;; (vector-set! exit-info 3 2) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "WARN" 
				 (if (eq? this-step-status 'warn) "Logpro warning found" #f)
				 #f))
	((check)
	 (launch:einf-rollup-status-set! exit-info 3) ;; (vector-set! exit-info 3 3) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "CHECK" 
				 (if (eq? this-step-status 'check) "Logpro check found" #f)
				 #f))
	((waived)
	 (launch:einf-rollup-status-set! exit-info 4) ;; (vector-set! exit-info 3 3) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "WAIVED" 
				 (if (eq? this-step-status 'check) "Logpro waived found" #f)
				 #f))
	((abort)
	 (launch:einf-rollup-status-set! exit-info 5) ;; (vector-set! exit-info 3 4) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "ABORT" 
				 (if (eq? this-step-status 'abort) "Logpro abort found" #f)
				 #f))
	((skip)
	 (launch:einf-rollup-status-set! exit-info 6) ;; (vector-set! exit-info 3 4) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "SKIP" 
				 (if (eq? this-step-status 'skip) "Logpro skip found" #f)
				 #f))
	((pass)
	 (tests:test-set-status! run-id test-id next-state "PASS" #f #f))
	(else ;; 'fail
	 (launch:einf-rollup-status-set! exit-info 1) ;; (vector-set! exit-info 3 1) ;; force fail, this used to be next-state but that doesn't make sense. should always be "COMPLETED" 
	 (tests:test-set-status! run-id test-id "COMPLETED" "FAIL" (conc "Failed at step " stepname) #f)
	 )))
    logpro-used))

(define (ezsteps:run-from testdat start-step-name run-one)
  ;;# TODO - recapture item variables, debug repeated step eval; regen logpro from test
  (let* ((do-update-test-state-status #f)
         (test-run-dir  ;; (filedb:get-path *fdb* 
	  (db:test-get-rundir testdat)) ;; )
	 (testconfig    (read-config (conc test-run-dir "/testconfig") #f #t environ-patt: "pre-launch-env-vars"))
	 (ezstepslst    (hash-table-ref/default testconfig "ezsteps" '()))
	 (run-mutex     (make-mutex))
	 (rollup-status 0)
         (rollup-status-string #f)
         (rollup-status-sym #f)
	 (exit-info     (vector #t #t #t))
	 (test-id       (db:test-get-id        testdat))
	 (run-id        (db:test-get-run_id    testdat))
	 (test-name     (db:test-get-testname  testdat))
         (orig-test-state (db:test-get-state   testdat))
         (orig-test-status (db:test-get-status testdat))
	 (kill-job      #f)) ;; for future use (on re-factoring with launch.scm code
	 (kill-job      #f) ;; for future use (on re-factoring with launch.scm code
	 (the-step-params '())) ;; not exactly "functional"

    ;; keep trying till NFS deigns to populate test run dir on this host
    (let loop ((count 5))
      (if (not (common:file-exists? test-run-dir))
	  ;;(push-directory test-run-dir)
	  (if (> count 0)
	      (begin
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
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







-
-
+
+
+
+














+
+







	(message-window "ERROR: You can only re-run steps defined via ezsteps")
	(begin
	  (let loop ((ezstep   (car ezstepslst))
		     (tal      (cdr ezstepslst))
                     (status-sym-so-far 'pass)
		     ;;(runflag  #f)
                     (saw-start-step-name #f)) ;; flag used to skip steps when not starting at the beginning
	    (if (vector-ref exit-info 1)
		(let* ((stepname    (car ezstep))  ;; do stuff to run the step
	    (if (or (vector-ref exit-info 1)
		    (equal? (alist-ref 'keep-going prev-step-params) 'yes))
		(let* ((prev-step-params the-step-params) ;; need to snag this now
		       (stepname    (car ezstep))  ;; do stuff to run the step
                       (logpro-used (common:file-exists? (conc test-run-dir "/" stepname ".logpro")))
		       (stepinfo    (cadr ezstep))
		       (stepparts   (string-match (regexp "^(\\{([^\\}]*)\\}\\s*|)(.*)$") stepinfo))
		       (stepparms   (list-ref stepparts 2)) ;; for future use, {VAR=1,2,3}, run step for each 
		       (stepcmd     (list-ref stepparts 3))
		       (script      (conc "mt_ezstep '"test-run-dir"' '"stepname"' '"stepcmd"'")) ;; call the command using mt_ezstep
                       (saw-start-step-name-next (or saw-start-step-name (equal? stepname start-step-name)))
                       (proceed-with-this-step
                        (or (not start-step-name)
                            (equal? stepname start-step-name)
                            (and saw-start-step-name (not run-one))
                            saw-start-step-name-next
                            (and start-step-name (equal? stepname start-step-name))))
                       )
		  (debug:print 0 *default-log-port* "NOTE: stepparms=" stepparms)
		  (set! prev-step-params stepparms)
                  (set! do-update-test-state-status (and proceed-with-this-step (null? tal)))
                  ;;(BB> "stepname="stepname" proceed-with-this-step="proceed-with-this-step " do-update-test-state-status="do-update-test-state-status " orig-test-state="orig-test-state" orig-test-status="orig-test-status)
                  (cond
                   ((and (not proceed-with-this-step) (null? tal))
                    'done)
                   ((not proceed-with-this-step)
                      (loop (car tal)

Added fossil-utils/Makefile version [ce704a362f].















1
2
3
4
5
6
7
8
9
10
11
12
13
14
+
+
+
+
+
+
+
+
+
+
+
+
+
+


all : run.sh

go : run.sh
	bash run.sh

fossilrebase : fossilrebase.scm
	csc fossilrebase.scm

run.sh : fossilrebase justtesting/*.dat
	./fossilrebase dumpcmds justtesting > run.sh


Added fossil-utils/fossilrebase.scm version [d36203f150].







































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(use yaml matchable srfi-1 sqlite3 regex)

(define (get-timeline)
  (let* ((inp (open-input-pipe "fossil json timeline checkin -n 0"))
	 (res (yaml-load inp)))
    (close-input-pipe inp)
    res))

(define (get-val data key)
  (alist-ref key data equal?))

(define (any->string val)
  (if (string? val)
      val
      (conc val)))

(define (branch-match branches tags)
  (if (list? tags)
      (any (lambda (x)
	     (member x branches))
	   tags)
      (member tags branches)))

(define (refdb-set-value dbname sheetname row col value)
  (let ((pid (process-run "refdb" `("set" ,dbname ,sheetname ,row ,col ,value))))
    (let-values (((a b c)(process-wait pid)))
      b)))

(define (seconds->std-time-str sec)
  (time->string 
   (seconds->local-time sec)
   "%Y-%m-%d %H:%M:%S"))

(define (gen-refdb dbname branches)
  (if (not (file-exists? (conc dbname "/sheet-names.cfg")))
      (begin
	(print "ERROR: You must precreate the refdb with \"refdb edit <dbname>\"")
	(exit 1)))
  (print "Getting data from timeline...")
  (let* ((data (get-timeline))
	 (branches (string-split branches ",")))
    (print "Got data from timeline...")
    (let* ((timeline (get-val (get-val data "payload") "timeline")))
      (print "Got " (length timeline) " timeline records. Filling refdb...")
    (for-each
     (lambda (rec)
       (let ((uuid (get-val rec "uuid")))
	 (if (branch-match branches (get-val rec "tags"))
	     (let ((tagnum 0)
		   (tags   (get-val rec "tags")))
	       (print "uuid: " uuid " tags: " (get-val rec "tags"))
	       ;; First the tags so they are visible to left
	       (for-each
		(lambda (tagv)
		  (refdb-set-value dbname "timeline" uuid (conc "tag" tagnum) tagv)
		  (set! tagnum (+ tagnum 1)))
		(if (list? tags)
		    tags
		    (list tags)))
	       (for-each
		(lambda (key)
		  (refdb-set-value dbname "timeline" uuid key (any->string (get-val rec key))))
		'("user" "comment"))
	       (refdb-set-value dbname "extra" uuid "parents" (string-intersperse (get-val rec "parents") ","))
	       (refdb-set-value dbname "timeline" uuid "timestamp" (seconds->std-time-str (get-val rec "timestamp")))
	       (refdb-set-value dbname "timeline" uuid "timestamp_sec" (any->string (get-val rec "timestamp")))
	       ))))
     timeline))))

(define (escape-string-for-bash str)
  (string-substitute "'" "''" str #t))

;; tag0 tag1 tag2 cherrypick backout hide usedate recomment user
;; comment timestamp timestamp_sec
;;
(define (get-node-details db node-id)
  (let* ((result #f)
	 (count  0))
    (for-each-row
     (lambda (rowkey tag0 cmdnum cherrypick do-commit backout hide usedate recomment user comment timestamp timestamp_sec)
       (set! result `((uuid . ,rowkey)
		      (tag0 . ,tag0)
		      (cmdnum . ,cmdnum)
		      (cherrypick . ,cherrypick)
		      (do-commit  . ,do-commit)
		      (backout    . ,backout)
		      (hide . ,hide)
		      (usedate . ,usedate)
		      (recomment . ,recomment)
		      (user . ,user)
		      (comment . ,comment)
		      (timestamp . ,timestamp)
		      (timestamp_sec . ,timestamp_sec)))
       (set! count (+ count 1)))
     db
     "SELECT rowkey,tag0,cmdnum,cherrypick,do_commit,backout,hide,usedate,recomment,user,comment,timestamp,timestamp_sec FROM timeline WHERE rowkey LIKE ?;"
     node-id)
    (if (> count 1)
	(print "WARNING: more than one node matches " node-id ", found " count " nodes"))
    result))

;; get branches to create
;;
(define (get-new-branches db)
  (let* ((res '()))
    (for-each-row
     (lambda (rowkey node mode)
       (set! res (cons `((branch . ,rowkey)
			 (node   . ,node)
			 (mode   . ,mode))
		       res)))
     db
     "SELECT rowkey,node,mode FROM branches;")
    res))

;; get cherrypicks
;;
(define (get-cherry-picks db)
  (let* ((res '()))
    (for-each-row
     (lambda (rowkey tag0 cherrypick firstmerge do-commit usedate comment recomment)
       (set! res (cons `((uuid       . ,rowkey)
			 (tag0       . ,tag0)
			 (cherrypick . ,cherrypick)
			 (firstmerge . ,firstmerge)
			 (do-commit  . ,do-commit)
			 (usedate    . ,usedate)
			 (comment    . ,comment)
			 (recomment  . ,recomment))
		       res)))
     db ;; sort desc and the cons puts it back in correct order
     "SELECT rowkey,tag0,cherrypick,firstmerge,do_commit,usedate,comment,recomment FROM timeline WHERE cherrypick != '' AND cherrypick NOT NULL ORDER BY timestamp_sec DESC;")
    res))

;; always private and same time as parent node + 1 second
;;
;; fossil branch new BRANCH-NAME BASIS ?OPTIONS?
;; 
;;        Create a new branch BRANCH-NAME off of check-in BASIS.
;;        Supported options for this subcommand include:
;;        --private             branch is private (i.e., remains local)
;;        --bgcolor COLOR       use COLOR instead of automatic background
;;        --nosign              do not sign contents on this branch
;;        --date-override DATE  DATE to use instead of 'now'
;;        --user-override USER  USER to use instead of the current default
;; 
;;        DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
;;        year-month-day form, it may be truncated, the "T" may be
;;        replaced by a space, and it may also name a timezone offset
;;        from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward).
;;        Either no timezone suffix or "Z" means UTC.
;; 
(define (create-branch db branch-name parent-node)
  (let* ((parent-info (get-node-details db (conc parent-node "%"))))
    (if (not parent-info)
	(print "ERROR: no info found for node " parent-node)
	(let* ((parent-date (alist-ref 'timestamp parent-info))
	       (parent-user (alist-ref 'user      parent-info)))
	  (print "fossil branch new " branch-name " " parent-node " --private --date-override '" parent-date "'")
	  ;; (print "Creating private branch " branch-name " from node " parent-node)
	  ;; (pp parent-info)
	  ;; (print "")
	  ))))

(define (do-cherrypick db cherrypick dbfname)
  (let* ((tag0       (alist-ref 'tag0 cherrypick))
	 (uuid       (alist-ref 'uuid cherrypick))
	 (nodeinf    (get-node-details db uuid))
	 (nodedate   (alist-ref 'timestamp nodeinf))
	 (user       (alist-ref 'user      nodeinf))
	 (targ       (alist-ref 'cherrypick cherrypick))     ;; do fossil up to this node
	 (firstmerge (alist-ref 'firstmerge cherrypick))
	 (do-commit  (alist-ref 'do-commit     cherrypick)) ;; if yes do a commit
	 (usedate    (alist-ref 'usedate    cherrypick)) ;; if no use current time
	 (comment    (alist-ref 'comment    cherrypick))
	 (recomment  (alist-ref 'recomment cherrypick)))
    (print "#======= Start of cherrypick for " uuid "=======")
    (print "fossil checkout " targ)
    ;; first - do we have a firstmerge?
    (if (and (string? firstmerge)
	     (> (string-length firstmerge) 0))
	(print "fossil merge " firstmerge))
    
    (print "fossil merge --cherrypick " uuid)
    (if #t ;;(member do-commit '("x" "yes"))
	(print "fossil commit -m '" (escape-string-for-bash comment) "' "
	       (if (equal? usedate "no")
		   ""
		   (conc " --date-override '" nodedate "'"))
	       " --user-override " user
	       ))
    (print "if [[ $(fossil status | grep CONFLICT | wc -l) -gt 0 ]];then")
    (print "  echo \"\nHAVE CONFLICT - STOPPING\n\"")
    (print "  echo \"cherry pick of " uuid " into " targ " resulted in conflicts\"")
    (print "  exit 1")
    (print "else")
    (print "  echo GOOD, marking node " uuid " as DONE")
    (print "  refdb set " dbfname " timeline " uuid " status DONE")
    (print "fi")
    (print "#======= end of cherrypick for " uuid "=======")
    (print "")
    ))
		   
;; 
(define (gen-rebase-commands dbname)
  (let* ((sqldbname (conc "/tmp/" (current-user-name) "-" dbname ".db"))
	 (dbfname   (conc (current-directory) "/" dbname))) ;; want the fully qualified path so we can call the generated script from anywhere
    (print "# Create sqlite db " sqldbname "...")
    (system (conc "refdb dump2sqlite3 " dbname " " sqldbname))
    (let* ((db (open-database sqldbname))
	   (branches (get-new-branches db))
	   (cherrypicks (get-cherry-picks db)))
      ;; create the setup
      (dump-setup db)
      
      ;; create the branches
      (for-each
       (lambda (branchdat)
	 (create-branch db
			(alist-ref 'branch branchdat)
			(alist-ref 'node   branchdat)))
       branches)

      ;; create the cherrypicks
      (for-each
       (lambda (cherrypick)
	 (do-cherrypick db cherrypick dbfname))
       cherrypicks)
      )))

(define (dump-setup db)
  (for-each-row
   (lambda (cmd)
     (print cmd))
   db
   "SELECT command FROM 'setup' ORDER BY rowkey ASC;"))

(define help
"fossilrebase - register commits in a refdb, edit them by hand then execute them

WARNING: It is highly recommended you do this on a disconnected copy of your fossil database!!

Usage: fossilrebase cmd [params ...]
  where cmd is one of:
    genrefdb fname b1,b2... : generate a refdb of all the commits for branches matching patterns listed, edit with \"refdb edit fname\"
    dumpcmds fname          : from refdb fname dump fossil commands to implement the rebase you want to do.
")

(define (main)
  (if (< (length (command-line-arguments)) 1)
      (begin
	(print help)
	(exit 1))
      (match (command-line-arguments)
	(("genrefdb" fname branches) (gen-refdb fname branches))
	(("dumpcmds" fname)          (gen-rebase-commands fname))
	(else
	 (print "Sorry, didn't know what to do with \"" (string-intersperse (command-line-arguments) " ") "\"")
	 (exit 1)))))


(main)

Added fossil-utils/justtesting/branches.dat version [44988b069a].







1
2
3
4
5
6
+
+
+
+
+
+
[node]
v1.65-broken-fixes 367ffc5bdf
nobranch 367ffc5bdf
[mode]
v1.65-broken-fixes private
nobranch private

Added fossil-utils/justtesting/extra.dat version [ee15d0a10c].




















































































































































































































































































































































































































































































































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[parents]
e7b6428a2533b1901a3bb12411a4095ce23a4d35 e5c65818cc818ef14c94682202fac7bf40375ec1
e5c65818cc818ef14c94682202fac7bf40375ec1 9fc475313fb461746f4de5df8343ddf15f6b345d,f6dc7607a8ecb7df68b5e50455a97f17eaefa348
9fc475313fb461746f4de5df8343ddf15f6b345d e9153fe95b68ac1ab72d38b5cbe22b1f1237f8cc
e9153fe95b68ac1ab72d38b5cbe22b1f1237f8cc 3bd95bc26bb7491d5ab89f264232159d7c188e1b
c7baa27145762eab04802b34d95818386df2e3f7 1b0d4f257e6d9740397662ede6dc01bf0f5fcec7
1b0d4f257e6d9740397662ede6dc01bf0f5fcec7 c13726326ce034fbedb36a634179fc1f685ef076
c13726326ce034fbedb36a634179fc1f685ef076 ad2000389bacbff6847a9920ec8cc44363ff9682
ad2000389bacbff6847a9920ec8cc44363ff9682 473d6eaf82c96fb6db9905da82b1ef1419852a93
473d6eaf82c96fb6db9905da82b1ef1419852a93 367ffc5bdf35456922c1d3ceebbe633b65a65bcf
f6dc39b0f7277ade8986ad06aa9a5f043c3fba2c 2ded3e4899f49656d06b26c1a35ff730ed9768be
2ded3e4899f49656d06b26c1a35ff730ed9768be 39ec01ec3bb664aa2293ed35dc6f131e00b1d4db
39ec01ec3bb664aa2293ed35dc6f131e00b1d4db 7f1e84d10d19cd8fa9a639fd60c5102aa6c3fdf5
7f1e84d10d19cd8fa9a639fd60c5102aa6c3fdf5 7f0801084261f8dec9f4eaa05707897c239bd577
7f0801084261f8dec9f4eaa05707897c239bd577 901de8992f8a31ef8ddfe47edfb31c251044de61
901de8992f8a31ef8ddfe47edfb31c251044de61 6118471b3384fcc3ae99fd9400d2193b05ceb0f7
6118471b3384fcc3ae99fd9400d2193b05ceb0f7 73dfd99fe60a44fc519d78117e3bfb0791268fa1
73dfd99fe60a44fc519d78117e3bfb0791268fa1 2f7d94848b24bab8702d82654351d25711cc89b6
2f7d94848b24bab8702d82654351d25711cc89b6 875a0b48c6fa9e2eb37094a0b53f80fa316f1189
875a0b48c6fa9e2eb37094a0b53f80fa316f1189 66d6fd1aaf5dee5b79fbf7f47a3e7325851b7d6d
66d6fd1aaf5dee5b79fbf7f47a3e7325851b7d6d 268055792a6b6210a6d53f3bce9555a6b2de7075,e7b6428a2533b1901a3bb12411a4095ce23a4d35
f6dc7607a8ecb7df68b5e50455a97f17eaefa348 3bd95bc26bb7491d5ab89f264232159d7c188e1b
f13cb3f1bc36ede7b967ea347fa9cad59d680c88 bd18bd00ac2955b4864a543b19522525434dfe80
3bd95bc26bb7491d5ab89f264232159d7c188e1b 522b48d828c3295920e0dbd15480dae21426a74b
522b48d828c3295920e0dbd15480dae21426a74b 5dc1573e7d958fae8fb3711663a07f7f5a0670f3
5dc1573e7d958fae8fb3711663a07f7f5a0670f3 c5bd5112a83452b0cbae5dddc852d47c76ab9ff4
c5bd5112a83452b0cbae5dddc852d47c76ab9ff4 9d1cc54fe17184885380c438aaa3a2f172d3c275
9d1cc54fe17184885380c438aaa3a2f172d3c275 da2b09089751193627241c81260e7cafa10657bc
da2b09089751193627241c81260e7cafa10657bc 7fc5b1bdcc47a6f43723efd27f2edcf63bc564b1
7fc5b1bdcc47a6f43723efd27f2edcf63bc564b1 bb4c7dd6b98dbe9924182e9e5010f8846d702525
bb4c7dd6b98dbe9924182e9e5010f8846d702525 071ebc34ba460be1bdead4ec1a3c261e6bcd2bc4
071ebc34ba460be1bdead4ec1a3c261e6bcd2bc4 64aa9347d5e5af8d43fdcfbf64891596022cebe9
64aa9347d5e5af8d43fdcfbf64891596022cebe9 50237f6e1f5f369b5e1022774427028c4dba7d6b
50237f6e1f5f369b5e1022774427028c4dba7d6b e28be4def5c32dd0a16a6059db1fac22b2aa3653
e28be4def5c32dd0a16a6059db1fac22b2aa3653 b487e8f3c5ee74eeeaa6edabd92e2548a33210f7
b487e8f3c5ee74eeeaa6edabd92e2548a33210f7 63e558983a2101551ea0fa140888a5e6fd4322ae
63e558983a2101551ea0fa140888a5e6fd4322ae 19f75192e22ab76c4de3eacbf57416d192617b48
19f75192e22ab76c4de3eacbf57416d192617b48 8fd408420ba2b46d851b409832a4b0eb55f33a19
8fd408420ba2b46d851b409832a4b0eb55f33a19 2e3a570e3e8896f290135b2dfc012b0f69c3516d
268055792a6b6210a6d53f3bce9555a6b2de7075 aa29985039a593ff4c56ddc64870c8e205999184
2e3a570e3e8896f290135b2dfc012b0f69c3516d e5bf9db624e5904b1efb29df7d7ed14f7fc23bc0
e5bf9db624e5904b1efb29df7d7ed14f7fc23bc0 0a7ddadc4dece2446166d8156ecd1de168115649
0a7ddadc4dece2446166d8156ecd1de168115649 aa29985039a593ff4c56ddc64870c8e205999184
bd18bd00ac2955b4864a543b19522525434dfe80 0cb77d7f74edafa41a5d9ac28467c532b679325d
aa29985039a593ff4c56ddc64870c8e205999184 0a9e690b28f0ef4ee710dab3af7b3c45a0e4a38d
3d9c1de6339fcecbd59eb7cbec2be5680f0f914d 6625f3bc6a98d3f05f57ab42d329391613bbe008
6625f3bc6a98d3f05f57ab42d329391613bbe008 3ccc64251fcfc210fe7ba1998fa90a96d3bf2fa3
3ccc64251fcfc210fe7ba1998fa90a96d3bf2fa3 0a9e690b28f0ef4ee710dab3af7b3c45a0e4a38d
0a9e690b28f0ef4ee710dab3af7b3c45a0e4a38d 18da8b6a613e8ee42c2b82fd00fedcf38c153433
18da8b6a613e8ee42c2b82fd00fedcf38c153433 7ff937a8a2df1a3e473a760363b85e98aa01bbc4
7ff937a8a2df1a3e473a760363b85e98aa01bbc4 5b7f0c6aa302ede19e96946ad2e33a7fa97e4fbb
5b7f0c6aa302ede19e96946ad2e33a7fa97e4fbb ea8c3e52e9f9c216ed88a2707722d4c61e246522
ea8c3e52e9f9c216ed88a2707722d4c61e246522 a374d9084bb19e0715a3981a05f81b259a7500fc
a374d9084bb19e0715a3981a05f81b259a7500fc 07ff7dca1e64439988168406443a703b0ad929fa
07ff7dca1e64439988168406443a703b0ad929fa 15b59cfa429cb21c7ea1dbe8cdc3d8074d3617b6
0cb77d7f74edafa41a5d9ac28467c532b679325d d825e32743716501b8fe878f973898a5caa0c450
15b59cfa429cb21c7ea1dbe8cdc3d8074d3617b6 0364beb9c92e54e3e658cdf1876d7c75b2d68e15,d825e32743716501b8fe878f973898a5caa0c450
0364beb9c92e54e3e658cdf1876d7c75b2d68e15 0645166f9cdc9cbb2e922e7a3b0094fbf78e9c8c
0645166f9cdc9cbb2e922e7a3b0094fbf78e9c8c 5de2fd17b5348d5283f874e7ec9bf2c53cad12a0
d825e32743716501b8fe878f973898a5caa0c450 220b14a861c4883ff947e46ea39af32c046aaa99
220b14a861c4883ff947e46ea39af32c046aaa99 8724301727841358def98a48e191a0e344ddbf68
8724301727841358def98a48e191a0e344ddbf68 cdd5e92143e616f56b8b4ba90f6bc2114de0dee1
5de2fd17b5348d5283f874e7ec9bf2c53cad12a0 2a858c5054f56588fefe6039621ebaefc5344d29
2a858c5054f56588fefe6039621ebaefc5344d29 0495fb12176784b1907c243c54898c23f2afc140
0495fb12176784b1907c243c54898c23f2afc140 3b86fd8d4c9f097a04885021f902a69cfc375eeb
3b86fd8d4c9f097a04885021f902a69cfc375eeb 367ffc5bdf35456922c1d3ceebbe633b65a65bcf,cdd5e92143e616f56b8b4ba90f6bc2114de0dee1
cdd5e92143e616f56b8b4ba90f6bc2114de0dee1 c7d9089a6f8e857878fcdfda8b46b9034379dcf9
c7d9089a6f8e857878fcdfda8b46b9034379dcf9 c7977972a11df8cb1ea188cf6cf7a30e71d4292f
c7977972a11df8cb1ea188cf6cf7a30e71d4292f ccab6e04aff4406711aecbfa9b41ea0a6349fb43
ccab6e04aff4406711aecbfa9b41ea0a6349fb43 eeb358089d89aee9f2b1804a4c630ef42a231ee2
eeb358089d89aee9f2b1804a4c630ef42a231ee2 e9a528680b234a33522c1b4f6d1719d95dda5b7e
e9a528680b234a33522c1b4f6d1719d95dda5b7e caed2ecdc2c88e2ee1572137ec4cc6fe38e632bd
caed2ecdc2c88e2ee1572137ec4cc6fe38e632bd b82fdf714f1b169991340004c60d758e09ba0fbf
b82fdf714f1b169991340004c60d758e09ba0fbf 2c22506f667e6c675af6256a6bcc5bf3519f68c3
2c22506f667e6c675af6256a6bcc5bf3519f68c3 03755c29bfeaf4f4b6d00c21048eb5dd798e5cba
03755c29bfeaf4f4b6d00c21048eb5dd798e5cba 55a9a872eed80f88b6a2e2dd82da8d2822ae3fe6
55a9a872eed80f88b6a2e2dd82da8d2822ae3fe6 f02d97f2923801d99f3dd769654032cb12ce7266
f02d97f2923801d99f3dd769654032cb12ce7266 4c2b15c948deb5ac11fbd034872081dd93b029aa
4c2b15c948deb5ac11fbd034872081dd93b029aa 6fef3e6460425a7627a787fee924c8077ceae6b6
6fef3e6460425a7627a787fee924c8077ceae6b6 03921a66f9001e8fbc4252a2c355763aef6b2198
03921a66f9001e8fbc4252a2c355763aef6b2198 db55d34798110efd902302e670128e5860e4e820
db55d34798110efd902302e670128e5860e4e820 c9f20f12f36bad0d76d71faaac64f7d1a45a610e,367ffc5bdf35456922c1d3ceebbe633b65a65bcf
c9f20f12f36bad0d76d71faaac64f7d1a45a610e 3d4fba2e820c1e62f2bc2822311388172aeece58
3d4fba2e820c1e62f2bc2822311388172aeece58 681523dd88dc59a656b458bad144821ec5ac1411
681523dd88dc59a656b458bad144821ec5ac1411 23a58a862f09874f9977dc7e56866c9537b25b3b
23a58a862f09874f9977dc7e56866c9537b25b3b 156279118f7b88026768cec53312a037e6361062
156279118f7b88026768cec53312a037e6361062 8b3c7571c1376d5d6bf49935e2ecdb37ab18a82f
367ffc5bdf35456922c1d3ceebbe633b65a65bcf e1e57863eaf85b8ab3f383491a1ead12a9b46b79,e24a447e399223972ac25a520705a99221429b82
e1e57863eaf85b8ab3f383491a1ead12a9b46b79 0193399945554a426feec8595486cbc212259970
e24a447e399223972ac25a520705a99221429b82 0193399945554a426feec8595486cbc212259970
0193399945554a426feec8595486cbc212259970 37d16ef457b144b699e5d0456a8110e697b0e892
8b3c7571c1376d5d6bf49935e2ecdb37ab18a82f c3f58e0a36a34fc63b39a0e8b6dd714452a81b38
c3f58e0a36a34fc63b39a0e8b6dd714452a81b38 462317ce59bff2956b603255c533579cd960e2c1
462317ce59bff2956b603255c533579cd960e2c1 9d160839b2b6ef2f1f4ec697a4bb58595b9749ed,37d16ef457b144b699e5d0456a8110e697b0e892
37d16ef457b144b699e5d0456a8110e697b0e892 9529e99c78d2bf1ffb1b0fd6d53f8e80c73eba17
9d160839b2b6ef2f1f4ec697a4bb58595b9749ed 879965196f0456b5d09c387f51ad1aa8bc517b7e
879965196f0456b5d09c387f51ad1aa8bc517b7e 074a5dfda2c9ce4d5d98e092edef0214a15e1243
074a5dfda2c9ce4d5d98e092edef0214a15e1243 a6e3ff583a14d4a5ca8d660859a00e7501a9a4bd
a6e3ff583a14d4a5ca8d660859a00e7501a9a4bd 6ba016ecfeaf3ae2aa56e66040cc96270b94b147,d0c812fcf1a7463a75a4b0821aad7b53a698ae94
6ba016ecfeaf3ae2aa56e66040cc96270b94b147 51bf826840a8c9ae4cad2e8b5ef6d52183ede70f,9529e99c78d2bf1ffb1b0fd6d53f8e80c73eba17
d0c812fcf1a7463a75a4b0821aad7b53a698ae94 51bf826840a8c9ae4cad2e8b5ef6d52183ede70f
9529e99c78d2bf1ffb1b0fd6d53f8e80c73eba17 164020026e3a719738a3bb388ed211c757b66327
164020026e3a719738a3bb388ed211c757b66327 79f23e4a0a71efe4bcfd5d12194b5be8116b3d95
79f23e4a0a71efe4bcfd5d12194b5be8116b3d95 7dbdcbf5a0b70e2610cc6a033d855cf49277c14b
51bf826840a8c9ae4cad2e8b5ef6d52183ede70f c9f5ad314ed551d772f67971e2bf31c41c86c692
c9f5ad314ed551d772f67971e2bf31c41c86c692 cd0ae03e77f5e6b40577d94b4cad95beb0024205
7dbdcbf5a0b70e2610cc6a033d855cf49277c14b 4021551b199416dec89ccf166f168aef66cf4607
cd0ae03e77f5e6b40577d94b4cad95beb0024205 34c17b3528a056aa806b966b8fe2c875dcdfcf0f
34c17b3528a056aa806b966b8fe2c875dcdfcf0f 28423d419711ab263d31dffd54765ac939b04ed8
28423d419711ab263d31dffd54765ac939b04ed8 4021551b199416dec89ccf166f168aef66cf4607
4021551b199416dec89ccf166f168aef66cf4607 99e278145e3f48aa41d9eec257ed0e9682d80449
99e278145e3f48aa41d9eec257ed0e9682d80449 a0e6c2fdcb7cc5b53a65c204e6aacd6a41980d60
a0e6c2fdcb7cc5b53a65c204e6aacd6a41980d60 4e53ed2041f4640f0f9bd87af471042a56d55539
4e53ed2041f4640f0f9bd87af471042a56d55539 f7368a81a94f513114cb2cc1fed5f0b72269356e
f7368a81a94f513114cb2cc1fed5f0b72269356e 1aa2709b5fa6242898d01a2c7a65dac7478a65f0
1aa2709b5fa6242898d01a2c7a65dac7478a65f0 7458dc962f7de10c581e01d58ed10a190e725a95
7458dc962f7de10c581e01d58ed10a190e725a95 7c99ac42bb0d578a369f60222222878bb4bb2cea
7c99ac42bb0d578a369f60222222878bb4bb2cea 5df054d940f33812707b7c4db2ecbabb88c007f9
5df054d940f33812707b7c4db2ecbabb88c007f9 e37d51cfa5b7019e32b59051293ac069a7eb3c76
e37d51cfa5b7019e32b59051293ac069a7eb3c76 36d5ae8d9f42524366b6f3e0766235258888f879
36d5ae8d9f42524366b6f3e0766235258888f879 7e2466117d4b0a7b8d3c096d65254c3a72deaf4d
7e2466117d4b0a7b8d3c096d65254c3a72deaf4d 9fa5ffffd985c6c6835789649594f4c3eabe3e58
9fa5ffffd985c6c6835789649594f4c3eabe3e58 070a358879597c688719a64957b27b06c6ae3470
070a358879597c688719a64957b27b06c6ae3470 c7af076fb5441a6521944c470fcc7eb7e2379d1a
c7af076fb5441a6521944c470fcc7eb7e2379d1a fca9c83d5196974ec2583dc568cd6d4d13373700
fca9c83d5196974ec2583dc568cd6d4d13373700 00f6f2a2c39c22d21672f6c7d906c690d0df8df4
00f6f2a2c39c22d21672f6c7d906c690d0df8df4 2d41b2e87dc70ee208e16fb5dbdbddb807635f4d
2d41b2e87dc70ee208e16fb5dbdbddb807635f4d 844ff4c128bf32c32a02735411dbf058e5a1ed6b
844ff4c128bf32c32a02735411dbf058e5a1ed6b 224048bd1995aca9704c0bd8e3702b3da8d89b13
224048bd1995aca9704c0bd8e3702b3da8d89b13 578c1ae2425620886ec2a98b800bdfc5a75fedd6
578c1ae2425620886ec2a98b800bdfc5a75fedd6 201844bfafadb8adbb2f8e8b66d024d0798561c0
201844bfafadb8adbb2f8e8b66d024d0798561c0 9b45090ffbfdaa2b89d848b421a48b2df083977e
9b45090ffbfdaa2b89d848b421a48b2df083977e e313d518c57ab333d2f81356e52ca3cf884672f0
e313d518c57ab333d2f81356e52ca3cf884672f0 6f67e195394c055bd1f81e09f12dcd12b7b00594
6f67e195394c055bd1f81e09f12dcd12b7b00594 e94599755425765da97442e9b266d93f465df718
e94599755425765da97442e9b266d93f465df718 16da8558ede201d82667e5df765977aa99888f7b
16da8558ede201d82667e5df765977aa99888f7b 02787730a2e6787aeb1dc8cbd2d20e43925b9272
6fa2e78406096d30186b3237e119aa7d40206316 9ab2add492901a823f238b673f091a011a259f95
9ab2add492901a823f238b673f091a011a259f95 77cd1aff880b9ae014d9495bfc358095c1007049
77cd1aff880b9ae014d9495bfc358095c1007049 a7636bcfcc51032fb33630218d9761b01c219465
a7636bcfcc51032fb33630218d9761b01c219465 dde06b663fd358e1704ecf43df3465204be6a92e
dde06b663fd358e1704ecf43df3465204be6a92e 7e32aa8d9e0889efc2f30250e52aa82a832272a3
7e32aa8d9e0889efc2f30250e52aa82a832272a3 69d1d314cd31b774f4336fa2c8906e4387696013
69d1d314cd31b774f4336fa2c8906e4387696013 7ed5a5de192f37b2b56057b1d227d870c55eb769
02787730a2e6787aeb1dc8cbd2d20e43925b9272 bce20f2af9049caf12c4cab893672a0c7db2f76a
7ed5a5de192f37b2b56057b1d227d870c55eb769 bf33407036998851ea0546470d52a8954d3df5b2
bf33407036998851ea0546470d52a8954d3df5b2 841c3f498e72b482c6dc66631427ab1292cef062
841c3f498e72b482c6dc66631427ab1292cef062 27e03ab10c5de7b1c9479842a274873824d726f0
27e03ab10c5de7b1c9479842a274873824d726f0 b433734ae4d1cd0014708b7172d9cb16303105b9
b433734ae4d1cd0014708b7172d9cb16303105b9 f7cdc16245d3f850767e0c1e4b4ec954d0fa0be4
bce20f2af9049caf12c4cab893672a0c7db2f76a c5229569095ff3749bf58ea164ae082ef65a6937
f7cdc16245d3f850767e0c1e4b4ec954d0fa0be4 830231e6626606438e35d7d4320cd5a449db60ad
830231e6626606438e35d7d4320cd5a449db60ad 88ef67d3eeb590a2f45277fa236264eeda6677f5
88ef67d3eeb590a2f45277fa236264eeda6677f5 600378be441be44b2ec38356993736c374d604cf
c5229569095ff3749bf58ea164ae082ef65a6937 a7f72a923ae16e361ae18fc8473754ea2de4b1da
a7f72a923ae16e361ae18fc8473754ea2de4b1da 80a94ea109520c8cc719f9f7fb83e78f670a2c06
80a94ea109520c8cc719f9f7fb83e78f670a2c06 c8e58c2956d3ae8924cea61bbfc83fd3f0914b6f
600378be441be44b2ec38356993736c374d604cf f27cf9f446e2c0181415ed25d55c5047200c63ef
c8e58c2956d3ae8924cea61bbfc83fd3f0914b6f e22603e687c8a3c0e025a432e8082431420c3d66
e22603e687c8a3c0e025a432e8082431420c3d66 2454028ce7b5efdf6e1c7c467846d322c9b6e8c7
f27cf9f446e2c0181415ed25d55c5047200c63ef 2daae45b51f3454a8f74d876ab6adf98e9fdf836
2daae45b51f3454a8f74d876ab6adf98e9fdf836 27df8e8106135e2cd38975f36f07fdb4d944d484
27df8e8106135e2cd38975f36f07fdb4d944d484 04fc782eae164945d7eca8c85d44ea51c525d547
04fc782eae164945d7eca8c85d44ea51c525d547 577bbbab0b399075da217ec94d0521ae897185b3
2454028ce7b5efdf6e1c7c467846d322c9b6e8c7 c165b411100e84002dded53504d2151a5fda47d5
577bbbab0b399075da217ec94d0521ae897185b3 03fc95cacb87025a409d7dda22687770234e461f
03fc95cacb87025a409d7dda22687770234e461f dfa5ecc8d17d379e8e2961297d116b7d818c9075
dfa5ecc8d17d379e8e2961297d116b7d818c9075 2415804df98278e66a8f2a3837ec93f4c7ca1823
c165b411100e84002dded53504d2151a5fda47d5 64fa416b34d4225a42ca988820b6cd356dc0419b
64fa416b34d4225a42ca988820b6cd356dc0419b 8ec43965a7e5f43a9090442d36674c16595b9641
8ec43965a7e5f43a9090442d36674c16595b9641 78105f5bdbb89ab66f1f2aa409e58d9c9a5cd59f
78105f5bdbb89ab66f1f2aa409e58d9c9a5cd59f 8a260ddbc7f6c72167041280ae17c74934db579b
2415804df98278e66a8f2a3837ec93f4c7ca1823 e057f70f5187dd2e058d15950be4eac0cd49e4ad
e057f70f5187dd2e058d15950be4eac0cd49e4ad c54ed87ce367cf35aaf0916a9d3bf7108a52477c
c54ed87ce367cf35aaf0916a9d3bf7108a52477c 3decad145bdb968c13959f6f2d7e6b85ca2079b7
3decad145bdb968c13959f6f2d7e6b85ca2079b7 2c1a4adb23ced0b1be1e6b237573f08c48806cdf
2c1a4adb23ced0b1be1e6b237573f08c48806cdf 5c9f3ec17a904eb05e916b3bca595db7ffd12a0e
5c9f3ec17a904eb05e916b3bca595db7ffd12a0e 339aab0882a72b280c84f94b39d94e6f1b101b32
339aab0882a72b280c84f94b39d94e6f1b101b32 740d248cf846ed8128931483a12247ed3a179813
740d248cf846ed8128931483a12247ed3a179813 76caa1268409ae81c086266f91a1904711e90cc1
76caa1268409ae81c086266f91a1904711e90cc1 b7a9734bdf60928400cdc3785c6c0e47ed4ca7fd
8a260ddbc7f6c72167041280ae17c74934db579b 368d761da8fa62ab3fed5bad2aa03bd156d4fd4d,33694be5f862fb551556bc292347983d3629009b
368d761da8fa62ab3fed5bad2aa03bd156d4fd4d 634c52d06c7fd44853ffba7bf5dce34256570a7f
634c52d06c7fd44853ffba7bf5dce34256570a7f b3fbd7024b3f06a8d4dd4bda1cad1c8614367514
b7a9734bdf60928400cdc3785c6c0e47ed4ca7fd 7a5eb536d0e29f04d7927150d3e8bfa43150191f
33694be5f862fb551556bc292347983d3629009b e6e04b8c79af9dba388b2d7bdaaef52e4b46d1ee
e6e04b8c79af9dba388b2d7bdaaef52e4b46d1ee dc43b3418e799d4a28a530781b89111b32fea18f
dc43b3418e799d4a28a530781b89111b32fea18f b3fbd7024b3f06a8d4dd4bda1cad1c8614367514
7a5eb536d0e29f04d7927150d3e8bfa43150191f 159145e9c371ad7bcab6f91856a06ad57afd509f
159145e9c371ad7bcab6f91856a06ad57afd509f 7f499ea08bb1f3f491aac185a980444ddb694d54
7f499ea08bb1f3f491aac185a980444ddb694d54 b056a2ef6454c89441a49ff127e73ea1d3a5e4bc
b056a2ef6454c89441a49ff127e73ea1d3a5e4bc 8fb98dda5f358dfeca48c1d054fe474521ed8c45
8fb98dda5f358dfeca48c1d054fe474521ed8c45 5f97e5ae8d8d44f424886e7dce0224698a157516
5f97e5ae8d8d44f424886e7dce0224698a157516 566a3b0cf88b86bb0c2da1fea2ad970004d12d47
566a3b0cf88b86bb0c2da1fea2ad970004d12d47 d6f3b7c58c9ec886897422a482ca25123ea92ccb
d6f3b7c58c9ec886897422a482ca25123ea92ccb 016c7dba29c59cccea17fb2a1bcc93a839cb38d9
016c7dba29c59cccea17fb2a1bcc93a839cb38d9 792cf5fe01f5cf08c1c69bcc242b5ff0fa6e970d
792cf5fe01f5cf08c1c69bcc242b5ff0fa6e970d cfaa83fc7069a9cd0ee9d930b7d2c97042f517a0
cfaa83fc7069a9cd0ee9d930b7d2c97042f517a0 3405d7b2dbfe7eb8f4bb9ce55fb4aa4298d820c4
3405d7b2dbfe7eb8f4bb9ce55fb4aa4298d820c4 d22d4fa40848bafb724a0624c3d6d45da92f7982
d22d4fa40848bafb724a0624c3d6d45da92f7982 074c36575043c530d29db1f9029aa9aecfc2df78
074c36575043c530d29db1f9029aa9aecfc2df78 1773996e332e9fe68035384e4ea956345e5349aa
1773996e332e9fe68035384e4ea956345e5349aa 93858377ad386a94ea9d93b82725bcd351222921
93858377ad386a94ea9d93b82725bcd351222921 23f8fa562020b18153f44fe614bfb6e10576c723
23f8fa562020b18153f44fe614bfb6e10576c723 036b7a9d4e9ad3bc6ec6c8a009b7104708bf2ea4
036b7a9d4e9ad3bc6ec6c8a009b7104708bf2ea4 6afd2e723ab6072f128b66ebdae01d4f84fdaf3c
6afd2e723ab6072f128b66ebdae01d4f84fdaf3c fde3cd0ad14f2e195c1dfd46a5ad3abf3bfd8f6d
fde3cd0ad14f2e195c1dfd46a5ad3abf3bfd8f6d 932f8e97c02dd4a1a6a905862ade47d5a33ecefc
932f8e97c02dd4a1a6a905862ade47d5a33ecefc 813b6b2b305151df1a237a4e3f9f3b3e2ca77efb
813b6b2b305151df1a237a4e3f9f3b3e2ca77efb b564e3a921293af1df4c6425823045d083ea7abc
b564e3a921293af1df4c6425823045d083ea7abc d684bd81f12e96d65885c9d23936bf313fdac673
d684bd81f12e96d65885c9d23936bf313fdac673 9f0b57c507c1c8f7eff359e8ebd0047084138ff2
9f0b57c507c1c8f7eff359e8ebd0047084138ff2 6b93274918649a6b61050d37c9aa787bb99b1db0
6b93274918649a6b61050d37c9aa787bb99b1db0 5751790037c9a2a99b68388d884c2b514179d44a
5751790037c9a2a99b68388d884c2b514179d44a d64b4b4760be2163a0b5e0321248fd1635dc8277
d64b4b4760be2163a0b5e0321248fd1635dc8277 ebaba5e3733c35203175a40998d9b6f11ade5217
ebaba5e3733c35203175a40998d9b6f11ade5217 a8e82ae9f4bd20bea816b3be31549e58fb7a70e6
a8e82ae9f4bd20bea816b3be31549e58fb7a70e6 232c8ec0e8f142e78bad8f775bd65054b4a6997b
232c8ec0e8f142e78bad8f775bd65054b4a6997b 01be4cf099557c79896956dcf4d0575cd97b71fd
01be4cf099557c79896956dcf4d0575cd97b71fd f83553313cf13c83e8bc13cf8d4c2f071e7a7145
f83553313cf13c83e8bc13cf8d4c2f071e7a7145 22eaf9c6fa040e13c652928b8bd56797ca3c6ae5
22eaf9c6fa040e13c652928b8bd56797ca3c6ae5 f22dab86da656a98303cfa4839907922ed3fbe52
f22dab86da656a98303cfa4839907922ed3fbe52 082ff62d8007aee4c47867bc92261c623d536e83
082ff62d8007aee4c47867bc92261c623d536e83 0df1257922823f33bc48f8d468825ac205477c7c
0df1257922823f33bc48f8d468825ac205477c7c 093e8bc8c2728655b17aeba753a25665ce1c4535
093e8bc8c2728655b17aeba753a25665ce1c4535 d636d628b5a0f41bff89d72b66f374764f85fc69
b3fbd7024b3f06a8d4dd4bda1cad1c8614367514 3eaa18cb5bd478a6d2dc747bef1073b29113abe8
d636d628b5a0f41bff89d72b66f374764f85fc69 28468fe546a2cc9fd6650cac6a4064b70d0ebbe2
28468fe546a2cc9fd6650cac6a4064b70d0ebbe2 07e5f0959111e1144339881645dd599bf793c9ca
07e5f0959111e1144339881645dd599bf793c9ca 6871dc0b7945ef34afd2eadd67f4d32e9a1f4105
3eaa18cb5bd478a6d2dc747bef1073b29113abe8 8a70b57bea4d1e5312f8826ffa5f16417531bbae
6871dc0b7945ef34afd2eadd67f4d32e9a1f4105 b7b562b7b3af9671b0c986dcfdd98972607216a3
b7b562b7b3af9671b0c986dcfdd98972607216a3 028f0d8c40e871fdf6ce62f08a8e5805d513c6a9
028f0d8c40e871fdf6ce62f08a8e5805d513c6a9 77149209be527afd33c4f67b37e55cb5d64b982b
77149209be527afd33c4f67b37e55cb5d64b982b fc8c642fb9b81ae9bcbc73cf5e0036231e09f15b
fc8c642fb9b81ae9bcbc73cf5e0036231e09f15b 129edccbd5f34d3128bbb177bd104bad684d7eb4
129edccbd5f34d3128bbb177bd104bad684d7eb4 a1f5573562dd58df7106703a41665b233bf82753
a1f5573562dd58df7106703a41665b233bf82753 78799c8e556b479804fcf4b9cd8e487a405e90b5
78799c8e556b479804fcf4b9cd8e487a405e90b5 1d3928260aa5e7503ca7ccdf71236c9849e51cff
1d3928260aa5e7503ca7ccdf71236c9849e51cff f6d852ea5423899a904625e7ffb4afbdf2dd3045
3dee8c9dd39b25a661cb50f7ed4e9b5533de0489 9b6c3193e6f492c668c89846b83b3a6b0a8f0a7a
f6d852ea5423899a904625e7ffb4afbdf2dd3045 9b6c3193e6f492c668c89846b83b3a6b0a8f0a7a
9b6c3193e6f492c668c89846b83b3a6b0a8f0a7a 99551309fa5760491b267e1754c2ee79a9c31c6f
99551309fa5760491b267e1754c2ee79a9c31c6f dc7ab217fe2743658babab5613b2451356e448ed
dc7ab217fe2743658babab5613b2451356e448ed 0869d10a938cbcba1b028d87fd7a6cc843303683
0869d10a938cbcba1b028d87fd7a6cc843303683 71a141e42eef4f86e4e1ce50b9aebbf5bf80b0ef
71a141e42eef4f86e4e1ce50b9aebbf5bf80b0ef 386b7b1848ab5f0babbbc73fa424b2514472e359
386b7b1848ab5f0babbbc73fa424b2514472e359 2d1ae5e50841133cb6e39e5e60eb89c368b42ff0
2d1ae5e50841133cb6e39e5e60eb89c368b42ff0 0ffb3c1a2bc275dd5482538586860091b97e9b5f
0ffb3c1a2bc275dd5482538586860091b97e9b5f 634d2c37e0e30b768fcf211d9ae70a6f4860cdf2
634d2c37e0e30b768fcf211d9ae70a6f4860cdf2 a114850abbcb083dc50de6e75cadaeb9ba3ea54c
a114850abbcb083dc50de6e75cadaeb9ba3ea54c 54f26c491b0d2dd73fc2c9e7823e3aca72a9f5a2,8a70b57bea4d1e5312f8826ffa5f16417531bbae
8a70b57bea4d1e5312f8826ffa5f16417531bbae 65e88e7bdc2bf7140c941bb20d46cb5875ee35d9
65e88e7bdc2bf7140c941bb20d46cb5875ee35d9 92c72d977c5f448716b94425e030b6f759d89ba3,78c9e0e0c54cab356975604dd664f0df46404580
92c72d977c5f448716b94425e030b6f759d89ba3 a7fef27f05f019b017d6c204aabf432f42b9b40e
a7fef27f05f019b017d6c204aabf432f42b9b40e 61dc513a05232d6f7bb36636190b31cda11feace
61dc513a05232d6f7bb36636190b31cda11feace 57d0d68288770282c430fa37afeb360fd9425c8c
57d0d68288770282c430fa37afeb360fd9425c8c 84f39d59fbcb3bc49fa4c856d7126f1adc2f5d4a
84f39d59fbcb3bc49fa4c856d7126f1adc2f5d4a ffb3fa86c6fd6939f728d06b404414cfd9ef55d5
54f26c491b0d2dd73fc2c9e7823e3aca72a9f5a2 5b4dacbff273c38e8706c3aa60a2121d18b3f7d3
5b4dacbff273c38e8706c3aa60a2121d18b3f7d3 fcf5650f1fe9f9a54858beab9087c62539873b93
fcf5650f1fe9f9a54858beab9087c62539873b93 b767764b1adf9413412a3572d33a40a548d30bf9
b767764b1adf9413412a3572d33a40a548d30bf9 e300afb35f20d9867341f92c250e911729cc8453,ffb3fa86c6fd6939f728d06b404414cfd9ef55d5
ffb3fa86c6fd6939f728d06b404414cfd9ef55d5 0d84db9635a9271fa8b4009346c38a35b266b914
e300afb35f20d9867341f92c250e911729cc8453 38212a804adc593bc4386c7445e5932b618605a9
38212a804adc593bc4386c7445e5932b618605a9 0d84db9635a9271fa8b4009346c38a35b266b914
0d84db9635a9271fa8b4009346c38a35b266b914 ad4a6187780e93ca8e49892b4c9b787fc18ab4cb,3e30a989772d3d1931bbe7a7065a905be61385c8
ad4a6187780e93ca8e49892b4c9b787fc18ab4cb 1153bc2fbaf02086ad2b989accba68e6a9cb5ab5
1153bc2fbaf02086ad2b989accba68e6a9cb5ab5 8f2462ead6441802a313373831c049a10465ba73
8f2462ead6441802a313373831c049a10465ba73 7c04317658e9e33cc13113d833b0dff1c92c134e
3e30a989772d3d1931bbe7a7065a905be61385c8 16ede37af50bf397cb08a4b83766a7c7465857d9,7c04317658e9e33cc13113d833b0dff1c92c134e
7c04317658e9e33cc13113d833b0dff1c92c134e 20a8d29b9b4732f0aaa19129e9fa35cb95404edc
20a8d29b9b4732f0aaa19129e9fa35cb95404edc 931244e94b062bb1a9d7af0078fc55465079d14c
16ede37af50bf397cb08a4b83766a7c7465857d9 c4b5049ef650faded2af059d1e2dd2357f917a77,641de07eb28ec9fc09db6a32cf9c82908a8f8fdd
c4b5049ef650faded2af059d1e2dd2357f917a77 741ee4b6a72d021b97712a303f6b3dfd5e91e379,e9444e85d37ef71fae8264684e627d14ccdb0e34,931244e94b062bb1a9d7af0078fc55465079d14c
931244e94b062bb1a9d7af0078fc55465079d14c 769eada4588c4c14812c10d8bfcec36e169b46c5
741ee4b6a72d021b97712a303f6b3dfd5e91e379 769eada4588c4c14812c10d8bfcec36e169b46c5,1fe765631fd96ed6e04304818a102c7a232d106e
769eada4588c4c14812c10d8bfcec36e169b46c5 702e56f5a226458ce02fba6c18902b0b7bef2926
702e56f5a226458ce02fba6c18902b0b7bef2926 b2688e276938c63f0e83343755c96e4ee87dcc8d
b2688e276938c63f0e83343755c96e4ee87dcc8d e45a9670135d682a6a5f2af660950a6b8b2f589c
e45a9670135d682a6a5f2af660950a6b8b2f589c f20587918bc5e1886f910058e5189d33ca07e2bb
f20587918bc5e1886f910058e5189d33ca07e2bb ae80d00cc7e94dbfbe164d9a63022f16c61082b2
ae80d00cc7e94dbfbe164d9a63022f16c61082b2 eb90f6fe980d47e0aeec5e24b106ff77ee4373bf
eb90f6fe980d47e0aeec5e24b106ff77ee4373bf 2e84f80306de8d059a99affe97a6566244630b50
2e84f80306de8d059a99affe97a6566244630b50 ffaeb9b69270c01c528394cb080e2ba815b0413b
ffaeb9b69270c01c528394cb080e2ba815b0413b ec5345e6ecc7783dee188df0d4eae343912d9eac
ec5345e6ecc7783dee188df0d4eae343912d9eac 731033a46a8632934c70c4a5aa1d354e91e2619f
731033a46a8632934c70c4a5aa1d354e91e2619f 37a2da3f610d19d28099467f73fabe68713dd44b
37a2da3f610d19d28099467f73fabe68713dd44b f08db11c36260ef555311695aef4290b4e6a22ee
f08db11c36260ef555311695aef4290b4e6a22ee af3a660dfbb6065dafea4b91677da02ef8398f7a
af3a660dfbb6065dafea4b91677da02ef8398f7a 19f2bc121f642d42ac3ccfab583566cc567bf0b0
19f2bc121f642d42ac3ccfab583566cc567bf0b0 a36cdd0820c18f70ccc19e284c4b81dd1b8be2a1
a36cdd0820c18f70ccc19e284c4b81dd1b8be2a1 00665c494078299dd945b4c438f8d7644cd04608
00665c494078299dd945b4c438f8d7644cd04608 965c3fa0774eee49c5d8a6b128cf820a41f95fb6,f66fad5ea749f3df400e17e58c347b99e380a2dc
965c3fa0774eee49c5d8a6b128cf820a41f95fb6 059415e777ed0967b88997c5e11f10e417024926,f7a5f0b8f14cda009733dc89a69c97a60a7ee4fe
059415e777ed0967b88997c5e11f10e417024926 d3caf011b4c7ec0b40cadc97bd5d619654e5d03b,f66fad5ea749f3df400e17e58c347b99e380a2dc
d3caf011b4c7ec0b40cadc97bd5d619654e5d03b 2c08c1f7c0493877c114715633c59bc2381a1113
f7a5f0b8f14cda009733dc89a69c97a60a7ee4fe b129805ac85708a12a222c298b9c361f6ccf116d
2c08c1f7c0493877c114715633c59bc2381a1113 49469ad16e121ddc47ac2cb268a71f5fe4e84e2f
49469ad16e121ddc47ac2cb268a71f5fe4e84e2f 1aaf1064c64285d7466f05f2521d0a3554ea5fb0
1aaf1064c64285d7466f05f2521d0a3554ea5fb0 eecf6b993e5deb874410fa317bb020d3b68b76e1
eecf6b993e5deb874410fa317bb020d3b68b76e1 57d7865ae2c1a2a34822f253dcf9655e2e65de5c
57d7865ae2c1a2a34822f253dcf9655e2e65de5c 0be89c389a4609197fe89dcda300528fc8c35c5a
0be89c389a4609197fe89dcda300528fc8c35c5a b129805ac85708a12a222c298b9c361f6ccf116d
b129805ac85708a12a222c298b9c361f6ccf116d f3be772e6ca62c38a11429c4c833cb038efe88e4
f3be772e6ca62c38a11429c4c833cb038efe88e4 2cf2b7b1449efe706e802779e083fe6b358450b5,234608b6ff336c17a62e728fa8940e81393ef2d9
2cf2b7b1449efe706e802779e083fe6b358450b5 44b91abd1f8477a45c7e257a51f5053e1fa207e1
44b91abd1f8477a45c7e257a51f5053e1fa207e1 ca9da88e3e855c589ccb1d55c6661c76724b5279,1b5d412efbfb5634ce7799a505afe4925825df0f
ca9da88e3e855c589ccb1d55c6661c76724b5279 e03d5c75f8af0be58e38b630f20de226de34a355
e03d5c75f8af0be58e38b630f20de226de34a355 231a14dc2dd954ba25edc51a72e662daa53a192e
231a14dc2dd954ba25edc51a72e662daa53a192e ec43e24ac438d698688e9afdd1a8e5edac65d67d
ec43e24ac438d698688e9afdd1a8e5edac65d67d 351fd3ff4fd7df647baa430e6ed5a131824d655d
351fd3ff4fd7df647baa430e6ed5a131824d655d ac8a516285c3fc79a272f935794a42e06621b46f
ac8a516285c3fc79a272f935794a42e06621b46f 3a76f000c0bfa520b3b8d28b68d118caf37ef60d
3a76f000c0bfa520b3b8d28b68d118caf37ef60d b7dfc5691b1deb29ddc0ff2d0d8417914960581f
b7dfc5691b1deb29ddc0ff2d0d8417914960581f ab579cdb7a3bc9bca352591376aa7ac11ffe871b
ab579cdb7a3bc9bca352591376aa7ac11ffe871b db1d22eadb8a586d7fc580a3d82029bdf7443d3c,8e9712a5d398a9fe5f8934af787d5d5d95a49a15
db1d22eadb8a586d7fc580a3d82029bdf7443d3c f61052be3c1cb795806f4c8895add22d6d1c9bf8,1550ea7ddf75b4478f9cf8719b00fc1cafa26a1e
f61052be3c1cb795806f4c8895add22d6d1c9bf8 8293650fcd428a498d500053f6d145e51b6ca526,2ea9ce81b49510a06465aa57e03fa9f5846abed7
8293650fcd428a498d500053f6d145e51b6ca526 6fbc0a6bcf00bdf91d1ad9d133b34a29751ae9df
6fbc0a6bcf00bdf91d1ad9d133b34a29751ae9df 2be9e621916f2895bc52f74d45a2c65b0d10f91c
2be9e621916f2895bc52f74d45a2c65b0d10f91c c038aff905aa4ecad62a1da3d559d4bbd7ed2204,fe83540f6ad304de3f03fda268112557485781de
c038aff905aa4ecad62a1da3d559d4bbd7ed2204 28de54b8dbfb3b2e5038fb59ab43ecf869733e70
28de54b8dbfb3b2e5038fb59ab43ecf869733e70 61b1af2634de8b4dd1da756c3c7a57620b517aa6
61b1af2634de8b4dd1da756c3c7a57620b517aa6 54a615c4aafa3617e6a60b911277ed87d163a162
54a615c4aafa3617e6a60b911277ed87d163a162 16e5e51d776f635f0aeec080a5e4c26645cf83f6
16e5e51d776f635f0aeec080a5e4c26645cf83f6 4b37eea7d09d818497b7fdaca5f139d64823e288
4b37eea7d09d818497b7fdaca5f139d64823e288 002d037cb3d0cbab979b4e2e14b09e16ab2c76ee
002d037cb3d0cbab979b4e2e14b09e16ab2c76ee 183f89d3457c45a95e5a70bd77943526eb59e45f
183f89d3457c45a95e5a70bd77943526eb59e45f fa5f74982be4138bda1124183612e353bfe37503
fa5f74982be4138bda1124183612e353bfe37503 3a179173299d7fdbd0cdeb64095bdd889ae3994f
3a179173299d7fdbd0cdeb64095bdd889ae3994f d9ba150235432800ddbd88b1c1d36ec2d1fb3169
d9ba150235432800ddbd88b1c1d36ec2d1fb3169 7ef81d8632ba5534eba2e00152396bf19fae1066,589e316b300ba53abd4c61730283ec7a3026de79
7ef81d8632ba5534eba2e00152396bf19fae1066 7b1e0451690771f00400b797fbda41496c3941b0
7b1e0451690771f00400b797fbda41496c3941b0 73cb4bf58e99c6154baa6981ca3e144c4bcbd03c,1d106be1728ca9ca36f72f9c60f0238bdba094e7
73cb4bf58e99c6154baa6981ca3e144c4bcbd03c 2aaccbd409e28b08e66b8271cce18279d363d982,1b4e30d106adb0ba869c736335aede5e1fd7359d
2aaccbd409e28b08e66b8271cce18279d363d982 31c8ca7f7868fc612e50a40a8b336abfe59947c2,ef2ec4a2aa8bbc0c3f805b815729f8b3430ac207
adbeb66c05311ae7dd12044e50ffe30a7bac4d5c e52f8b2513cf17879f6a00d912aa445b35a45d76
31c8ca7f7868fc612e50a40a8b336abfe59947c2 081ae45cc81c7d9bbcf14dbf11e947868786f4ca
081ae45cc81c7d9bbcf14dbf11e947868786f4ca 8fe99604383456d3e09bf637076453d9c103690f
8fe99604383456d3e09bf637076453d9c103690f 29f35f475c1ed2287f876308834d179cd39611ca
e52f8b2513cf17879f6a00d912aa445b35a45d76 0c8e6ec6fdc3c7fbab8ca602f6aeb6cf430add71
0c8e6ec6fdc3c7fbab8ca602f6aeb6cf430add71 bea6ae9a16fa70b27d1b341e7c280af1e97e31c0
bea6ae9a16fa70b27d1b341e7c280af1e97e31c0 13061daea933c0ca8871abf3aa7d09a75b224706
13061daea933c0ca8871abf3aa7d09a75b224706 e69f5bdf52f9b9757fc8db839951fa114296d6b4
e69f5bdf52f9b9757fc8db839951fa114296d6b4 e7f856437160ec8916590616ec6f4b3fd17ce57d
29f35f475c1ed2287f876308834d179cd39611ca 55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a
e7f856437160ec8916590616ec6f4b3fd17ce57d 977b907588e312b9feb26c3c49f168aaec0ac0e1
977b907588e312b9feb26c3c49f168aaec0ac0e1 e0622d9f3d96c83e832c2e833c3d619e1ce765dd
e0622d9f3d96c83e832c2e833c3d619e1ce765dd b28d552c97adc2d965ab7babf7c890e56e4eb4ce
b28d552c97adc2d965ab7babf7c890e56e4eb4ce 366547935e9b654834b37a1cf05cf02a8bf1bbb0
366547935e9b654834b37a1cf05cf02a8bf1bbb0 86a0fe717f7d121df52f81d3b4447c6d89d68c63
86a0fe717f7d121df52f81d3b4447c6d89d68c63 20ab92b6e4a54fbc9f880852cbea28dc4a880f08
20ab92b6e4a54fbc9f880852cbea28dc4a880f08 439caadb720f77df4157a7622ec441c6a01c6890
439caadb720f77df4157a7622ec441c6a01c6890 82da6b65d8f801579b16415c2d2bc937694dbabd
82da6b65d8f801579b16415c2d2bc937694dbabd e660d445bedeea6fc21810ef805b072b12056719
e660d445bedeea6fc21810ef805b072b12056719 f8012076472f9a344abd6e7bafe3fd87c8714c47
f8012076472f9a344abd6e7bafe3fd87c8714c47 959864784f3e7cf5452de90a774c7772eb3f7e51
959864784f3e7cf5452de90a774c7772eb3f7e51 6899c9d176819ece27b00273876bea0647978d87
6899c9d176819ece27b00273876bea0647978d87 723893d25c365adf9a50c309bd86458bad42e854
723893d25c365adf9a50c309bd86458bad42e854 3484aad0053fc732860b110832ad11b445a45a20
1d106be1728ca9ca36f72f9c60f0238bdba094e7 b5a0ecc65a1717a86364171529faf7352cd06bff,55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a
3484aad0053fc732860b110832ad11b445a45a20 da6d7b66552aac978cb586e2851fb56dfd167326,55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a
da6d7b66552aac978cb586e2851fb56dfd167326 b0a3cd70ab279e18883552db4a58982f84247294
b0a3cd70ab279e18883552db4a58982f84247294 60b0f467ffc8670113b608b2ddbf88278a8a4ecf
60b0f467ffc8670113b608b2ddbf88278a8a4ecf b5a0ecc65a1717a86364171529faf7352cd06bff
55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a 582b7fa0fbd2cecebceaa05b153860a49174d68f
582b7fa0fbd2cecebceaa05b153860a49174d68f 7566f2bf71d40b4db4e7c42a4ed5b9604f5cc01c
7566f2bf71d40b4db4e7c42a4ed5b9604f5cc01c c7a72a621149e788759cc375d5edf021a4eb35b5,06d1c273aab289fb1085e2d470c892222ca9086b
c7a72a621149e788759cc375d5edf021a4eb35b5 4952641dd93462e7fde19779ba307e3e8e970816
4952641dd93462e7fde19779ba307e3e8e970816 3c893a4210512daa70e7c955633e824f84d32d30,017981efcd5dbe3b7a59e19a0b8b1b3345a3deb9
017981efcd5dbe3b7a59e19a0b8b1b3345a3deb9 900b334740ad45bcbcfc7421e0703a51890f05c5
900b334740ad45bcbcfc7421e0703a51890f05c5 d9e675ce754550947c6e46586afc9705499a27fb
d9e675ce754550947c6e46586afc9705499a27fb 3c893a4210512daa70e7c955633e824f84d32d30
b5a0ecc65a1717a86364171529faf7352cd06bff 1254c88236907d47f7445c3f21ddb2606a3ea264
1254c88236907d47f7445c3f21ddb2606a3ea264 542b91337514945425da3d5722a87c0564d068c8,3c893a4210512daa70e7c955633e824f84d32d30
3c893a4210512daa70e7c955633e824f84d32d30 d26d705d6d4ae7234ee0a81b5ade3861e21abf15
542b91337514945425da3d5722a87c0564d068c8 50ea23ff376618ba330117cf27c0d105f4e4e35b
50ea23ff376618ba330117cf27c0d105f4e4e35b d26d705d6d4ae7234ee0a81b5ade3861e21abf15
d26d705d6d4ae7234ee0a81b5ade3861e21abf15 ac0148ceafdaced62f5dfa03eaabb657185608de
ac0148ceafdaced62f5dfa03eaabb657185608de 430f66247caec1a031a28b997f05a6f84155adda
430f66247caec1a031a28b997f05a6f84155adda 1f6bb250f849ccfceb3ca03d383913896c7ca04b
1f6bb250f849ccfceb3ca03d383913896c7ca04b 6d8663e1519c3c38126b6b35a7dc51d10692b558
ed59d297988963292cb5f31798edb2c095027d2c c6ecb4ee03f6726df71fd4c74448315bdd31c285
6d8663e1519c3c38126b6b35a7dc51d10692b558 32331b404a5e8fd77f7f83a15ef6e0dad4556959,85039c3ea470a14df0c2ce193ed4bc101b0ba761
85039c3ea470a14df0c2ce193ed4bc101b0ba761 32331b404a5e8fd77f7f83a15ef6e0dad4556959
c6ecb4ee03f6726df71fd4c74448315bdd31c285 32331b404a5e8fd77f7f83a15ef6e0dad4556959
32331b404a5e8fd77f7f83a15ef6e0dad4556959 16c73ccb256348cf2de008746ea8d8a61c164173
16c73ccb256348cf2de008746ea8d8a61c164173 8fddfd8f37adc66bdca13e41909e34bfe95ca285
8fddfd8f37adc66bdca13e41909e34bfe95ca285 c066b7977151553d9ec37f5db8eb3776ee1d8c88
c066b7977151553d9ec37f5db8eb3776ee1d8c88 738e6abeed9a984f31700812d084cd6ec40fe47d
738e6abeed9a984f31700812d084cd6ec40fe47d 59a626c53fe61faf9fd4a1565814c0087d38e8b0
aefba9d5f100edcf3c42a787563a2c231f7d27a6 99dec402d5e4207653a81fb914c06cfb50359d7c
99dec402d5e4207653a81fb914c06cfb50359d7c 86beaad7468f163c3efd9f7f224e29768bfbbf0e
86beaad7468f163c3efd9f7f224e29768bfbbf0e 386832d44235c0915bd0c59098ed39eeadc5d789
386832d44235c0915bd0c59098ed39eeadc5d789 adb0f2f99cc50f48d0c1be93f04c78f2ed71f9e3
adb0f2f99cc50f48d0c1be93f04c78f2ed71f9e3 f2aaee910053f7f2803ae67858011d7aaa50a1bd
f2aaee910053f7f2803ae67858011d7aaa50a1bd 884a77869d8281d66058ef769c4f880fb6f51865
884a77869d8281d66058ef769c4f880fb6f51865 8a363f876e77ab3e144a67ef3120384b6b1b513c
8a363f876e77ab3e144a67ef3120384b6b1b513c 59a626c53fe61faf9fd4a1565814c0087d38e8b0
59a626c53fe61faf9fd4a1565814c0087d38e8b0 4c0b5593dd64f4f03ea32ee9d1853347fa022db8
4c0b5593dd64f4f03ea32ee9d1853347fa022db8 a5596b73e4822e25faf10acd35abf01b9b111b07
a5596b73e4822e25faf10acd35abf01b9b111b07 5834a7acc8eaf3139a43dac4f56bb59a9c4679e8
5834a7acc8eaf3139a43dac4f56bb59a9c4679e8 74324f583bc9dd7317a7c31cc6a3fd754693a903
74324f583bc9dd7317a7c31cc6a3fd754693a903 eb63661bd1476f9156c6cf61534644f5b2d7b6bc,71d89918c0e5efb435591a5e25dd67b157540146
71d89918c0e5efb435591a5e25dd67b157540146 934132ed7c6b885d00911062f5e0d2cad1032f8b
934132ed7c6b885d00911062f5e0d2cad1032f8b edcc532c167c4ae2b74d6cbbe040ae356e1862f3
edcc532c167c4ae2b74d6cbbe040ae356e1862f3 a647090d9409d12c72248d6b4a20ad38d252214a
a647090d9409d12c72248d6b4a20ad38d252214a eb63661bd1476f9156c6cf61534644f5b2d7b6bc
eb63661bd1476f9156c6cf61534644f5b2d7b6bc dbcb3cf9a959924a84fdc7cf79d1887c5e95f4dd
dbcb3cf9a959924a84fdc7cf79d1887c5e95f4dd b2e6ae7b8938c2518d58179bf92c54d7454c5243
b2e6ae7b8938c2518d58179bf92c54d7454c5243 a4dbbfa5fddfc3e167a1b4c05e57336b05ee9222
a4dbbfa5fddfc3e167a1b4c05e57336b05ee9222 22faaf83686db877ff9058220271ba8827717a9b
22faaf83686db877ff9058220271ba8827717a9b 2b11d3acea19d9917ac6a3b11c71e44d52c200d3
2b11d3acea19d9917ac6a3b11c71e44d52c200d3 866681b74e95b997147b99c51e07da5d60feb432
866681b74e95b997147b99c51e07da5d60feb432 494eadce2e32082499eddbf082ccc0e49ece3466
494eadce2e32082499eddbf082ccc0e49ece3466 c45b0ca87c2b86f41f14bac0b162a446681aa601
c45b0ca87c2b86f41f14bac0b162a446681aa601 11a467a8ef91545bb242890660b7c1ed16481f55
11a467a8ef91545bb242890660b7c1ed16481f55 be6116e971bb865603ed4a6c8f83bd691c54422a
fff83466f384a50a9cdbc24fdbec64fbe97b397b be6116e971bb865603ed4a6c8f83bd691c54422a
be6116e971bb865603ed4a6c8f83bd691c54422a 38764bf86da93d5795e40d18947e4c6a8d71842f
38764bf86da93d5795e40d18947e4c6a8d71842f 566569e56f5ce387da9bd1238e12e4a4673193a9
566569e56f5ce387da9bd1238e12e4a4673193a9 33cf143a502e8422991ffd33794c4344e3cfd733
33cf143a502e8422991ffd33794c4344e3cfd733 2a51bc466941c8e4cc79a790df3b41f94efe902e
2a51bc466941c8e4cc79a790df3b41f94efe902e 67b2c7d27d32bc86e5c85546911865e6d53cbbd2
67b2c7d27d32bc86e5c85546911865e6d53cbbd2 d12eb7e791044c266d07998cd4e302390f73c881
d12eb7e791044c266d07998cd4e302390f73c881 5d8a2f9b91d23ef0302b3adf7c8c307a138eb03e
5d8a2f9b91d23ef0302b3adf7c8c307a138eb03e 6c93b89220d50081c68cfcc49a18b3f413c91044
6c93b89220d50081c68cfcc49a18b3f413c91044 6733bbf4a7a0255f2134f3bc7013a3a0b44d9723
6733bbf4a7a0255f2134f3bc7013a3a0b44d9723 e669693ecfde3d8f65b6f79da4c0a5275908855a
e669693ecfde3d8f65b6f79da4c0a5275908855a 0a8c497528261aa173658da4e2b416b3a58071f8
0a8c497528261aa173658da4e2b416b3a58071f8 058bef15102031f9c04c7887b6497986f722513c
058bef15102031f9c04c7887b6497986f722513c e4339a3c50515554d514886f630f68557ccc57a3,7a8dbd329924b2c3a1c5b3dd7a754ae677995f25
7a8dbd329924b2c3a1c5b3dd7a754ae677995f25 52591d24f412f3dedf650c931009dfe99dd74b3e
e4339a3c50515554d514886f630f68557ccc57a3 1b80dd0400d1deace38ef139ff02ff621f785bdf
1b80dd0400d1deace38ef139ff02ff621f785bdf fd4c0d8701b7646e93dba00409e9022dac714827
52591d24f412f3dedf650c931009dfe99dd74b3e fb7e6638f82b75f13d06d9695667992eba806073
fd4c0d8701b7646e93dba00409e9022dac714827 b04e689404c660fdf6727bf2645dd515f6a2fed4
b04e689404c660fdf6727bf2645dd515f6a2fed4 83edad0b8e3b7d7932fa579d0dce19b074773b29
83edad0b8e3b7d7932fa579d0dce19b074773b29 10d6c50ecd62eaaf8476fd1f7878a7e6a4b9bf0f,27a8f638a910eca20e09ad51deb3ea22182077e8
10d6c50ecd62eaaf8476fd1f7878a7e6a4b9bf0f 97716c5057503600ac267505e910b7b601c2ae26
97716c5057503600ac267505e910b7b601c2ae26 fb7e6638f82b75f13d06d9695667992eba806073
fb7e6638f82b75f13d06d9695667992eba806073 d55ba5cbfdf0cb089cdb58a32d7aaea623fef1ed
d55ba5cbfdf0cb089cdb58a32d7aaea623fef1ed 6f7d6654c501279e136dae443ed655021fc25124
6f7d6654c501279e136dae443ed655021fc25124 949d5407dbad5db056abd5b028a9cdce2c3eae58
949d5407dbad5db056abd5b028a9cdce2c3eae58 6139430731c2e3daf64bf3515effab4064da2eef
6139430731c2e3daf64bf3515effab4064da2eef c1e7660763b4416639fb0e35b58f290da1a854e5
c1e7660763b4416639fb0e35b58f290da1a854e5 c260f8f3ea5df6be3602ccddc140193ba64443fd
c260f8f3ea5df6be3602ccddc140193ba64443fd 2f6d498c71980333cb734d6a1226e8ebd46b2bef
2f6d498c71980333cb734d6a1226e8ebd46b2bef 10a8cb99bfe2b89a84510196977d3a6c9401e78c
10a8cb99bfe2b89a84510196977d3a6c9401e78c f4e6b4ecb213799fe9ebfaff2799b803eb4fa53d
f4e6b4ecb213799fe9ebfaff2799b803eb4fa53d 6b4a7cf4a41521712a2d8076f3d20acc84111f61
6b4a7cf4a41521712a2d8076f3d20acc84111f61 96a83f9ea5e62c9adced7d43f9818eb86e832d25
96a83f9ea5e62c9adced7d43f9818eb86e832d25 5a7b531a5237bc6f9d8ccdf4ead5db55a8017ce2
5a7b531a5237bc6f9d8ccdf4ead5db55a8017ce2 ac5c30cfa9a0af5aa442b6cf1c3cb60809e6ae9f
ac5c30cfa9a0af5aa442b6cf1c3cb60809e6ae9f eed93e593410ead2dfb213c22cd4d461d748caf5
eed93e593410ead2dfb213c22cd4d461d748caf5 681c4c04e0479999d9c39ba33a6c961c5f21e932
681c4c04e0479999d9c39ba33a6c961c5f21e932 268ce73e8a93b35c48177f348e55e2b09ecf2ac2
268ce73e8a93b35c48177f348e55e2b09ecf2ac2 91fc43b9f0070cc6c64f813846a19dc38e5885fe
91fc43b9f0070cc6c64f813846a19dc38e5885fe c4eadcfc06eeb2f82f7e84ebf3c1eede03f20c65
c4eadcfc06eeb2f82f7e84ebf3c1eede03f20c65 50a6d511213fbb79c2105e6478e0a0c89ae32dff
50a6d511213fbb79c2105e6478e0a0c89ae32dff 55ad7b5c0301c04c61f781ec2e7c760eda44b8a5
55ad7b5c0301c04c61f781ec2e7c760eda44b8a5 c64db4cd71340dec95f5e1fb95ce7a5c4b783cbd
c64db4cd71340dec95f5e1fb95ce7a5c4b783cbd e15d743b85df021b3c3a8af77165c81db0684ed8
e15d743b85df021b3c3a8af77165c81db0684ed8 8a75426772eb59bd97a9657c5e622a4e934eecb7
8a75426772eb59bd97a9657c5e622a4e934eecb7 7011408fb5511bc3278fa56429b2f4a43819dcc3
7011408fb5511bc3278fa56429b2f4a43819dcc3 ee1d5c9fac14e0c5a23f0b1479968d535cb361ce
ee1d5c9fac14e0c5a23f0b1479968d535cb361ce a3760325d1d17ed96dc4138ae6e1f32bb3107f90
a3760325d1d17ed96dc4138ae6e1f32bb3107f90 0323ded23f0f2937f939f8cb935a0529d1eac99c
0323ded23f0f2937f939f8cb935a0529d1eac99c 5cda9f73463a504d040ccce183bcfc3d1239fcd6
5cda9f73463a504d040ccce183bcfc3d1239fcd6 aa94695956a625174f6d85c2f566a81c4107867e
aa94695956a625174f6d85c2f566a81c4107867e 03d9a6fefa74839a49232900092f7c5b1a4e53d9
03d9a6fefa74839a49232900092f7c5b1a4e53d9 abf642e1fb04d7765589d5599e0de281bb92029e
abf642e1fb04d7765589d5599e0de281bb92029e 0c15178d6d1f09ff8f09fa430bc73adaab1d2d62
0c15178d6d1f09ff8f09fa430bc73adaab1d2d62 708a0404a7604d2efcede5917e3254725bc86acf
708a0404a7604d2efcede5917e3254725bc86acf e174a07c36829083e912566dcd3907aa9bc83877
6929385e83c3c54019e85e5eb4094d0c4fcbcb21 e174a07c36829083e912566dcd3907aa9bc83877
e174a07c36829083e912566dcd3907aa9bc83877 754913fd32aa45542db1ef62fa4a9652b936fc29
64c9c79a950c8a37d631cf7ea078270ac4eca7d9 1519ed155c9c1400fd579bc02cb50e1c47a3a56b
754913fd32aa45542db1ef62fa4a9652b936fc29 0251c2384e7f1b247cb63560c5ef1b5a7ad6331c
0251c2384e7f1b247cb63560c5ef1b5a7ad6331c 8e8dd3185e704f0b699e8712e1d4e1b4bbc94439,7a74b8e95278601116074b745efb8cc0cda35be5
1519ed155c9c1400fd579bc02cb50e1c47a3a56b 5fb5dbfbf78c969ff4590c7d5e6ee60a98d6a256
5fb5dbfbf78c969ff4590c7d5e6ee60a98d6a256 3200899a59caa8666a805583b2c0ea3228931542
3200899a59caa8666a805583b2c0ea3228931542 39082cc602697fab98b65fa1a07daa276f31d1d0
8e8dd3185e704f0b699e8712e1d4e1b4bbc94439 087b1eac2a1b7f3034e6eb39ba4fa6bb545ed25b,cb3bbc9d2e0a39c37bce340972c524a3b0c8e77f
087b1eac2a1b7f3034e6eb39ba4fa6bb545ed25b 1dd24dcdda7d20f38bd88a0c2c01a4283d0e3eb0
39082cc602697fab98b65fa1a07daa276f31d1d0 a00177454224cbad76c210cdb433359f7628ff07
a00177454224cbad76c210cdb433359f7628ff07 8f16c927857bc68a2d317d10641842e5ae4f475e
8f16c927857bc68a2d317d10641842e5ae4f475e 8abfd3775131b06db3b745f1c67a3b9ad5bba6ec
8abfd3775131b06db3b745f1c67a3b9ad5bba6ec 992c83b80ddbf4d0dbd67afd1f5cb0050d9bbacb
992c83b80ddbf4d0dbd67afd1f5cb0050d9bbacb 7a74b8e95278601116074b745efb8cc0cda35be5,00b438b957bdfbe2385f11cbd189ab5ddb02b05c
00b438b957bdfbe2385f11cbd189ab5ddb02b05c eb1aa9c1230160fe1a8cf99c5943c0c19cc4c82d,7a74b8e95278601116074b745efb8cc0cda35be5
eb1aa9c1230160fe1a8cf99c5943c0c19cc4c82d a32edcfb82854905ee5d3efd3a59c158209c4b16
7a74b8e95278601116074b745efb8cc0cda35be5 2741d9eb4fd52f98b05fc33534428c226c016bef
a32edcfb82854905ee5d3efd3a59c158209c4b16 c6224b1a9100e05cc5850b3dd5bcdab4c705fbed
2741d9eb4fd52f98b05fc33534428c226c016bef c661628acbf41075ef824a737bc225f6f173a0c6
c661628acbf41075ef824a737bc225f6f173a0c6 56e69f81e0f86eb66f9ab620298f00e4613232d2
c6224b1a9100e05cc5850b3dd5bcdab4c705fbed ac6f23131f686339af403d236dac13c1fd6f2e14,56e69f81e0f86eb66f9ab620298f00e4613232d2
56e69f81e0f86eb66f9ab620298f00e4613232d2 1dd24dcdda7d20f38bd88a0c2c01a4283d0e3eb0
ac6f23131f686339af403d236dac13c1fd6f2e14 f5fba357bdfc3898731bfbb3866ef40ee75b16c0
f5fba357bdfc3898731bfbb3866ef40ee75b16c0 f5559ef39a659c9f42979d45e7583a1d388c881e
1dd24dcdda7d20f38bd88a0c2c01a4283d0e3eb0 b9f1218ee50d5a4df6aa0b76289e826b72d4f1bc
f5559ef39a659c9f42979d45e7583a1d388c881e 335c8473b59bdc38492c9ead1bc3a0b5245d2e17
335c8473b59bdc38492c9ead1bc3a0b5245d2e17 e551f1cae08dbe419dc2320cdd30f1cb04dad75b
e551f1cae08dbe419dc2320cdd30f1cb04dad75b 90e6a7e419181c0fb3ea16d70a097b7099e25bd4
90e6a7e419181c0fb3ea16d70a097b7099e25bd4 03ef168ab1775755638995b16d4c73ac64776c75
03ef168ab1775755638995b16d4c73ac64776c75 b9f1218ee50d5a4df6aa0b76289e826b72d4f1bc
b9f1218ee50d5a4df6aa0b76289e826b72d4f1bc f5f300b27d1b2a90d051f6137dcad9aae07a556c
f5f300b27d1b2a90d051f6137dcad9aae07a556c 2d65cd8ad02de59743a61d2a04517f4b3968718b
2d65cd8ad02de59743a61d2a04517f4b3968718b 93e4191ac585f159d69c56d24ff90f8cbd130f72,e99d630f5587c9fc7c3319e98a4c0c45ee3ce939
e99d630f5587c9fc7c3319e98a4c0c45ee3ce939 649822464b92911db5733c5a6cd604d27f691387
649822464b92911db5733c5a6cd604d27f691387 93e4191ac585f159d69c56d24ff90f8cbd130f72
93e4191ac585f159d69c56d24ff90f8cbd130f72 4f2bafcb9e72d6be2bbfd96f8496b897cae985f3
4f2bafcb9e72d6be2bbfd96f8496b897cae985f3 470f227b7c55112c04a4d63ad7e7d081be0b1e36
470f227b7c55112c04a4d63ad7e7d081be0b1e36 5e968a126b69f89494596d6e429dee59826abbf6
5e968a126b69f89494596d6e429dee59826abbf6 8232118283fc2cfa70eec8239a1012a62a15948d,1ba6aba073c6860a1a020486827144afef86abba
8232118283fc2cfa70eec8239a1012a62a15948d 59a93a028a7d69ebeea9d2148615c411bb8be404
1ba6aba073c6860a1a020486827144afef86abba 94a053d0eab42120fb0896f671db5fc1a9de46f5,a2ee369f433a570c5bcf673ec5d57f93a57ce54b
59a93a028a7d69ebeea9d2148615c411bb8be404 a2ee369f433a570c5bcf673ec5d57f93a57ce54b,94a053d0eab42120fb0896f671db5fc1a9de46f5
a2ee369f433a570c5bcf673ec5d57f93a57ce54b 977ca5be29771ae6680f3cee3cb420feb186a691
977ca5be29771ae6680f3cee3cb420feb186a691 9480b4262994433d56ea454f5f942631f4346774
94a053d0eab42120fb0896f671db5fc1a9de46f5 c28e4b5652ff8d1c9c3a5525a3762034086c9ab6
c28e4b5652ff8d1c9c3a5525a3762034086c9ab6 f8b993531b45d0022629fd19ca5340dd9c397618
9480b4262994433d56ea454f5f942631f4346774 9ebad2b30da5317976e8176fc160fccef4c589fb
9ebad2b30da5317976e8176fc160fccef4c589fb 4aeb75f670ba69c9abd0ad109cc2d5b2ff3033d2
4aeb75f670ba69c9abd0ad109cc2d5b2ff3033d2 d668d912e4bf2d89acbe50c524f72e4eaec835dd
d668d912e4bf2d89acbe50c524f72e4eaec835dd c2d166b052fc39a8461a56b46d0ee330893402d0
c2d166b052fc39a8461a56b46d0ee330893402d0 90452f880b21795692a2ac3d5113aefc5963abba
f8b993531b45d0022629fd19ca5340dd9c397618 90452f880b21795692a2ac3d5113aefc5963abba
90452f880b21795692a2ac3d5113aefc5963abba c280060f24e08bbd58a9d8ea941ff3780ede11d1
c280060f24e08bbd58a9d8ea941ff3780ede11d1 77f61cd330a3ca2373c1d432d05ce087c8fd0db1
77f61cd330a3ca2373c1d432d05ce087c8fd0db1 9e56800a6942b9cc89cd15a1373c414049393b05
9e56800a6942b9cc89cd15a1373c414049393b05 01ed63fe8a3016ef61c067400cee73407c1a4d79,14e9c3fb650acaa291b75625bfa4a58f05c8297e
14e9c3fb650acaa291b75625bfa4a58f05c8297e 01ed63fe8a3016ef61c067400cee73407c1a4d79
01ed63fe8a3016ef61c067400cee73407c1a4d79 d7e5356bcad6e5622ea68cc039e89e86ba749493
d7e5356bcad6e5622ea68cc039e89e86ba749493 3f0d1f8803cb6a95353b635c2dfe9c9cc4ef3899
3f0d1f8803cb6a95353b635c2dfe9c9cc4ef3899 b5ed77d7454aac9d98703f7cd688bf408847c1ee
b5ed77d7454aac9d98703f7cd688bf408847c1ee 2a86e587bcf4871707cb3aa55ceb44702495b91d
2a86e587bcf4871707cb3aa55ceb44702495b91d 497953438434d529d1362091a6ee1fbca1ef2ee9
497953438434d529d1362091a6ee1fbca1ef2ee9 1e9a20f13ab327da684893f312d18f06815f5a77,ae42e0260e2f476bb6c0558e1604d9b812a4b004
ae42e0260e2f476bb6c0558e1604d9b812a4b004 ae21e2aec14b38a3186f609656779e22eec3a11b
ae21e2aec14b38a3186f609656779e22eec3a11b 915e74bc332cca88f57964fe501c1d5c05b6e79a
915e74bc332cca88f57964fe501c1d5c05b6e79a d05d52e7504b851b0932af9d52fbef30e08accca
d05d52e7504b851b0932af9d52fbef30e08accca 1e9a20f13ab327da684893f312d18f06815f5a77
1e9a20f13ab327da684893f312d18f06815f5a77 b7bca59fa9703a5a024fc550340524fc591132fc
b7bca59fa9703a5a024fc550340524fc591132fc f598a7e51ea45ca101f2e89a1b31aa0618a9041e,18868f44fd07e5c73329377c60e946c8c4c4efb5
f598a7e51ea45ca101f2e89a1b31aa0618a9041e b6ea4f981a526654afe9d6d30d5b462ae3a0cf62
b6ea4f981a526654afe9d6d30d5b462ae3a0cf62 c57a166878875b960e8051d72eec716c016baf5b
c57a166878875b960e8051d72eec716c016baf5b f1ae1885662d78efd7bc206352c21a1a974a2c0b
f1ae1885662d78efd7bc206352c21a1a974a2c0b ab7e6db80c30b830ec8dc016e162f52b2ee7eb94
ab7e6db80c30b830ec8dc016e162f52b2ee7eb94 6961246ad7afecc990d346b9d2f543b6abb76bf7
6961246ad7afecc990d346b9d2f543b6abb76bf7 97727e82b875406e51e022fcddc642180f06e675
97727e82b875406e51e022fcddc642180f06e675 3321c2c52278ba7f8d12aaea3cbc07f6a505fedc
3321c2c52278ba7f8d12aaea3cbc07f6a505fedc 067b4c3661c6a97f88ff34072107ee601e782183
067b4c3661c6a97f88ff34072107ee601e782183 cd9d9347c272aa02e2292cc3fa2fd599f53bd2f8
cd9d9347c272aa02e2292cc3fa2fd599f53bd2f8 64d93529768e368d3dbf59e3da39a1750ab556bb
64d93529768e368d3dbf59e3da39a1750ab556bb 30b0302862cb860f31ab9ab80e7fc8874e5be1a5
30b0302862cb860f31ab9ab80e7fc8874e5be1a5 83fad2f941618f4b3efe58a2a40354e7d7f228e9
83fad2f941618f4b3efe58a2a40354e7d7f228e9 744916ab205a49f31e30a3c215c50b9c1e7ba43c
744916ab205a49f31e30a3c215c50b9c1e7ba43c 8a292192e55474a928883137244d11ff852ac2f5
8a292192e55474a928883137244d11ff852ac2f5 d2b6ddbe9c4dc205ed92955daceae90b976399e4
d2b6ddbe9c4dc205ed92955daceae90b976399e4 794d62eebe3a2bb8dc687152712f02804c76714e
794d62eebe3a2bb8dc687152712f02804c76714e 856838e0f017591c07fa91f41cdca3423710d1a1
856838e0f017591c07fa91f41cdca3423710d1a1 6f2b3e137f04276d578b367adf5b8ef4b1b75e7a
6f2b3e137f04276d578b367adf5b8ef4b1b75e7a f37121f8b18ab9076f299c55249a5f4a5ce83602,fde3dc46b70e5b82c514fe2af4c02cc0c6c8cf78
fde3dc46b70e5b82c514fe2af4c02cc0c6c8cf78 504c555d5a09ab502c55ef8f6eba884ae8090421
504c555d5a09ab502c55ef8f6eba884ae8090421 0179214de8763308df414fdd8c25174c2c4d1ac6
0179214de8763308df414fdd8c25174c2c4d1ac6 237a19178bf7b962c419090447ed12b093f98031
237a19178bf7b962c419090447ed12b093f98031 be9acfd8edc953fd7c1a27df479f5dcb22d3d023
be9acfd8edc953fd7c1a27df479f5dcb22d3d023 6b11655edddb7fe8219566adf05a7313cd3f3a52
f37121f8b18ab9076f299c55249a5f4a5ce83602 3271143f7080ffd0be43286f513b58200a6bde42
6b11655edddb7fe8219566adf05a7313cd3f3a52 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6
3271143f7080ffd0be43286f513b58200a6bde42 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6
ee563960f8474b8b2d6ef1d964ce55be449caa94 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6
fe0ca9de59f0dd99b5fb45340b42bc2884b263f6 114eed176f7dc84e70c567f7a20d59093bed7105,e4b276aa24aa86724ac0cd824a7227881519c126,ece2bfcae2b3897da82c44c8371486191f1e8c10
114eed176f7dc84e70c567f7a20d59093bed7105 a8cb71c532ecef1e04cc0090d7bbc9953f673362
a8cb71c532ecef1e04cc0090d7bbc9953f673362 b79b86ca4b2865063eac92cbdee0fbb37c5f0743
b79b86ca4b2865063eac92cbdee0fbb37c5f0743 de8934622a88ef3efcae29b44871ffbbbaff4753
de8934622a88ef3efcae29b44871ffbbbaff4753 08a3d6e3440b4221f4191377a95795e408e90962
08a3d6e3440b4221f4191377a95795e408e90962 6275b9b5c591725e9d838cfb0d9a69a676cfb736
0fe0deb19435d23d4b71a8b359dcaf38963b7e2e ece2bfcae2b3897da82c44c8371486191f1e8c10
ece2bfcae2b3897da82c44c8371486191f1e8c10 776745031ae77aa2af8cafe7d4f6084780499182
776745031ae77aa2af8cafe7d4f6084780499182 3d4ae9e02e2e680af484d3072dd52945b6c5b83f
3d4ae9e02e2e680af484d3072dd52945b6c5b83f c460b80adbd94283479a317a59632e9ccf4600ce
c460b80adbd94283479a317a59632e9ccf4600ce 6275b9b5c591725e9d838cfb0d9a69a676cfb736,0b61bcfc94a82dde32ed899aaebf16a055aa4de9
6275b9b5c591725e9d838cfb0d9a69a676cfb736 aaa37a7f4af579627ee26c512e13e995f0d0f777,5be250d6fc1102b29d0529bc344ab2f604b9e71f
aaa37a7f4af579627ee26c512e13e995f0d0f777 bfb563fbe2b0771d55b0f58de88c52b0e65e5157
bfb563fbe2b0771d55b0f58de88c52b0e65e5157 ba67d062aed155feb5898ba14710bb9373576d44
0b61bcfc94a82dde32ed899aaebf16a055aa4de9 ba67d062aed155feb5898ba14710bb9373576d44
ba67d062aed155feb5898ba14710bb9373576d44 93728683855435e098dd85c5865dc9d5394358d5
93728683855435e098dd85c5865dc9d5394358d5 e4718cf7ed770ae44fa1f433204f0313d2a82fef
e4b276aa24aa86724ac0cd824a7227881519c126 b711d2b4301cad9eb2d600792480c8365193e2a1
b711d2b4301cad9eb2d600792480c8365193e2a1 e4718cf7ed770ae44fa1f433204f0313d2a82fef
e4718cf7ed770ae44fa1f433204f0313d2a82fef 87b98ca112fd8143b05ee24c80ab6734d0eca45a
87b98ca112fd8143b05ee24c80ab6734d0eca45a 9f03d93cddf2c7503c53eb639fe66d37cefb6a9b
9f03d93cddf2c7503c53eb639fe66d37cefb6a9b 8b52109594c7f506182eb0cf780a8e30d7605ab7
8b52109594c7f506182eb0cf780a8e30d7605ab7 a630d7090cea3b1b4eb0b760d16b11506f8a59b6
a630d7090cea3b1b4eb0b760d16b11506f8a59b6 4432b3c8fa5e5205e70b2195ff3869f1ebee18a5
4432b3c8fa5e5205e70b2195ff3869f1ebee18a5 441e299543e0f819da8d988de6f36e5f593b5582
441e299543e0f819da8d988de6f36e5f593b5582 c8b69bc77f121376922659f8a45b85026798313c
c8b69bc77f121376922659f8a45b85026798313c a354b5c1cb82ccca2e2ad6ccbe161f88e2e5f0d4
a354b5c1cb82ccca2e2ad6ccbe161f88e2e5f0d4 68d79bff21bb8edebbe644e4ce83279bf1c680b8
68d79bff21bb8edebbe644e4ce83279bf1c680b8 8de562aa651be4ca133a38bc798c05e5e5d9ac4c
8de562aa651be4ca133a38bc798c05e5e5d9ac4c 39718da514fa680d3b36220f278ded94fb864a8f
39718da514fa680d3b36220f278ded94fb864a8f 2e121e3655c16a333eaafabdf3d9a9be0979a99e
2e121e3655c16a333eaafabdf3d9a9be0979a99e a91345f8e232d8d120a1ba2a6959cf9b3009edaf,70391eee14574b70d75f91f6a7ba24fd0ffd93df
a91345f8e232d8d120a1ba2a6959cf9b3009edaf 596110698ae00ddcb774e58070f12f35f67b00ab
596110698ae00ddcb774e58070f12f35f67b00ab 7953e9dc317d38b0b7596c1249c2251c5a8528e4
7953e9dc317d38b0b7596c1249c2251c5a8528e4 4a97fe2a81a0aa10a8bec8e6dea7189f6f3f4dc4
18db59ea626c5bcfe6cad451022a7a369e40fa10 4a97fe2a81a0aa10a8bec8e6dea7189f6f3f4dc4
4a97fe2a81a0aa10a8bec8e6dea7189f6f3f4dc4 7cb9fcca308241b8ee47ac03fbe225f34e4eab44
7cb9fcca308241b8ee47ac03fbe225f34e4eab44 dabd344efb93270ef258726f7870d4485d334add
dabd344efb93270ef258726f7870d4485d334add c0aef352366ca03fc684a04a26af9123a2d7f403
c0aef352366ca03fc684a04a26af9123a2d7f403 3eb427f66fab067982a1525785b6035db89f8fc3
3eb427f66fab067982a1525785b6035db89f8fc3 25d7ed4419d1f50254f6b4f42dd78938ac4e5d1e
25d7ed4419d1f50254f6b4f42dd78938ac4e5d1e b5369b3646723455d85a19efde21b54b20f99b27,c60797615037705d285c62bb15b4ff38efa77d1a
b5369b3646723455d85a19efde21b54b20f99b27 2f99cf9da6268db580aa2046abcc7a4a70644887,55cc440b5e3701841011542eabd752945e529082
2f99cf9da6268db580aa2046abcc7a4a70644887 c0aaf523c6e77bd3dc079a00b5e34a1584863a8a,3944bdfd6a0741fdd3fdf41c8e6ce4d3c124af66
c0aaf523c6e77bd3dc079a00b5e34a1584863a8a 5824d18b655397fe0c5d316c228a886f70ec7e9c,a399f30afdaeb5b0b247b3cfdef05300c6f3803f
5824d18b655397fe0c5d316c228a886f70ec7e9c b054d488904c1db742d4d491a17a2fc7cd287b9e
b054d488904c1db742d4d491a17a2fc7cd287b9e 5fe44e93934b015546033d33ecbff9f3fbec8e9f,621d3c2ef213a43cad70eb978b3308a4c3e0595e
5fe44e93934b015546033d33ecbff9f3fbec8e9f b2ea6646eb94c43ebcbb98463157dcd38c1eac50
b2ea6646eb94c43ebcbb98463157dcd38c1eac50 52d24fd4b2ee1236eb33e6f58ebba63f6af9ba79
52d24fd4b2ee1236eb33e6f58ebba63f6af9ba79 244e676ac0b0e386d7620794d23806c13bca9113
244e676ac0b0e386d7620794d23806c13bca9113 b6bf1dd82ba9dedbbbd963c379960f46a2555df0
2abfcad6eb95acc73472061251b4d9fbb897c989 b6bf1dd82ba9dedbbbd963c379960f46a2555df0
b6bf1dd82ba9dedbbbd963c379960f46a2555df0 0f8fa0be12ccac493e1d7d6be25ddcc7cb16a18e,456c27dbc63c1fd70ae48de899833c5ca02e6e32
456c27dbc63c1fd70ae48de899833c5ca02e6e32 9f5f817c0ed579f0a3a7f3ba3a391403f6ee37bc
9f5f817c0ed579f0a3a7f3ba3a391403f6ee37bc 624ddf95e6b54a943a644c0b5e785c990880999f,0f8fa0be12ccac493e1d7d6be25ddcc7cb16a18e
624ddf95e6b54a943a644c0b5e785c990880999f 9a750784a33ab9d714cdc68949906610f76cb964
9a750784a33ab9d714cdc68949906610f76cb964 0706805720a141819654f6446f832416b5c551a4
0f8fa0be12ccac493e1d7d6be25ddcc7cb16a18e 6f42a208581102d3679d23617d936fa9f3c2225a,6789a2c68486802961334f34c07e8e881261e54c
6789a2c68486802961334f34c07e8e881261e54c a01342192b8f798b5700d48b060a927a1714d636,6f42a208581102d3679d23617d936fa9f3c2225a
6f42a208581102d3679d23617d936fa9f3c2225a 9e070b3017644c5621ea48c2beae202be4232c84,f1f17cc9c784db6de2905ed1374879c7524ba376
0706805720a141819654f6446f832416b5c551a4 92c8226782546e3086fef83d361cf2cc866a9ec1
9e070b3017644c5621ea48c2beae202be4232c84 92c8226782546e3086fef83d361cf2cc866a9ec1,849b4de9ea7d0cdf1fe4006709ee7072f2d13e23
92c8226782546e3086fef83d361cf2cc866a9ec1 170a77e923c53908caff93faf855b22cf871cf6a
170a77e923c53908caff93faf855b22cf871cf6a a533b6fa408fd80356242171e2f827a449ea3812
a533b6fa408fd80356242171e2f827a449ea3812 0ae58081efbb1cc9fc7b20368d9c1208972e767b
0ae58081efbb1cc9fc7b20368d9c1208972e767b 77620de737b78f85f7b30f7e298428ddd67bd928
77620de737b78f85f7b30f7e298428ddd67bd928 b95f77dc672b96ded94aa1392769abcdd8eb2470
b95f77dc672b96ded94aa1392769abcdd8eb2470 9d5efca0bda7c6edb3936805bfb5cd7ae32126dd
9d5efca0bda7c6edb3936805bfb5cd7ae32126dd 703316903c43fb0ee8b445fb4811262fc937968e
703316903c43fb0ee8b445fb4811262fc937968e d5ab33bd7c48cc126fb4ef8f086a6d862df59ef5
d5ab33bd7c48cc126fb4ef8f086a6d862df59ef5 57fdf136efcbda786125e07951d6f8a8b7d14592
57fdf136efcbda786125e07951d6f8a8b7d14592 1b76773ad44f3180d8d0dc4e77dc3b50485aa05d
1b76773ad44f3180d8d0dc4e77dc3b50485aa05d 37803689fe1e764cb95508dad401f34972f73179
37803689fe1e764cb95508dad401f34972f73179 0d58b5f4ddb056a6c8cb2350292d118696aa63b0,f8bf61270c28add4f64ab7d4bc9767a21f18e831
0d58b5f4ddb056a6c8cb2350292d118696aa63b0 76b4277ddca72719e1ce0692c44b8907085f9791
76b4277ddca72719e1ce0692c44b8907085f9791 67151b5753c7819309760ac097aaed33d74e2f93,23745b43026065c5ec6a3d61b964e1d65659036a
67151b5753c7819309760ac097aaed33d74e2f93 a9bdb539385321ec79cace958a816d397b6625c7,43341d56e0f80c10302563c5773d8ed4c2f9f420
a9bdb539385321ec79cace958a816d397b6625c7 5c94f3c9196e51913a0b8516423c95a1cca43362
68a6b805c52f5da6ce3a5c58df25270c2045ab32 adc89fda393154699c1712a5d8869184419dd798
5c94f3c9196e51913a0b8516423c95a1cca43362 c3d314c7c50116890ecf8cb6155c6ca7b9f711ef
c3d314c7c50116890ecf8cb6155c6ca7b9f711ef 25f400c8f88eaddd0ca48c63e6e3f0791cc9f21a
25f400c8f88eaddd0ca48c63e6e3f0791cc9f21a 8a40b211a4197f5016f1497240761123a7523fb2
8a40b211a4197f5016f1497240761123a7523fb2 a1dbd06515099561a77523765ad303e23051b456
a1dbd06515099561a77523765ad303e23051b456 2f03232e1d7998dd77f1e118585ba2e1420304e8,5464c15055afb0cf2627838a18d92f1081c7b066
2f03232e1d7998dd77f1e118585ba2e1420304e8 a5ed8f0caaed7d6b63ad93abc1dddeb45a27fb8e
a5ed8f0caaed7d6b63ad93abc1dddeb45a27fb8e 2120db9cffa7487197f01bf528fdb79c5319d0c9,2f6825c738be3a9d276e65d43975278ba174d9b5
2120db9cffa7487197f01bf528fdb79c5319d0c9 10b99d180db996c6f438191e7521b7c39826979b,32584d6c1d9d8af3873babb0d356e8400c9582c0
10b99d180db996c6f438191e7521b7c39826979b bcfb084eb25a7124496664afc5c48df85d85e838
bcfb084eb25a7124496664afc5c48df85d85e838 82bd7da1b39153c0429fb36653a21994150420c1
82bd7da1b39153c0429fb36653a21994150420c1 900f227fc0add02b87b86d8c509242eff7a6c264,2890f3b6933eb96b4f338b85524ab4562abda157
900f227fc0add02b87b86d8c509242eff7a6c264 eac8148602a78ff2819b562f63e09679f24b4cbf
eac8148602a78ff2819b562f63e09679f24b4cbf 841b30b8c962d535454b80a8e0bb5d4161225699
841b30b8c962d535454b80a8e0bb5d4161225699 277cc86ec7d1921574b6fdc40e5af33efd1d27d4
277cc86ec7d1921574b6fdc40e5af33efd1d27d4 69ed787cf98b13e1c6b9031871fbe5fe88284bd3
69ed787cf98b13e1c6b9031871fbe5fe88284bd3 1bf5c0bd2017622e9d5cad94683a7f00b3a7985d,a692915fb36b1f34dabf71452af63e04c91be209
1bf5c0bd2017622e9d5cad94683a7f00b3a7985d d823b9ddaeb9c1f2dfe6e1e914337bd0543357ae,cd95146b0abcec1cd52629d80db969fdd27fa303
d823b9ddaeb9c1f2dfe6e1e914337bd0543357ae 5148b5915f997c933f63570bdff8461f1aa7278e
5148b5915f997c933f63570bdff8461f1aa7278e a6afe6e1d7adba44262416bd4931e54f70b479d8,1c79e4a8344be1d5d9a293a542fc057aa524c50d
a6afe6e1d7adba44262416bd4931e54f70b479d8 fc84397e48939f77d2f783eb85143bd9db674e1a
fc84397e48939f77d2f783eb85143bd9db674e1a 20865cc9cf5470ee39ab9e99ef6a853233a9ca2a,e821f056086d11d0a8ff2fa6ae58f5a44678f707
20865cc9cf5470ee39ab9e99ef6a853233a9ca2a ddc112387c36d1c270004bc9458b3cd3d6749ce9
ddc112387c36d1c270004bc9458b3cd3d6749ce9 6a182939795451cf6d3817c41c343ecf905e831c
6a182939795451cf6d3817c41c343ecf905e831c c269abcad799c19d0488a098ad3a861256e4aaac
c269abcad799c19d0488a098ad3a861256e4aaac 2a906e05b06fa45908f2cf37b416649fecf09b7e,85fa0e2f1429aadd858971eec1a3798867a5112e
2a906e05b06fa45908f2cf37b416649fecf09b7e 346da738c4dd3e54fc827b42ca65790e22239c23,d806a4bc7493caf7d6ac3d447ec476eb4ce428fd
24a725dc99507e55283f453f7b5ca7d8e70be52f 3766f8e4ea2efd1e01520e99d4e5bf2885c302c4,346da738c4dd3e54fc827b42ca65790e22239c23
7b2c89a42fa0a68561aee72886a479db368d713b fa65768bcc90fec0ddaf912d92a6bda4d06b3f61,346da738c4dd3e54fc827b42ca65790e22239c23
aca1299f55bdb0844095f98de9c4a2008eac6ad0 a16fc0d2d04199c1d6664bc80706f165dc915d39,346da738c4dd3e54fc827b42ca65790e22239c23
346da738c4dd3e54fc827b42ca65790e22239c23 b960ebe7d03d215353778093773b8ce3bcc9fb27,eaf721a3d3f690dc5766dca97c05ee8f779f828b
5464c15055afb0cf2627838a18d92f1081c7b066 259631117742cbc4a691f43bc3ce278082455ab1,39bde846fc3cee61a8ca81872ddde83253f48925
b960ebe7d03d215353778093773b8ce3bcc9fb27 259631117742cbc4a691f43bc3ce278082455ab1,03e6b6ae8854c6f585f3e82553dfc5311e49f53e
259631117742cbc4a691f43bc3ce278082455ab1 cdbe742d201adb616cba467563fb2bfb524dd16a
cdbe742d201adb616cba467563fb2bfb524dd16a d7af4dd892b8a48a5107c4bf871d5d25f63e8511
d7af4dd892b8a48a5107c4bf871d5d25f63e8511 614169b1acb86b21b562f807a6b54aa164d4056a
614169b1acb86b21b562f807a6b54aa164d4056a 7e269b22b6070768ce18c0b81d7b802662b2b6ed
7e269b22b6070768ce18c0b81d7b802662b2b6ed 7d703fee73ee850af7325ac7e4eebb6514c2757e
7d703fee73ee850af7325ac7e4eebb6514c2757e 6b673d12166ae1a5729aa517bdfd2e8ad974170e
6b673d12166ae1a5729aa517bdfd2e8ad974170e edc83414c9a7955c8f874c2fed261d8e1ae2eb91
edc83414c9a7955c8f874c2fed261d8e1ae2eb91 17f63f989af77ffcca34d142b8ef5c210323e098
17f63f989af77ffcca34d142b8ef5c210323e098 958206e68abbb9bb2cc76256ab3202363678e61f,06a1cb9d9b23aadc5231cbb188b2fac1003fbe28
958206e68abbb9bb2cc76256ab3202363678e61f da26ce8d3cc378e9e0d8246540197575428132f9
da26ce8d3cc378e9e0d8246540197575428132f9 aeabc7304c582c9a58e6098443430cbd2b323616
aeabc7304c582c9a58e6098443430cbd2b323616 6efedc27d5e08a15fb9501ad32c257738c48334e
6efedc27d5e08a15fb9501ad32c257738c48334e 3a9471a6ea20a92b57325b0c56448d3e313a1d1a,1eb7abcd285650928a22eb81185a63d36b1b2cba
3a9471a6ea20a92b57325b0c56448d3e313a1d1a 6aa0069d074711085d57def494f56ddeb65a7551,6129574e1588a0cf30d5d0762a8cf49a9ebb5585
6aa0069d074711085d57def494f56ddeb65a7551 704e7039441ea5383545da405e3b5f4cf01077c3,b0c45c85fe85689c0c59660a15e3476340b6819a
704e7039441ea5383545da405e3b5f4cf01077c3 b44a2afd2a47a63d510b1d4b7d58cdf5fc13b65d
b0c45c85fe85689c0c59660a15e3476340b6819a 8a26c9c9d71007dad93508ff17c5971ff7dc13b3
8a26c9c9d71007dad93508ff17c5971ff7dc13b3 b44a2afd2a47a63d510b1d4b7d58cdf5fc13b65d,8528e93d3ce01d0b8b209c599ab261aa1987a108
b44a2afd2a47a63d510b1d4b7d58cdf5fc13b65d 8bb5134286f52a3dbb1979de5bee25d7460b3c36,09c716a4e30e8744365c158619b44006fbf6d3b6
fa65768bcc90fec0ddaf912d92a6bda4d06b3f61 bb194efe1821622d96c8c43d2a4c9de17e800391,8bb5134286f52a3dbb1979de5bee25d7460b3c36
a01342192b8f798b5700d48b060a927a1714d636 bbe5c643c42223f97c8914ba3cd26b3c8d2c5030,8bb5134286f52a3dbb1979de5bee25d7460b3c36
8bb5134286f52a3dbb1979de5bee25d7460b3c36 cb8d623593567f34e3fbf89a1b640cdb7b1eda75,2fae4888f332dfba920901c5afaf9ac448ca89c9
cb8d623593567f34e3fbf89a1b640cdb7b1eda75 c31a46930cee2835641e43171f6c3f8800da3ae8,e71001dca11670f6e468d5b3c05c78292a748834
c31a46930cee2835641e43171f6c3f8800da3ae8 90059ea0179772a7d296a382bb3c94865003c33e,dec8d412cdcc82e55fd516b1b1a874f290e7a806
90059ea0179772a7d296a382bb3c94865003c33e 07eda936ba952eb3255eca4e2cbc00d49c3fd831,a2b3efa030a54e6cfb6c6736fca7e1e27d07cd15
07eda936ba952eb3255eca4e2cbc00d49c3fd831 0ac98cae0481794557025cd5002aa2508d5347b6
0ac98cae0481794557025cd5002aa2508d5347b6 fdfd424b83ec718a8cf74f38b01d8f1005e01faa,50414b8e0e67e191f1ae38bde54e30189de97b34
fdfd424b83ec718a8cf74f38b01d8f1005e01faa 0cadfc4182b8bb43635020f393f5cdd6578b7cfd
0cadfc4182b8bb43635020f393f5cdd6578b7cfd dcf421dabda2384d57913343e73dd01688eb4dcf
dcf421dabda2384d57913343e73dd01688eb4dcf 82e28e89e54c198a6aa3c6435b5b32eec05ed65f
82e28e89e54c198a6aa3c6435b5b32eec05ed65f 657b6ecb353c1f5b0b91d2d5161aff9063af3fb0
657b6ecb353c1f5b0b91d2d5161aff9063af3fb0 afa3279d3b6cb8913ba3d6eed8e635f66fa59d8e,30dc6100056269e9d384711478be9dd1bd744ddf
afa3279d3b6cb8913ba3d6eed8e635f66fa59d8e 4485968e237121d19cce63d18312987c84f0860e,599461b731bbb3081f49dcd72c356695da4bf483
4485968e237121d19cce63d18312987c84f0860e 21dd573ab7ab0a63d35c0df07df08dae8b19bb16,08a1393c61b3c6d2ee96a35b52ae945806d0299e
21dd573ab7ab0a63d35c0df07df08dae8b19bb16 66eb2de9fa18125906e5d13abf52705839c9d088,3129220de08efe91135e7b1256772167e0dcdf15
66eb2de9fa18125906e5d13abf52705839c9d088 fc9432d5a51c65f1716cf0ba20b1e693ccd2edce,5941191cd2682ef374df3afeebc0ae9d242162db
fc9432d5a51c65f1716cf0ba20b1e693ccd2edce f72fea4b3bc98ca7ab186eacce57b3dfd2557032
f72fea4b3bc98ca7ab186eacce57b3dfd2557032 ade6384a7b0e4d065e18076ffa901e580679e26d,dd090afbe47f0aa25d6ec8cfe484fa02c23eb61a

Added fossil-utils/justtesting/setup.dat version [27b5f4c974].










1
2
3
4
5
6
7
8
9
+
+
+
+
+
+
+
+
+
[command]
0 rm -rf /tmp/$USER/megatest
1 mkdir -p /tmp/$USER/megatest
2 cp /home/matt/fossils/megatest.fossil /tmp/$USER/megatest
3 cd /tmp/$USER/megatest
4 fossil open megatest.fossil;fossil up trunk
5 fossil set autosync 0
7 fossil set gmerge ''
8 fossil scrub --private --force

Added fossil-utils/justtesting/sheet-names.cfg version [a2c6169f2d].





1
2
3
4
+
+
+
+
timeline
extra
branches
setup

Added fossil-utils/justtesting/sxml/_sheets.sxml version [170f68b304].






































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
((@ (http://www.w3.org/2001/XMLSchema-instance:schemaLocation
      "http://www.gnumeric.org/v9.xsd"))
 (http://www.gnumeric.org/v10.dtd:Version
   (@ (Minor "17")
      (Major "10")
      (Full "1.10.17")
      (Epoch "1")))
 (http://www.gnumeric.org/v10.dtd:Attributes
   (http://www.gnumeric.org/v10.dtd:Attribute
     (http://www.gnumeric.org/v10.dtd:type "4")
     (http://www.gnumeric.org/v10.dtd:name
       "WorkbookView::show_horizontal_scrollbar")
     (http://www.gnumeric.org/v10.dtd:value "TRUE"))
   (http://www.gnumeric.org/v10.dtd:Attribute
     (http://www.gnumeric.org/v10.dtd:type "4")
     (http://www.gnumeric.org/v10.dtd:name
       "WorkbookView::show_vertical_scrollbar")
     (http://www.gnumeric.org/v10.dtd:value "TRUE"))
   (http://www.gnumeric.org/v10.dtd:Attribute
     (http://www.gnumeric.org/v10.dtd:type "4")
     (http://www.gnumeric.org/v10.dtd:name
       "WorkbookView::show_notebook_tabs")
     (http://www.gnumeric.org/v10.dtd:value "TRUE"))
   (http://www.gnumeric.org/v10.dtd:Attribute
     (http://www.gnumeric.org/v10.dtd:type "4")
     (http://www.gnumeric.org/v10.dtd:name
       "WorkbookView::do_auto_completion")
     (http://www.gnumeric.org/v10.dtd:value "TRUE"))
   (http://www.gnumeric.org/v10.dtd:Attribute
     (http://www.gnumeric.org/v10.dtd:type "4")
     (http://www.gnumeric.org/v10.dtd:name
       "WorkbookView::is_protected")
     (http://www.gnumeric.org/v10.dtd:value "FALSE")))
 (urn:oasis:names:tc:opendocument:xmlns:office:1.0:document-meta
   (@ (urn:oasis:names:tc:opendocument:xmlns:office:1.0:version
        "1.2"))
   (urn:oasis:names:tc:opendocument:xmlns:office:1.0:meta
     (http://purl.org/dc/elements/1.1/:date
       "2020-06-01T04:28:18Z")
     (urn:oasis:names:tc:opendocument:xmlns:meta:1.0:creation-date
       "2020-06-01T01:13:31Z")))
 (http://www.gnumeric.org/v10.dtd:Calculation
   (@ (MaxIterations "100")
      (ManualRecalc "0")
      (IterationTolerance "0.001")
      (FloatRadix "2")
      (FloatDigits "53")
      (EnableIteration "1")))
 (http://www.gnumeric.org/v10.dtd:SheetNameIndex
   (http://www.gnumeric.org/v10.dtd:SheetName
     (@ (http://www.gnumeric.org/v10.dtd:Rows "65536")
        (http://www.gnumeric.org/v10.dtd:Cols "256"))
     "timeline")
   (http://www.gnumeric.org/v10.dtd:SheetName
     (@ (http://www.gnumeric.org/v10.dtd:Rows "65536")
        (http://www.gnumeric.org/v10.dtd:Cols "256"))
     "extra")
   (http://www.gnumeric.org/v10.dtd:SheetName
     (@ (http://www.gnumeric.org/v10.dtd:Rows "65536")
        (http://www.gnumeric.org/v10.dtd:Cols "256"))
     "branches")
   (http://www.gnumeric.org/v10.dtd:SheetName
     (@ (http://www.gnumeric.org/v10.dtd:Rows "65536")
        (http://www.gnumeric.org/v10.dtd:Cols "256"))
     "setup"))
 (http://www.gnumeric.org/v10.dtd:Geometry
   (@ (Width "2220") (Height "804")))
 (http://www.gnumeric.org/v10.dtd:UIData
   (@ (SelectedTab "0"))))

Added fossil-utils/justtesting/sxml/_workbook.sxml version [96ffb7f9d5].


1
+
(*TOP* (*PI* xml "version=\"1.0\" encoding=\"UTF-8\""))

Added fossil-utils/justtesting/sxml/branches.sxml version [ba44d3c184].








































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(http://www.gnumeric.org/v10.dtd:Sheet
  (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE")
     (OutlineSymbolsRight "1")
     (OutlineSymbolsBelow "1")
     (HideZero "0")
     (HideRowHeader "0")
     (HideGrid "0")
     (HideColHeader "0")
     (GridColor "0:0:0")
     (DisplayOutlines "1")
     (DisplayFormulas "0"))
  (http://www.gnumeric.org/v10.dtd:MaxCol "8")
  (http://www.gnumeric.org/v10.dtd:MaxRow "16")
  (http://www.gnumeric.org/v10.dtd:Zoom "1")
  (http://www.gnumeric.org/v10.dtd:Names
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Print_Area")
      (http://www.gnumeric.org/v10.dtd:value "#REF!")
      (http://www.gnumeric.org/v10.dtd:position "A1"))
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Sheet_Title")
      (http://www.gnumeric.org/v10.dtd:value
        "\"First_Sheet\"")
      (http://www.gnumeric.org/v10.dtd:position "A1")))
  (http://www.gnumeric.org/v10.dtd:PrintInformation
    (http://www.gnumeric.org/v10.dtd:Margins
      (http://www.gnumeric.org/v10.dtd:top
        (@ (PrefUnit "mm") (Points "93.26")))
      (http://www.gnumeric.org/v10.dtd:bottom
        (@ (PrefUnit "mm") (Points "93.26")))
      (http://www.gnumeric.org/v10.dtd:left
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:right
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:header
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:footer
        (@ (PrefUnit "mm") (Points "72"))))
    (http://www.gnumeric.org/v10.dtd:Scale
      (@ (type "percentage") (percentage "100")))
    (http://www.gnumeric.org/v10.dtd:vcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:hcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:grid
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:even_if_only_styles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:monochrome
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:draft
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:titles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:do_not_print
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:print_range
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:order
      "d_then_r")
    (http://www.gnumeric.org/v10.dtd:orientation
      "portrait")
    (http://www.gnumeric.org/v10.dtd:Header
      (@ (Right "") (Middle "&[tab]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:Footer
      (@ (Right "") (Middle "&[page]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:paper
      "na_letter")
    (http://www.gnumeric.org/v10.dtd:comments "none")
    (http://www.gnumeric.org/v10.dtd:errors
      "as_displayed"))
  (http://www.gnumeric.org/v10.dtd:Styles
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "0")
         (startCol "0")
         (endRow "65535")
         (endCol "255"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans"))))
  (http://www.gnumeric.org/v10.dtd:Cols
    (@ (DefaultSizePts "48"))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "95.25") (No "0")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "99") (No "1") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "64.01") (No "2") (Count "7"))))
  (http://www.gnumeric.org/v10.dtd:Rows
    (@ (DefaultSizePts "12.1"))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.64") (No "0")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "1") (Count "16"))))
  (http://www.gnumeric.org/v10.dtd:Selections
    (@ (CursorRow "2") (CursorCol "1"))
    (http://www.gnumeric.org/v10.dtd:Selection
      (@ (startRow "2")
         (startCol "1")
         (endRow "2")
         (endCol "1"))))
  (http://www.gnumeric.org/v10.dtd:SheetLayout
    (@ (TopLeft "A2"))
    (http://www.gnumeric.org/v10.dtd:FreezePanes
      (@ (UnfrozenTopLeft "A2") (FrozenTopLeft "A1"))))
  (http://www.gnumeric.org/v10.dtd:Solver
    (@ (ProgramR "0")
       (ProblemType "0")
       (NonNeg "1")
       (ModelType "0")
       (MaxTime "60")
       (MaxIter "1000")
       (Discr "0")
       (AutoScale "0"))))

Added fossil-utils/justtesting/sxml/extra.sxml version [b737f7669d].










































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(http://www.gnumeric.org/v10.dtd:Sheet
  (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE")
     (OutlineSymbolsRight "1")
     (OutlineSymbolsBelow "1")
     (HideZero "0")
     (HideRowHeader "0")
     (HideGrid "0")
     (HideColHeader "0")
     (GridColor "0:0:0")
     (DisplayOutlines "1")
     (DisplayFormulas "0"))
  (http://www.gnumeric.org/v10.dtd:MaxCol "8")
  (http://www.gnumeric.org/v10.dtd:MaxRow "722")
  (http://www.gnumeric.org/v10.dtd:Zoom "1")
  (http://www.gnumeric.org/v10.dtd:Names
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Print_Area")
      (http://www.gnumeric.org/v10.dtd:value "#REF!")
      (http://www.gnumeric.org/v10.dtd:position "A1"))
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Sheet_Title")
      (http://www.gnumeric.org/v10.dtd:value
        "\"First_Sheet\"")
      (http://www.gnumeric.org/v10.dtd:position "A1")))
  (http://www.gnumeric.org/v10.dtd:PrintInformation
    (http://www.gnumeric.org/v10.dtd:Margins
      (http://www.gnumeric.org/v10.dtd:top
        (@ (PrefUnit "mm") (Points "93.26")))
      (http://www.gnumeric.org/v10.dtd:bottom
        (@ (PrefUnit "mm") (Points "93.26")))
      (http://www.gnumeric.org/v10.dtd:left
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:right
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:header
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:footer
        (@ (PrefUnit "mm") (Points "72"))))
    (http://www.gnumeric.org/v10.dtd:Scale
      (@ (type "percentage") (percentage "100")))
    (http://www.gnumeric.org/v10.dtd:vcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:hcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:grid
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:even_if_only_styles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:monochrome
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:draft
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:titles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:do_not_print
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:print_range
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:order
      "d_then_r")
    (http://www.gnumeric.org/v10.dtd:orientation
      "portrait")
    (http://www.gnumeric.org/v10.dtd:Header
      (@ (Right "") (Middle "&[tab]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:Footer
      (@ (Right "") (Middle "&[page]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:paper
      "na_letter")
    (http://www.gnumeric.org/v10.dtd:comments "none")
    (http://www.gnumeric.org/v10.dtd:errors
      "as_displayed"))
  (http://www.gnumeric.org/v10.dtd:Styles
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "0")
         (startCol "0")
         (endRow "65535")
         (endCol "255"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans"))))
  (http://www.gnumeric.org/v10.dtd:Cols
    (@ (DefaultSizePts "48"))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "243") (No "0")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "462") (No "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "64.01") (No "2") (Count "7"))))
  (http://www.gnumeric.org/v10.dtd:Rows
    (@ (DefaultSizePts "12.1"))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.64") (No "0")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "1") (Count "17")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "18") (Count "705"))))
  (http://www.gnumeric.org/v10.dtd:Selections
    (@ (CursorRow "3") (CursorCol "1"))
    (http://www.gnumeric.org/v10.dtd:Selection
      (@ (startRow "3")
         (startCol "1")
         (endRow "3")
         (endCol "1"))))
  (http://www.gnumeric.org/v10.dtd:SheetLayout
    (@ (TopLeft "A2"))
    (http://www.gnumeric.org/v10.dtd:FreezePanes
      (@ (UnfrozenTopLeft "A2") (FrozenTopLeft "A1"))))
  (http://www.gnumeric.org/v10.dtd:Solver
    (@ (ProgramR "0")
       (ProblemType "0")
       (NonNeg "1")
       (ModelType "0")
       (MaxTime "60")
       (MaxIter "1000")
       (Discr "0")
       (AutoScale "0"))))

Added fossil-utils/justtesting/sxml/setup.sxml version [1e32386adc].


































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(http://www.gnumeric.org/v10.dtd:Sheet
  (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE")
     (OutlineSymbolsRight "1")
     (OutlineSymbolsBelow "1")
     (HideZero "0")
     (HideRowHeader "0")
     (HideGrid "0")
     (HideColHeader "0")
     (GridColor "0:0:0")
     (DisplayOutlines "1")
     (DisplayFormulas "0"))
  (http://www.gnumeric.org/v10.dtd:MaxCol "1")
  (http://www.gnumeric.org/v10.dtd:MaxRow "8")
  (http://www.gnumeric.org/v10.dtd:Zoom "1")
  (http://www.gnumeric.org/v10.dtd:Names
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Print_Area")
      (http://www.gnumeric.org/v10.dtd:value "#REF!")
      (http://www.gnumeric.org/v10.dtd:position "A1"))
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Sheet_Title")
      (http://www.gnumeric.org/v10.dtd:value
        "\"setup\"")
      (http://www.gnumeric.org/v10.dtd:position "A1")))
  (http://www.gnumeric.org/v10.dtd:PrintInformation
    (http://www.gnumeric.org/v10.dtd:Margins
      (http://www.gnumeric.org/v10.dtd:top
        (@ (PrefUnit "mm") (Points "120")))
      (http://www.gnumeric.org/v10.dtd:bottom
        (@ (PrefUnit "mm") (Points "120")))
      (http://www.gnumeric.org/v10.dtd:left
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:right
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:header
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:footer
        (@ (PrefUnit "mm") (Points "72"))))
    (http://www.gnumeric.org/v10.dtd:Scale
      (@ (type "percentage") (percentage "100")))
    (http://www.gnumeric.org/v10.dtd:vcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:hcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:grid
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:even_if_only_styles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:monochrome
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:draft
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:titles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:do_not_print
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:print_range
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:order
      "d_then_r")
    (http://www.gnumeric.org/v10.dtd:orientation
      "portrait")
    (http://www.gnumeric.org/v10.dtd:Header
      (@ (Right "") (Middle "&[TAB]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:Footer
      (@ (Right "") (Middle "Page &[PAGE]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:paper
      "na_letter")
    (http://www.gnumeric.org/v10.dtd:comments "none")
    (http://www.gnumeric.org/v10.dtd:errors
      "as_displayed"))
  (http://www.gnumeric.org/v10.dtd:Styles
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "0")
         (startCol "0")
         (endRow "65535")
         (endCol "255"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans"))))
  (http://www.gnumeric.org/v10.dtd:Cols
    (@ (DefaultSizePts "48"))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "48") (No "0")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "333") (No "1"))))
  (http://www.gnumeric.org/v10.dtd:Rows
    (@ (DefaultSizePts "12.75"))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "0") (Count "9"))))
  (http://www.gnumeric.org/v10.dtd:Selections
    (@ (CursorRow "7") (CursorCol "0"))
    (http://www.gnumeric.org/v10.dtd:Selection
      (@ (startRow "7")
         (startCol "0")
         (endRow "7")
         (endCol "255"))))
  (http://www.gnumeric.org/v10.dtd:SheetLayout
    (@ (TopLeft "A1")))
  (http://www.gnumeric.org/v10.dtd:Solver
    (@ (ProgramR "0")
       (ProblemType "0")
       (NonNeg "1")
       (ModelType "0")
       (MaxTime "60")
       (MaxIter "1000")
       (Discr "0")
       (AutoScale "0"))))

Added fossil-utils/justtesting/sxml/timeline.sxml version [78bf77cda1].




































































































































































































































































































































































































































































































































































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(http://www.gnumeric.org/v10.dtd:Sheet
  (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE")
     (OutlineSymbolsRight "1")
     (OutlineSymbolsBelow "1")
     (HideZero "0")
     (HideRowHeader "0")
     (HideGrid "0")
     (HideColHeader "0")
     (GridColor "0:0:0")
     (DisplayOutlines "1")
     (DisplayFormulas "0"))
  (http://www.gnumeric.org/v10.dtd:MaxCol "17")
  (http://www.gnumeric.org/v10.dtd:MaxRow "65535")
  (http://www.gnumeric.org/v10.dtd:Zoom "1")
  (http://www.gnumeric.org/v10.dtd:Names
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Print_Area")
      (http://www.gnumeric.org/v10.dtd:value "#REF!")
      (http://www.gnumeric.org/v10.dtd:position "A1"))
    (http://www.gnumeric.org/v10.dtd:Name
      (http://www.gnumeric.org/v10.dtd:name
        "Sheet_Title")
      (http://www.gnumeric.org/v10.dtd:value
        "\"First_Sheet\"")
      (http://www.gnumeric.org/v10.dtd:position "A1")))
  (http://www.gnumeric.org/v10.dtd:PrintInformation
    (http://www.gnumeric.org/v10.dtd:Margins
      (http://www.gnumeric.org/v10.dtd:top
        (@ (PrefUnit "mm") (Points "93.26")))
      (http://www.gnumeric.org/v10.dtd:bottom
        (@ (PrefUnit "mm") (Points "93.26")))
      (http://www.gnumeric.org/v10.dtd:left
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:right
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:header
        (@ (PrefUnit "mm") (Points "72")))
      (http://www.gnumeric.org/v10.dtd:footer
        (@ (PrefUnit "mm") (Points "72"))))
    (http://www.gnumeric.org/v10.dtd:Scale
      (@ (type "percentage") (percentage "100")))
    (http://www.gnumeric.org/v10.dtd:vcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:hcenter
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:grid
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:even_if_only_styles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:monochrome
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:draft
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:titles
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:do_not_print
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:print_range
      (@ (value "0")))
    (http://www.gnumeric.org/v10.dtd:order
      "d_then_r")
    (http://www.gnumeric.org/v10.dtd:orientation
      "portrait")
    (http://www.gnumeric.org/v10.dtd:Header
      (@ (Right "") (Middle "&[tab]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:Footer
      (@ (Right "") (Middle "&[page]") (Left "")))
    (http://www.gnumeric.org/v10.dtd:paper
      "na_letter")
    (http://www.gnumeric.org/v10.dtd:comments "none")
    (http://www.gnumeric.org/v10.dtd:errors
      "as_displayed"))
  (http://www.gnumeric.org/v10.dtd:Styles
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "0")
         (startCol "0")
         (endRow "255")
         (endCol "63"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "256")
         (startCol "0")
         (endRow "431")
         (endCol "7"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "432")
         (startCol "0")
         (endRow "463")
         (endCol "4"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "464")
         (startCol "0")
         (endRow "511")
         (endCol "7"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "512")
         (startCol "0")
         (endRow "65535")
         (endCol "63"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "432")
         (startCol "5")
         (endRow "448")
         (endCol "5"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "449")
         (startCol "5")
         (endRow "449")
         (endCol "5"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "450")
         (startCol "5")
         (endRow "463")
         (endCol "5"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "432")
         (startCol "6")
         (endRow "463")
         (endCol "7"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "256")
         (startCol "8")
         (endRow "511")
         (endCol "63"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans")))
    (http://www.gnumeric.org/v10.dtd:StyleRegion
      (@ (startRow "0")
         (startCol "64")
         (endRow "65535")
         (endCol "255"))
      (http://www.gnumeric.org/v10.dtd:Style
        (@ (WrapText "0")
           (VAlign "2")
           (ShrinkToFit "0")
           (Shade "0")
           (Rotation "0")
           (PatternColor "0:0:0")
           (Locked "1")
           (Indent "0")
           (Hidden "0")
           (HAlign "1")
           (Format "General")
           (Fore "0:0:0")
           (Back "FFFF:FFFF:FFFF"))
        (http://www.gnumeric.org/v10.dtd:Font
          (@ (Unit "10")
             (Underline "0")
             (StrikeThrough "0")
             (Script "0")
             (Italic "0")
             (Bold "0"))
          "Sans"))))
  (http://www.gnumeric.org/v10.dtd:Cols
    (@ (DefaultSizePts "48"))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "243.8") (No "0")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "89.25")
         (No "1")
         (HardSize "1")
         (Count "2")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "51") (No "3") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "49.5") (No "4") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "105") (No "5") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "48") (No "6")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "70.5") (No "7") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "48") (No "8")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "60.75") (No "9") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "34.5") (No "10") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "177") (No "11") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "63.75") (No "12") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "413.2") (No "13") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "213.8") (No "14") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "198.8") (No "15") (HardSize "1")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "104.2") (No "16")))
    (http://www.gnumeric.org/v10.dtd:ColInfo
      (@ (Unit "78.75") (No "17"))))
  (http://www.gnumeric.org/v10.dtd:Rows
    (@ (DefaultSizePts "12.1"))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "0")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5")
         (No "1")
         (Hidden "1")
         (Count "17")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1")
         (No "18")
         (Hidden "1")
         (Count "41")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "59") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1")
         (No "60")
         (Hidden "1")
         (Count "131")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "191") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1")
         (No "192")
         (Hidden "1")
         (Count "215")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "407")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "408") (Count "10")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "418") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "419") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "420")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "421") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "422") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "423") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "424") (Count "18")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "442") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "443")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "444") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "445")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1")
         (No "446")
         (Hidden "1")
         (Count "3")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "449") (Count "7")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5") (No "456") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "457") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "458") (Count "2")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5")
         (No "460")
         (Hidden "1")
         (Count "3")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "463") (Count "4")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5")
         (No "467")
         (Hidden "1")
         (Count "15")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "482") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5")
         (No "483")
         (Hidden "1")
         (Count "5")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1") (No "488") (Hidden "1")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5")
         (No "489")
         (Hidden "1")
         (Count "4")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1")
         (No "493")
         (Hidden "1")
         (Count "5")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "13.5")
         (No "498")
         (Hidden "1")
         (Count "3")))
    (http://www.gnumeric.org/v10.dtd:RowInfo
      (@ (Unit "12.1")
         (No "501")
         (Hidden "1")
         (Count "65035"))))
  (http://www.gnumeric.org/v10.dtd:Selections
    (@ (CursorRow "426") (CursorCol "13"))
    (http://www.gnumeric.org/v10.dtd:Selection
      (@ (startRow "426")
         (startCol "13")
         (endRow "426")
         (endCol "13"))))
  (http://www.gnumeric.org/v10.dtd:SheetLayout
    (@ (TopLeft "A2"))
    (http://www.gnumeric.org/v10.dtd:FreezePanes
      (@ (UnfrozenTopLeft "A2") (FrozenTopLeft "A1"))))
  (http://www.gnumeric.org/v10.dtd:Filters
    (http://www.gnumeric.org/v10.dtd:Filter
      (@ (Area "A1:Q65536"))
      (http://www.gnumeric.org/v10.dtd:Field
        (@ (ValueType0 "v1.65-broken")
           (Value0 "60")
           (Type "expr")
           (Op0 "eq")
           (Index "1")))))
  (http://www.gnumeric.org/v10.dtd:Solver
    (@ (ProgramR "0")
       (ProblemType "0")
       (NonNeg "1")
       (ModelType "0")
       (MaxTime "60")
       (MaxIter "1000")
       (Discr "0")
       (AutoScale "0"))))

Added fossil-utils/justtesting/timeline.dat version [59068cf799].

cannot compute difference between binary files

Modified items.scm from [fd1d57a170] to [16328a4b96].

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
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








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
-
+
















-
+
+
+
+
+

-
+
+
+
+






(define (items:check-valid-items class item)
  (let ((valid-values (let ((s (configf:lookup *configdat* "validvalues" class)))
			(if s (string-split s) #f))))
    (if valid-values
	(if (member item valid-values)
	    item #f)
	item)))

;;  '(("k1" "k2" "k3")
;;    ("a" "b" "c")
;;    ("d" "e" "f"))
;;
;;    => '((("k1" "a")("k2" "b")("k3" "c"))
;;         (("k1" "d")("k2" "e")("k3" "f")))
;;
(define (items:first-row-intersperse data)
  (if (< (length data) 2)
      '()
      (let ((header (car data))
	    (rows   (cdr data)))
	(map (lambda (row)
	       (map list header row))
	     rows))))

;; k1/k2/k3
;; a/b/c
;; d/e/f
;;    => '(("k1" "k2" "k3")
;;         ("a" "b" "c")
;;         ("d" "e" "f"))
;;
;;    => '((("k1" "a")("k2" "b")("k3" "c"))
;;         (("k1" "d")("k2" "e")("k3" "f")))
;;
(define (items:read-items-file fname ftype) ;; 'sxml 'slash 'space 
  (if (and fname (file-exists? fname))
      (items:first-row-intersperse (case ftype
				     ((slash space)
				      (let ((splitter (case ftype
							((slash) (lambda (x)(string-split x "/")))
							(else    string-split))))
					(debug:print 0 *default-log-port* "Reading " fname " of type " ftype)
					(with-input-from-file fname
					  (lambda ()
					    (let loop ((inl (read-line))
						       (res '()))
					      (if (eof-object? inl)
						  res
						  (loop (read-line)(cons (splitter inl) res))))))))
				     ((sxml)(with-input-from-file fname read))
				     (else (debug:print 0 *default-log-port* "items file type " ftype " not recognised"))))
      (begin
	(if fname (debug:print 0 *default-log-port* "no items file " fname " found"))
	'())))

(define (items:get-items-from-config tconfig)
  (let* ((slashf      (configf:lookup tconfig "itemopts" "slash")) ;; a/b/c\nd/e/f\n ...
	 (sxmlf       (configf:lookup tconfig "itemopts" "sxml"))  ;; '(("a" "b" "c")("d" "e" "f") ...)
	 (spacef      (configf:lookup tconfig "itemopts" "space")) ;; a b c\nd e f\n ...
  (let* ((have-items  (hash-table-ref/default tconfig "items"      #f))
	 (have-items  (hash-table-ref/default tconfig "items"      #f))
	 (have-itable (hash-table-ref/default tconfig "itemstable" #f))
	 (items       (hash-table-ref/default tconfig "items"      '()))
	 (itemstable  (hash-table-ref/default tconfig "itemstable" '())))
    (debug:print 5 *default-log-port* "items: " items " itemstable: " itemstable)
    (set! items (map (lambda (item)
		       (if (procedure? (cadr item))
			   (list (car item)((cadr item)))  ;; evaluate the proc
			   item))
		     items))
    (set! itemstable (map (lambda (item)
			    (if (procedure? (cadr item))
				(list (car item)((cadr item)))  ;; evaluate the proc
				item))
			  itemstable))
    (if (and have-items  (null? items))     (debug:print 0 *default-log-port* "WARNING:[items] section in testconfig but no entries defined"))
    (if (and have-itable (null? itemstable))(debug:print 0 *default-log-port* "WARNNG:[itemstable] section in testconfig but no entries defined"))
    (if (or (not (null? items))(not (null? itemstable)))
    (if (or (not (null? items))
	    (not (null? itemstable))
	    slashf
	    sxmlf
	    spacef)
	(append (item-assoc->item-list items)
		(item-table->item-list itemstable))
		(item-table->item-list itemstable)
		(items:read-items-file slashf 'slash)
		(items:read-items-file sxmlf  'sxml)
		(items:read-items-file spacef 'space))
	'(()))))

;; (pp (item-assoc->item-list itemdat))


	

Modified launch.scm from [69546387ce] to [4cf4021031].

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
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







+


















-
+

-
+
+
+
+
+
+
+







(import (prefix sqlite3 sqlite3:))

(declare (unit launch))
(declare (uses subrun))
(declare (uses common))
(declare (uses configf))
(declare (uses db))
(declare (uses ezsteps))

(include "common_records.scm")
(include "key_records.scm")
(include "db_records.scm")

;;======================================================================
;; ezsteps
;;======================================================================

;; ezsteps were going to be coded as
;; stepname[,predstep1,predstep2 ...] [{VAR1=first,second,third}] command to execute
;;   BUT
;; now are
;; stepname {VAR=first,second,third ...} command ...
;; where the {VAR=first,second,third ...} is optional.

;; given an exit code and whether or not logpro was used calculate OK/BAD
;; return #t if we are ok, #f otherwise
(define (steprun-good? logpro exitcode)
(define (steprun-good? logpro exitcode stepparms)
  (or (eq? exitcode 0)
      (and logpro (eq? exitcode 2))))
      (and logpro (eq? exitcode 2)) ;; shouldn't this be (member exitcode 2 ...) with the other ok codes?
      (let* ((params (alist-ref 'params stepparms)) ;; get the params section
	     (keep-going (if params
			     (alist-ref "keep-going" params equal?)
			     #f)))
	(debug:print 0 *default-log-port* "keep-going=" keep-going)
	(and keep-going (equal? (car keep-going) "yes")))))

;; if handed a string, process it, else look for MT_CMDINFO
(define (launch:get-cmdinfo-assoc-list #!key (encoded-cmd #f))
  (let ((enccmd (if encoded-cmd encoded-cmd (getenv "MT_CMDINFO"))))
    (if enccmd
	(common:read-encoded-string enccmd)
	'())))
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
90
91
92
93
94
95
96





























































































































































































97
98
99
100
101
102
103







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







	  ;;  )
	  (cond
	   ((equal? status "PASS") "PASS") ;; skip the message part if status is pass
	   (status (conc (configf:lookup dat "final" "exit-status") ": " (if msg msg "no message")))
	   (else #f)))
	#f)))

(define (launch:runstep ezstep run-id test-id exit-info m tal testconfig) ;;; TODO: deprecate me in favor of ezsteps.scm
  (let* ((stepname       (car ezstep))  ;; do stuff to run the step
	 (stepinfo       (cadr ezstep))
	;; (let ((info (cadr ezstep)))
	;; 		   (if (proc? info) "" info)))
	;; (stepproc       (let ((info (cadr ezstep)))
	;; 		   (if (proc? info) info #f)))
	 (stepparts      (string-match (regexp "^(\\{([^\\}\\{]*)\\}\\s*|)(.*)$") stepinfo))
	 (stepparams     (if (and (list? stepparts)
				  (> (length stepparts) 1))
			     (list-ref stepparts 2)
			     #f)) ;; for future use, {VAR=1,2,3}, run step for each
	 (paramparts     (if (string? stepparams)
			     (map (lambda (x)(string-split x "=")) (string-split-fields "[^;]*=[^;]*" stepparams))
			     '()))
	 (subrun         (alist-ref "subrun" paramparts equal?))
	 (stepcmd        (if (and (list? stepparts)
				  (> (length stepparts) 2))
			     (list-ref stepparts 3)
			     (conc "# error, no command for step "stepname)))
	 (script         "") ; "#!/bin/bash\n") ;; yep, we depend on bin/bash FIXME!!!\
	 (logpro-file    (conc stepname ".logpro"))
	 (html-file      (conc stepname ".html"))
	 (dat-file       (conc stepname ".dat"))
	 (tconfig-logpro (configf:lookup testconfig "logpro" stepname))
	 (logpro-used    (common:file-exists? logpro-file)))

    (debug:print 0 *default-log-port* "stepparts: " stepparts ", stepparams: " stepparams
                 ", paramparts: " paramparts ", subrun: " subrun ", stepcmd: " stepcmd)
    
    (if (and tconfig-logpro
	     (not logpro-used)) ;; no logpro file found but have a defn in the testconfig
	(begin
	  (with-output-to-file logpro-file
	    (lambda ()
	      (print ";; logpro file extracted from testconfig\n"
		     ";;")
	      (print tconfig-logpro)))
	  (set! logpro-used #t)))
    
    ;; NB// can safely assume we are in test-area directory
    (debug:print 4 *default-log-port* "ezsteps:\n stepname: " stepname " stepinfo: " stepinfo " stepparts: " stepparts
		 " stepparams: " stepparams " stepcmd: " stepcmd)
    
    ;; ;; first source the previous environment
    ;; (let ((prev-env (conc ".ezsteps/" prevstep (if (string-search (regexp "csh") 
    ;;      							 (get-environment-variable "SHELL")) ".csh" ".sh"))))
    ;;   (if (and prevstep (common:file-exists? prev-env))
    ;;       (set! script (conc script "source " prev-env))))
    
    ;; call the command using mt_ezstep
    ;; (set! script (conc "mt_ezstep " stepname " " (if prevstep prevstep "x") " " stepcmd))
    
    (debug:print 4 *default-log-port* "script: " script)
    (rmt:teststep-set-status! run-id test-id stepname "start" "-" #f #f)
    ;; now launch the actual process
    (call-with-environment-variables 
     (list (cons "PATH" (conc (get-environment-variable "PATH") ":.")))
     (lambda () ;; (process-run "/bin/bash" "-c" "exec ls -l /tmp/foobar > /tmp/delme-more.log 2>&1")
       (let* ((cmd (conc stepcmd " > " stepname ".log 2>&1")) ;; >outfile 2>&1 
	      (pid #f))
	 (let ((proc (lambda ()
		       (set! pid (process-run "/bin/bash" (list "-c" cmd))))))
	   (if subrun
               (begin
                 (debug:print-info 0 *default-log-port* "Running without MT_.* environment variables.")
                 (common:without-vars proc "^MT_.*"))
	       (proc)))
	 
         (with-output-to-file "Makefile.ezsteps"
           (lambda ()
             (print stepname ".log :")
             (print "\t" cmd)
             (if (common:file-exists? (conc stepname ".logpro"))
                 (print "\tlogpro " stepname ".logpro " stepname ".html < " stepname ".log"))
             (print)
             (print stepname " : " stepname ".log")
             (print))
           #:append)

	 (rmt:test-set-top-process-pid run-id test-id pid)
	 (let processloop ((i 0))
	   (let-values (((pid-val exit-status exit-code)(process-wait pid #t)))
		       (mutex-lock! m)
		       (launch:einf-pid-set!         exit-info pid)         ;; (vector-set! exit-info 0 pid)
		       (launch:einf-exit-status-set! exit-info exit-status) ;; (vector-set! exit-info 1 exit-status)
		       (launch:einf-exit-code-set!   exit-info exit-code)   ;; (vector-set! exit-info 2 exit-code)
		       (mutex-unlock! m)
		       (if (eq? pid-val 0)
			   (begin
			     (thread-sleep! 2)
			     (processloop (+ i 1))))
		       )))))
    (debug:print-info 0 *default-log-port* "step " stepname " completed with exit code " (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2))
    ;; now run logpro if needed
    (if logpro-used
	(let* ((logpro-exe (or (getenv "LOGPRO_EXE") "logpro"))
               (pid        (process-run (conc "/bin/sh -c '"logpro-exe" "logpro-file " " (conc stepname ".html") " < " stepname ".log > /dev/null'"))))
	  (let processloop ((i 0))
	    (let-values (((pid-val exit-status exit-code)(process-wait pid #t)))
			(mutex-lock! m)
			;; (make-launch:einf pid: pid exit-status: exit-status exit-code: exit-code)
			(launch:einf-pid-set!         exit-info pid)         ;; (vector-set! exit-info 0 pid)
			(launch:einf-exit-status-set! exit-info exit-status) ;; (vector-set! exit-info 1 exit-status)
			(launch:einf-exit-code-set!   exit-info exit-code)   ;; (vector-set! exit-info 2 exit-code)
			(mutex-unlock! m)
			(if (eq? pid-val 0)
			    (begin
			      (thread-sleep! 2)
			      (processloop (+ i 1)))))
	    (debug:print-info 0 *default-log-port* "logpro for step " stepname " exited with code " (launch:einf-exit-code exit-info))))) ;; (vector-ref exit-info 2)))))
    
    (let ((exinfo (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2))
	  (logfna (if logpro-used (conc stepname ".html") ""))
	  (comment #f))
      (if logpro-used
	  (let ((datfile (conc stepname ".dat")))
	    ;; load the .dat file into the test_data table if it exists
	    (if (common:file-exists? datfile)
		(set! comment (launch:load-logpro-dat run-id test-id stepname)))
	    (rmt:test-set-log! run-id test-id (conc stepname ".html"))))
      (rmt:teststep-set-status! run-id test-id stepname "end" exinfo comment logfna))
    ;; set the test final status
    (let* ((process-exit-status (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2))
	   (this-step-status (cond
			      ((and (eq? process-exit-status 2) logpro-used) 'warn)   ;; logpro 2 = warnings
			      ((and (eq? process-exit-status 3) logpro-used) 'check)  ;; logpro 3 = check
			      ((and (eq? process-exit-status 4) logpro-used) 'waived) ;; logpro 4 = waived
			      ((and (eq? process-exit-status 5) logpro-used) 'abort)  ;; logpro 5 = abort
			      ((and (eq? process-exit-status 6) logpro-used) 'skip)   ;; logpro 6 = skip
			      ((eq? process-exit-status 0)                   'pass)   ;; logpro 0 = pass
			      (else 'fail)))
	   (overall-status   (cond
			      ((eq? (launch:einf-rollup-status exit-info) 2) 'warn) ;; rollup-status (vector-ref exit-info 3)
			      ((eq? (launch:einf-rollup-status exit-info) 0) 'pass) ;; (vector-ref exit-info 3)
			      (else 'fail)))
	   (next-status      (cond 
			      ((eq? overall-status 'pass) this-step-status)
			      ((eq? overall-status 'warn)
			       (if (eq? this-step-status 'fail) 'fail 'warn))
			      ((eq? overall-status 'abort) 'abort)
			      (else 'fail)))
	   (next-state       ;; "RUNNING") ;; WHY WAS THIS CHANGED TO NOT USE (null? tal) ??
	    (cond
	     ((null? tal) ;; more to run?
	      "COMPLETED")
	     (else "RUNNING"))))
      (debug:print 4 *default-log-port* "Exit value received: " (launch:einf-exit-code exit-info) " logpro-used: " logpro-used 
		   " this-step-status: " this-step-status " overall-status: " overall-status 
		   " next-status: " next-status " rollup-status: "  (launch:einf-rollup-status exit-info)) ;; (vector-ref exit-info 3))
      (case next-status
	((warn)
	 (launch:einf-rollup-status-set! exit-info 2) ;; (vector-set! exit-info 3 2) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "WARN" 
				 (if (eq? this-step-status 'warn) "Logpro warning found" #f)
				 #f))
	((check)
	 (launch:einf-rollup-status-set! exit-info 3) ;; (vector-set! exit-info 3 3) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "CHECK" 
				 (if (eq? this-step-status 'check) "Logpro check found" #f)
				 #f))
	((waived)
	 (launch:einf-rollup-status-set! exit-info 4) ;; (vector-set! exit-info 3 3) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "WAIVED" 
				 (if (eq? this-step-status 'check) "Logpro waived found" #f)
				 #f))
	((abort)
	 (launch:einf-rollup-status-set! exit-info 5) ;; (vector-set! exit-info 3 4) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "ABORT" 
				 (if (eq? this-step-status 'abort) "Logpro abort found" #f)
				 #f))
	((skip)
	 (launch:einf-rollup-status-set! exit-info 6) ;; (vector-set! exit-info 3 4) ;; rollup-status
	 ;; NB// test-set-status! does rdb calls under the hood
	 (tests:test-set-status! run-id test-id next-state "SKIP" 
				 (if (eq? this-step-status 'skip) "Logpro skip found" #f)
				 #f))
	((pass)
	 (tests:test-set-status! run-id test-id next-state "PASS" #f #f))
	(else ;; 'fail
	 (launch:einf-rollup-status-set! exit-info 1) ;; (vector-set! exit-info 3 1) ;; force fail, this used to be next-state but that doesn't make sense. should always be "COMPLETED" 
	 (tests:test-set-status! run-id test-id "COMPLETED" "FAIL" (conc "Failed at step " stepname) #f)
	 )))
    logpro-used))

(define (launch:manage-steps run-id test-id item-path fullrunscript ezsteps subrun test-name tconfigreg exit-info m)
  ;; (let-values
  ;;  (((pid exit-status exit-code)
  ;;    (run-n-wait fullrunscript)))
  ;; (tests:test-set-status! test-id "RUNNING" "n/a" #f #f)
  ;; Since we should have a clean slate at this time there is no need to do 
  ;; any of the other stuff that tests:test-set-status! does. Let's just 
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
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







-
+










-
-
+
+
+
+
+



-
+







              (set! ezsteps #t) ;; set the needed flag
	      (set! ezstepslst
                    (append (or ezstepslst '())
                            (list (list "subrun" (conc "{subrun=true} " mt-cmd)))))))

	;; process the ezsteps
	(if ezsteps
	    (begin
	    (let* ((all-steps-dat (make-hash-table))) ;; keep all the info around as stepname ==> alist; where  'params is the params list (add other stuff as needed)
	      (if (not (common:file-exists? ".ezsteps"))(create-directory ".ezsteps"))
	      ;; if ezsteps was defined then we are sure to have at least one step but check anyway
	      (if (not (> (length ezstepslst) 0))
		  (debug:print-error 0 *default-log-port* "ezsteps defined but ezstepslst is zero length")
		  (let loop ((ezstep (car ezstepslst))
			     (tal    (cdr ezstepslst))
			     (prevstep #f))
                    (debug:print-info 0 *default-log-port* "Processing ezstep \"" (string-intersperse ezstep " ") "\"")
		    ;; check exit-info (vector-ref exit-info 1)
		    (if (launch:einf-exit-status exit-info) ;; (vector-ref exit-info 1)
			(let ((logpro-used (launch:runstep ezstep run-id test-id exit-info m tal testconfig))
			      (stepname    (car ezstep)))
			(let* ((logpro-used (launch:runstep ezstep run-id test-id exit-info m tal testconfig all-steps-dat))
			       (stepname    (car ezstep))
			       (stepparms   (hash-table-ref all-steps-dat stepname)))
			  (setenv "MT_STEP_NAME" stepname)
			  (pp (hash-table->alist all-steps-dat))
			  ;; if logpro-used read in the stepname.dat file
			  (if (and logpro-used (common:file-exists? (conc stepname ".dat")))
			      (launch:load-logpro-dat run-id test-id stepname))
			  (if (steprun-good? logpro-used (launch:einf-exit-code exit-info))
			  (if (steprun-good? logpro-used (launch:einf-exit-code exit-info) stepparms)
			      (if (not (null? tal))
				  (loop (car tal) (cdr tal) stepname))
			      (debug:print 0 *default-log-port* "WARNING: step " (car ezstep) " failed. Stopping")))
			(debug:print 0 *default-log-port* "WARNING: a prior step failed, stopping at " ezstep)))))))))

(define (launch:monitor-job run-id test-id item-path fullrunscript ezsteps test-name tconfigreg exit-info m work-area runtlim misc-flags)
  (let* ((update-period (string->number (or (configf:lookup *configdat* "setup" "test-stats-update-period") "30")))
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
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







-
+

-
+


+
+
+
-
-
+
+
+
+
+
+
+



















-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+







(define (launch:end-of-run-check run-id )
    (let*	((not-completed-cnt (rmt:get-not-completed-cnt run-id))  
           (running-cnt (rmt:get-count-tests-running-for-run-id run-id))
           (all-test-launched (rmt:get-var (conc "lunch-complete-" run-id)))
           (current-state (rmt:get-run-state run-id))
           (current-status (rmt:get-run-status run-id)))
     ;;get-vars run-id to query metadata table to check if all completed. if all-test-launched = yes then only not-completed-cnt = 0 means everyting is completed if no entry found in the table do nothing 
     (debug:print 0 *default-log-port* "rollup run state/status")                      
     (debug:print 0 *default-log-port* "Running test cnt :" running-cnt)                      
     (rmt:set-state-status-and-roll-up-run  run-id current-state current-status)
 
     (runs:update-junit-test-reporter-xml run-id) 
     (cond 
       ((and all-test-launched (eq? not-completed-cnt 0) (equal? all-test-launched "yes" ))
                (if (and (equal? (rmt:get-var (conc "end-of-run-" run-id)) "no") (common:simple-lock (conc "endOfRun" run-id)))
                (begin
           	(debug:print 4 *default-log-port* "look for  post hook. currseconds: " (current-seconds) " EOR " (rmt:get-var (conc "end-of-run-" run-id)))
           	(debug:print 0 *default-log-port* "look for  post hook.")
          	(runs:run-post-hook run-id))
                (debug:print 0 *default-log-port* "End of Run Detected.")
                (rmt:set-var (conc "end-of-run-" run-id) "yes")
                ;(thread-sleep! 10)
          	(runs:run-post-hook run-id)
                (debug:print 4 *default-log-port* "currseconds: " (current-seconds)" eor: " (rmt:get-var (conc "end-of-run-" run-id)))
                (common:simple-unlock (conc "endOfRun" run-id)))
                 (debug:print 0 *default-log-port* "End of Run Detected but not running post hook. This should happen when eor is set to yes. This will happen only when 2 tests exit at smae time. eor= " (rmt:get-var (conc "end-of-run-" run-id)))))
        ((> running-cnt 3) 
        	  (debug:print 0 *default-log-port* "There are " running-cnt " tests running." ))
        ((> running-cnt 0)
            (debug:print 0 *default-log-port* "running cnt > 0 but <= 3 kill-running-tests-if-dead" )
   				  (let ((kill-cnt (launch:kill-tests-if-dead run-id)))
           			(if (and all-test-launched  (equal? all-test-launched "yes") (eq? kill-cnt running-cnt))
           					(launch:end-of-run-check run-id)))) ;;todo
        (else  (debug:print 0 *default-log-port* "Should it get here?? May be everything is not launched yet. Running test cnt:" running-cnt " Not completed test cnt:" not-completed-cnt)
         (let* ((not-completed-tests (rmt:get-tests-for-run run-id "%" `("NOT_STARTED" "RUNNING" "LAUNCHED" "REMOTEHOSTSTART") `() #f #f #f #f #f #f #f #f)))
       (if (> (length not-completed-tests) 0) 
           (let loop ((running-test (car not-completed-tests))
			     (tal    (cdr not-completed-tests)))
		       (let* ((test-name (vector-ref running-test 2))
                 (item-path (vector-ref running-test 11)))
			       	(debug:print 0 *default-log-port* "test " test-name "/" item-path " not completed")
              (if (not (null? tal))
				  (loop (car tal) (cdr tal)))))))))))        
 
(define (launch:is-test-alive host pid)
(if (and host pid (not (equal? host "n/a")))
(let* ((cmd (conc "ssh " host " pstree -A " pid))
      (output (with-input-from-pipe cmd read-lines)))
  (print "cmd: " cmd "\n op: " output )
  (if(eq? (length output) 0)
     #f
     #t))
#t))
  (if (and host pid (not (equal? host "n/a")))
      (let* ((cmd (conc "ssh " host " pstree -A " pid))
	     (output (with-input-from-pipe cmd read-lines)))
	(debug:print 2 *default-log-port* "Running " cmd " received " output)
	(if (eq? (length output) 0)
	   #f
	   #t))
      #t))
 
(define (launch:kill-tests-if-dead run-id)
  (let* ((running-tests (rmt:get-tests-for-run run-id "%" `("RUNNING" "LAUNCHED" "REMOTEHOSTSTART") `() #f #f #f #f #f #f #f #f)))
       (let loop ((running-test (car running-tests))
			     (tal    (cdr running-tests))
			     (kill-cnt 0))
		       (let* ((test-name (vector-ref running-test 2))
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
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







-
-
+
+






-
-
+
+







-
-
+
+







    ;; level
    (if (not not-iterated) ;; i.e. iterated
	(let ((iterated-parent  (pathname-directory (conc lnkpath "/" item-path))))
	  (debug:print-info 2 *default-log-port* "Creating iterated parent " iterated-parent)
	  (handle-exceptions
	   exn
	   (begin
	     (debug:print-error 0 *default-log-port* " Failed to create directory " iterated-parent ((condition-property-accessor 'exn 'message) exn) ", exiting")
	     (exit 1))
	     (debug:print-error 0 *default-log-port* " Failed to create directory " iterated-parent ((condition-property-accessor 'exn 'message) exn) ", continuing but link tree may be corrupted")
	     #;(exit 1))
	   (create-directory iterated-parent #t))))

    (if (symbolic-link? lnkpath) 
	(handle-exceptions
	 exn
	 (begin
	   (debug:print-error 0 *default-log-port* " Failed to remove symlink " lnkpath ((condition-property-accessor 'exn 'message) exn) ", exiting")
	   (exit 1))
	   (debug:print-error 0 *default-log-port* " Failed to remove symlink " lnkpath ((condition-property-accessor 'exn 'message) exn) ", continuing but link tree may be corrupted.")
	   #;(exit 1))
	 (delete-file lnkpath)))

    (if (not (or (common:file-exists? lnkpath)
		 (symbolic-link? lnkpath)))
	(handle-exceptions
	 exn
	 (begin
	   (debug:print-error 0 *default-log-port* " Failed to create symlink " lnkpath ((condition-property-accessor 'exn 'message) exn) ", exiting")
	   (exit 1))
	   (debug:print-error 0 *default-log-port* " Failed to create symlink " lnkpath ((condition-property-accessor 'exn 'message) exn) ", continuing but link tree may be corrupted.")
	   #;(exit 1))
	 (create-symbolic-link toptest-path lnkpath)))
    
    ;; NB - This was not working right - some top tests are not getting the path set!!!
    ;;
    ;; Do the setting of this record after the paths are created so that the shortdir can 
    ;; be set to the real directory location. This is safer for future clean up if the link
    ;; tree is damaged or lost.

Modified megatest-version.scm from [d6c237db6e] to [bdb917f339].

16
17
18
19
20
21
22
23

16
17
18
19
20
21
22

23







-
+
;;     along with Megatest.  If not, see <http://www.gnu.org/licenses/>.

;; Always use two or four digit decimal
;; 1.01, 1.02...1.10,1.11,1.1101 ... 1.99,2.00..

(declare (unit megatest-version))

(define megatest-version 1.6548)
(define megatest-version 1.6603)

Modified megatest.scm from [54cb07f11c] to [5271a099fb].

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
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







+



-
+








+







(declare (uses tdb))
(declare (uses mt))
(declare (uses api))
(declare (uses tasks)) ;; only used for debugging.
(declare (uses env))
(declare (uses diff-report))
(declare (uses commonmod))
(declare (uses adjutant))
;; (declare (uses ftail))
;; (import ftail)

(import stml2 mutils commonmod)
(import stml2 mutils commonmod adjutant)

;; invoke the imports
;; (declare (uses mtargs.import))
;; (declare (uses mtconfigf.import))
(declare (uses cookie.import))
(declare (uses stml2.import))
(declare (uses pkts.import))
(declare (uses commonmod.import))
(declare (uses adjutant.import))

(define *db* #f) ;; this is only for the repl, do not use in general!!!!

(include "common_records.scm")
(include "key_records.scm")
(include "db_records.scm")
(include "run_records.scm")
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
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







+
+










-




-


















+
+







  :units                  : name of the units for value, expected_value etc. (optional)
  -load-test-data         : read test specific data for storage in the test_data table
                            from standard in. Each line is comma delimited with four
                            fields category,variable,value,comment

Queries
  -list-runs patt         : list runs matching pattern \"patt\", % is the wildcard
  -fields fieldspec       : fields to include in json dump; runs:id,runame+tests:testname+steps
  -dumpmode MODE          : dump in MODE format instead of sexpr, MODE=json,ini,sexp etc. (add -debug 0,9 to see which file contributes each line)
  -show-keys              : show the keys used in this megatest setup
  -test-files targpatt    : get the most recent test path/file matching targpatt e.g. %/% or '*.log'
                            returns list sorted by age ascending, see examples below
  -test-paths             : get the test paths matching target, runname, item and test
                            patterns.
  -list-disks             : list the disks available for storing runs
  -list-targets           : list the targets in runconfigs.config
  -list-db-targets        : list the target combinations used in the db
  -show-config            : dump the internal representation of the megatest.config file
  -show-runconfig         : dump the internal representation of the runconfigs.config file
  -dumpmode MODE          : dump in MODE format instead of sexpr, MODE=json,ini,sexp etc. (add -debug 0,9 to see which file contributes each line)
  -show-cmdinfo           : dump the command info for a test (run in test environment)
  -section sectionName
  -var varName            : for config and runconfig lookup value for sectionName varName
  -since N                : get list of runs changed since time N (Unix seconds)
  -fields fieldspec       : fields to include in json dump; runs:id,runame+tests:testname+steps
  -sort fieldname         : in -list-runs sort tests by this field
  -testdata-csv [categorypatt/]varpatt  : dump testdata for given category

Misc 
  -start-dir path         : switch to this directory before running megatest
  -contour cname          : add a level of hierarcy to the linktree and run paths
  -area-tag tagname       : add a tag to an area while syncing to pgdb
  -run-tag tagname        : add a tag to a run while syncing to pgdb
  -rebuild-db             : bring the database schema up to date
  -cleanup-db             : remove any orphan records, vacuum the db
  -import-megatest.db     : push data from megatest.db to cache db files in /tmp/$USER
  -sync-to-megatest.db    : pull data from cache files in /tmp/$USER to megatest.db
  -sync-to dest           : sync to new postgresql central style database
  -update-meta            : update the tests metadata for all tests
  -setvars VAR1=val1,VAR2=val2 : Add environment variables to a run NB// these are
                                 overwritten by values set in config files.
  -server -|hostname      : start the server (reduces contention on megatest.db), use
                            - to automatically figure out hostname
  -adjutant C,M           : start the server/adjutant with allocated cores C and Mem M (Gig), 
                            use 0,0 to auto use full machine
  -transport http|rpc     : use http or rpc for transport (default is http) 
  -log logfile            : send stdout and stderr to logfile
  -list-servers           : list the servers 
  -kill-servers           : kill all servers
  -repl                   : start a repl (useful for extending megatest)
  -load file.scm          : load and run file.scm
  -mark-incompletes       : find and mark incomplete tests
248
249
250
251
252
253
254

255
256
257
258
259
260
261
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266







+







  -generate-html-structure  : create a top level html veiw to list targets/runs and a Run view within each run directory.  
  -list-run-time          : list time requered to complete runs. It supports following switches
                            -run-patt <patt> -target-patt <patt> -dumpmode <csv,json,plain-text>
  -list-test-time	  : list time requered to complete each test in a run. It following following arguments
                            -runname <patt> -target <patt> -dumpmode <csv,json,plain-text>
  -syscheck               : do some very basic checks; write access and space in tmp, home, runs, links and 
                            is $DISPLAY valid 
  -list-waivers           : dump waivers for specified target, runname, testpatt to stdout

Diff report
  -diff-rep               : generate diff report (must include -src-target, -src-runname, -target, -runname
                                                  and either -diff-email or -diff-html)
  -src-target <target>
  -src-runname <target>
  -diff-email <emails>    : comma separated list of email addresses to send diff report
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334

335
336
337
338
339
340
341
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







+









+







			;; values and messages
			":category"
			":variable"
			":value"
			":expected"
			":tol"
			":units"

			;; misc
			"-start-dir"
                        "-run-patt"
                        "-target-patt"   
			"-contour"
                        "-area-tag"  
                        "-area"  
			"-run-tag"
			"-server"
			"-adjutant"
			"-transport"
			"-port"
			"-extract-ods"
			"-pathmod"
			"-env2file"
			"-envcap"
			"-envdelta"
380
381
382
383
384
385
386

387
388
389
390
391
392
393
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401







+







                        "-src-target"
                        "-src-runname"
                        "-diff-email"
			"-sync-to"			
			"-pgsync"
			"-kill-wait"    ;; wait this long before removing test (default is 10 sec)
                        "-diff-html"

			)
 		 (list  "-h" "-help" "--help"
			"-manual"
			"-version"
		        "-force"
		        "-xterm"
		        "-showkeys"
427
428
429
430
431
432
433

434
435
436
437
438
439
440
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449







+







			"-list-disks"
			"-list-targets"
			"-list-db-targets"
			"-show-runconfig"
			"-show-config"
			"-show-cmdinfo"
			"-get-run-status"
			"-list-waivers"

			;; queries
			"-test-paths" ;; get path(s) to a test, ordered by youngest first

			"-runall"    ;; run all tests, respects -testpatt, defaults to %
			"-run"       ;; alias for -runall
			"-remove-runs"
508
509
510
511
512
513
514

515
516
517
518
519
520
521
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531







+







;;(if (not (args:get-arg "-server"))
;;    (thread-start! *watchdog*)) ;; if starting a server; wait till we get to running state before kicking off watchdog
(let* ((no-watchdog-args
       '("-list-runs"
         "-testdata-csv"
         "-list-servers"
         "-server"
	 "-adjutant"
         "-list-disks"
         "-list-targets"
         "-show-runconfig"
         ;;"-list-db-targets"
         "-show-runconfig"
         "-show-config"
         "-show-cmdinfo"
901
902
903
904
905
906
907








908
909
910
911
912
913
914
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932







+
+
+
+
+
+
+
+







;; Server? Start up here.
;;
(if (args:get-arg "-server")
    (let ((tl        (launch:setup))
          (transport-type (string->symbol (or (args:get-arg "-transport") "http"))))
      (server:launch 0 transport-type)
      (set! *didsomething* #t)))

;; The adjutant is a bit different, it does NOT run (launch:setup) as it is not necessarily tied to
;; a specific Megatest area. Detail are being hashed out and this may change.
;;
(if (args:get-arg "-adjutant")
    (begin
      (adjutant-run)
      (set! *didsomething* #t)))

(if (or (args:get-arg "-list-servers")
        (args:get-arg "-kill-servers"))
    (let ((tl (launch:setup)))
      (if tl ;; all roads from here exit
	  (let* ((servers (server:get-list *toppath*))
		 (fmtstr  "~8a~22a~20a~20a~8a\n"))
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
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







-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	  ;; (system (conc "rm -rf " tempdir))
	  (set! *didsomething* #t)
          (set! *time-to-exit* #t)
          ) ;; end if true branch (end of a let)
        ) ;; end if
    ) ;; end if -list-runs

;; Don't think I need this. Incorporated into -list-runs instead
;;
;; (if (and (args:get-arg "-since")
;; 	 (launch:setup))
;;     (let* ((since-time (string->number (args:get-arg "-since")))
;; 	   (run-ids    (db:get-changed-run-ids since-time)))
;;       ;; (rmt:get-tests-for-runs-mindata run-ids testpatt states status not-in)
;;       (print (sort run-ids <))
;;       (set! *didsomething* #t)))
;; list-waivers
(if (and (args:get-arg "-list-waivers")
	 (launch:setup))
    (let* ((runpatt     (or (args:get-arg "-runname") "%"))
	   (testpatt    (common:args-get-testpatt #f))
	   (keys        (rmt:get-keys)) 
	   (runsdat     (rmt:get-runs-by-patt
			 keys runpatt 
			 (common:args-get-target) #f #f
			 '("id" "runname" "state" "status" "owner" "event_time" "comment") 0))
	   (runs        (db:get-rows runsdat))
	   (header      (db:get-header runsdat))
	   (results     (make-hash-table))  ;; [target] ( (testname/itempath . "comment") ... )
	   (addtest     (lambda (target testname itempath comment)
			  (hash-table-set! results target (cons (cons (conc testname "/" itempath) comment)
								(hash-table-ref/default results target '())))))
	   (last-target #f))
      (for-each
       (lambda (run)
	 (let* ((run-id  (db:get-value-by-header run header "id"))
		(target  (rmt:get-target run-id))
		(runname (db:get-value-by-header run header "runname")) 
		(tests   (rmt:get-tests-for-run
			  run-id testpatt '("COMPLETED") '("WAIVED") #f #f #f 'testname 'asc							     ;; use qryvals if test-spec provided
			  #f #f #f)))
	   (if (not (equal? target last-target))
	       (print "[" target "]"))
	   (set! last-target target)
	   (print "# " runname)
	   (for-each
	    (lambda (testdat)
	      (let* ((testfullname (conc (db:test-get-testname testdat)
					 (if (equal? "" (db:test-get-item-path testdat))
					     ""
					     (conc "/" (db:test-get-item-path testdat)))
					 )))
	      (print testfullname " " (db:test-get-comment testdat))))
	    tests)))
       runs)
      (set! *didsomething* #t)))
      
      
;;======================================================================
;; full run
;;======================================================================

(define (handle-run-requests target runname keys keyvals need-clean)	 
  (if (or (args:get-arg "-kill-rerun") (args:get-arg "-rerun-clean")) ;; first set states/statuses correct
      ;; For rerun-clean do we or do we not support the testpatt?
      (let ((states   (or (configf:lookup *configdat* "validvalues" "cleanrerun-states")
			  "KILLREQ,KILLED,UNKNOWN,INCOMPLETE,STUCK,NOT_STARTED"))
	    (statuses (or (configf:lookup *configdat* "validvalues" "cleanrerun-statuses")
			  "FAIL,INCOMPLETE,ABORT,CHECK,DEAD,PREQ_FAIL,PREQ_DISCARDED")))
	(hash-table-set! args:arg-hash "-preclean" #t)
	(runs:operate-on 'set-state-status
			 target
			 (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
			 ;; "%" ;; (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
			 (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
			 state:  states
			 ;; status: statuses
			 new-state-status: "NOT_STARTED,n/a")
	(runs:clean-cache target runname *toppath*)
	(runs:operate-on 'set-state-status
			 target
			 (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
			 ;; "%" ;; (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
			 (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
			 ;; state:  states
			 status: statuses
			 new-state-status: "NOT_STARTED,n/a")))
  ;; RERUN ALL
  (if (args:get-arg "-rerun-all") ;; first set states/statuses correct
      (let* ((rconfig (full-runconfigs-read)))
	(hash-table-set! args:arg-hash "-preclean" #t)
	(runs:operate-on 'set-state-status
			 target
			 (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
			 (common:args-get-testpatt rconfig) ;; (args:get-arg "-testpatt")
			 state:  #f
			 ;; status: statuses
			 new-state-status: "NOT_STARTED,n/a")
	(runs:clean-cache target runname *toppath*)
	(runs:operate-on 'set-state-status
			 target
			 (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
			 (common:args-get-testpatt rconfig) ;; (args:get-arg "-testpatt")
			 ;; state:  states
			 status: #f
			 new-state-status: "NOT_STARTED,n/a")))
  (let* ((config-reruns      (let ((x (configf:lookup *configdat* "setup" "reruns")))
			       (if x (string->number x) #f)))
	 (rerun-cnt (if config-reruns
			config-reruns
			1)))

    (runs:run-tests target
		    runname
		    #f ;; (common:args-get-testpatt #f)
		    ;; (or (args:get-arg "-testpatt")
		    ;;     "%")
		    user
		    args:arg-hash
		    run-count: rerun-cnt)))

;; get lock in db for full run for this directory
;; for all tests with deps
;;   walk tree of tests to find head tasks
;;   add head tasks to task queue
;;   add dependant tasks to task queue 
;;   add remaining tasks to task queue
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
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







-
+
+




-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
-
-
-
+
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+







(if (or (args:get-arg "-runall")
	(args:get-arg "-run")
	(args:get-arg "-rerun-clean")
	(args:get-arg "-rerun-all")
	(args:get-arg "-runtests")
        (args:get-arg "-kill-rerun"))
    (let ((need-clean (or (args:get-arg "-rerun-clean")
                          (args:get-arg "-rerun-all"))))
                          (args:get-arg "-rerun-all")))
	  (orig-cmdline (string-intersperse (argv) " ")))
      (general-run-call 
       "-runall"
       "run all tests"
       (lambda (target runname keys keyvals)
         (if (or (args:get-arg "-kill-rerun") (args:get-arg "-rerun-clean")) ;; first set states/statuses correct
	     ;; For rerun-clean do we or do we not support the testpatt?
             (let ((states   (or (configf:lookup *configdat* "validvalues" "cleanrerun-states")
                                 "KILLREQ,KILLED,UNKNOWN,INCOMPLETE,STUCK,NOT_STARTED"))
                   (statuses (or (configf:lookup *configdat* "validvalues" "cleanrerun-statuses")
                                 "FAIL,INCOMPLETE,ABORT,CHECK,DEAD,PREQ_FAIL,PREQ_DISCARDED")))
               (hash-table-set! args:arg-hash "-preclean" #t)
               (runs:operate-on 'set-state-status
                                target
	 (if (or (string-search "%" target)
                                (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
                                ;; "%" ;; (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
                                (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
                                state:  states
                                ;; status: statuses
                                new-state-status: "NOT_STARTED,n/a")
               (runs:clean-cache target runname *toppath*)
               (runs:operate-on 'set-state-status
                                target
		 (string-search "%" runname)) ;; we are being asked to re-run multiple runs
	     (let* ((run-specs (rmt:simple-get-runs runname #f #f target #f))) ;; list of simple-run records
	       (debug:print-info 0 *default-log-port* "Pattern supplied for target or runname with "
				 (length run-specs) " matches round. Running each in turn.")
	       (if (null? run-specs)
		   (debug:print 0 *default-log-port* "WARNING: No runs match target " target " and runname " runname))
                                (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
                                ;; "%" ;; (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
                                (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt")
	       (for-each (lambda (spec) 
			   (let* ((precmd     (if (args:get-arg "-precmd")(conc (args:get-arg "-precmd") " ") ""))
                                ;; state:  states
                                status: statuses
                                new-state-status: "NOT_STARTED,n/a")))
				  (newcmdline (conc
         ;; RERUN ALL
         (if (args:get-arg "-rerun-all") ;; first set states/statuses correct
             (let* ((rconfig (full-runconfigs-read)))
               (hash-table-set! args:arg-hash "-preclean" #t)
               (runs:operate-on 'set-state-status
                                target
					       precmd
					       (string-substitute
						(conc "target " target)
                                (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
                                (common:args-get-testpatt rconfig) ;; (args:get-arg "-testpatt")
                                state:  #f
                                ;; status: statuses
                                new-state-status: "NOT_STARTED,n/a")
               (runs:clean-cache target runname *toppath*)
               (runs:operate-on 'set-state-status
                                target
						(conc "target " (simple-run-target spec))
                                (common:args-get-runname)  ;; (or (args:get-arg "-runname")(args:get-arg ":runname"))
                                (common:args-get-testpatt rconfig) ;; (args:get-arg "-testpatt")
                                ;; state:  states
                                status: #f
                                new-state-status: "NOT_STARTED,n/a")))
         (let* ((config-reruns      (let ((x (configf:lookup *configdat* "setup" "reruns")))
			       				(if x (string->number x) #f)))
               (rerun-cnt (if config-reruns
                              config-reruns
                              1)))

         (runs:run-tests target
                         runname
						(string-substitute
						 (conc "runname " runname)
						 (conc "runname " (simple-run-runname spec))
						 orig-cmdline)))))
			     (debug:print 0 *default-log-port* "ORIG: " orig-cmdline)
			     (debug:print 0 *default-log-port* "NEW:  " newcmdline)
			     (system newcmdline)))
			 run-specs))
                         #f ;; (common:args-get-testpatt #f)
                         ;; (or (args:get-arg "-testpatt")
                         ;;     "%")
                         user
                         args:arg-hash
                         run-count: rerun-cnt))))))
	     (handle-run-requests target runname keys keyvals need-clean))))))

;;======================================================================
;; run one test
;;======================================================================

;; 1. find the config file
;; 2. change to the test directory

Modified mtut.scm from [daf0c4d9a4] to [8133cd984a].

21
22
23
24
25
26
27

28
29
30
31
32
33
34
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35







+








;; fake out readline usage of toplevel-command
(define (toplevel-command . a) #f)

(use srfi-1 posix srfi-69 readline ;;  regex regex-case srfi-69 apropos json http-client directory-utils rpc typed-records;; (srfi 18) extras)
   srfi-19  srfi-18 extras format regex regex-case
     (prefix dbi dbi:)
     (prefix sqlite3 sqlite3:)
     nanomsg)

(declare (uses common))
(declare (uses megatest-version))
(declare (uses margs))
(declare (uses configf))
;; (declare (uses rmt))
839
840
841
842
843
844
845
846
847

848
849
850
851
852
853
854
840
841
842
843
844
845
846


847
848
849
850
851
852
853
854







-
-
+







	      (rgconf    (car rgconfdat))
	      (all-areas (map car (configf:get-section mtconf "areas")))
	      (contours  (configf:get-section mtconf "contours"))
	      (torun     (make-hash-table)) ;; target => ( ... info ... )
	      (rgentargs (hash-table-keys rgconf))) ;; these are the targets registered for automatically triggering

	 ;;(print "rgentargs: " rgentargs)
	 
	 (for-each
	  (for-each
	  (lambda (runkey)
	    (let* ((keydats   (configf:get-section rgconf runkey)))
	      (for-each
	       (lambda (sense) ;; these are the sense rules
		 (let* ((key        (car sense))
			(val        (cadr sense))
			(keyparts   (string-split key ":")) ;; contour:ruletype:action:optional
1427
1428
1429
1430
1431
1432
1433

1434
1435
1436
1437
1438
1439
1440
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441







+







       (let* ((rgconfdat (find-and-read-config (conc toppath "/runconfigs.config")))
	      (rgconf    (car rgconfdat))
	      (areas     (configf:get-section mtconf "areas"))
	      (contours  (configf:get-section mtconf "contours"))
	      (pkts      (find-pkts pdb '(cmd) '()))
	      (torun     (make-hash-table)) ;; target => ( ... info ... )
	      (rgentargs (hash-table-keys rgconf))) ;; these are the targets registered for automatically triggering
         (sqlite3:set-busy-handler! (dbi:db-conn pdb) (sqlite3:make-busy-timeout 10000))
	 (for-each
	  (lambda (pktdat)
	    (let* ((pkta    (alist-ref 'apkt pktdat))
		   (action  (alist-ref 'A pkta))
		   (cmdline (pkt->cmdline pkta))
		   (uuid    (alist-ref 'Z pkta))
		   (user    (alist-ref 'U pkta))

Modified rmt.scm from [8ff320805f] to [6209f83b0d].

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
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







-
+














+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







;;

(define (extras-case-11 *default-log-port* runremote cmd params attemptnum rid)
  ;; (mutex-unlock! *rmt-mutex*)
  (debug:print-info 12 *default-log-port* "rmt:send-receive, case  9")
  ;; (mutex-lock! *rmt-mutex*)
  (let* ((conninfo (remote-conndat runremote))
	 (dat      (case (remote-transport runremote)
	 (dat-in      (case (remote-transport runremote)
		     ((http) (condition-case ;; handling here has
					     ;; caused a lot of
					     ;; problems. However it
					     ;; is needed to deal with
					     ;; attemtped
					     ;; communication to
					     ;; servers that have gone
					     ;; away
			      (http-transport:client-api-send-receive 0 conninfo cmd params)
			      ((commfail)(vector #f "communications fail"))
			      ((exn)(vector #f "other fail" (print-call-chain)))))
		     (else
		      (debug:print 0 *default-log-port* "ERROR: transport " (remote-transport runremote) " not supported")
		      (exit))))

;; No Title 
;; Error: (vector-ref) out of range
;; #(#<condition: (exn type)> (#("db.scm:3740: regex#regexp" #f #f) #("db.scm:3739: regex#string-substitute" #f #f) #("db.scm:3738: base64#base64-decode" #f #f) #("db.scm:3737: z3#z3:decode-buffer" #f #f) #("db.scm:3736: with-input-from-string" #f #f) #("db.scm:3741: s11n#deserialize" #f #f) #("api.scm:374: api:execute-requests" #f #f) #("api.scm:139: call-with-current-continuation" #f #f) #("api.scm:139: with-exception-handler" #f #f) #("api.scm:139: ##sys#call-with-values" #f #f) #("api.scm:158: string->symbol" #f #f) #("api.scm:160: current-milliseconds" #f #f) #("api.scm:161: dbr:dbstruct-read-only" #f #f) #("api.scm:139: k15" #f #f) #("api.scm:139: g19" #f #f) #("api.scm:142: get-call-chain" #f #f)) #("get-test-info-by-id" (1102 507299)))
;; 6
;; 
;; 	Call history:
;; 
;; 	http-transport.scm:306: thread-terminate!	  
;; 	http-transport.scm:307: debug:print-info	  
;; 	common_records.scm:235: debug:debug-mode	  
;; 	rmt.scm:259: k587	  
;; 	rmt.scm:259: g591	  
;; 	rmt.scm:276: http-transport:server-dat-update-last-access	  
;; 	http-transport.scm:364: current-seconds	  
;; 	rmt.scm:282: debug:print-info	  
;; 	common_records.scm:235: debug:debug-mode	  
;; 	rmt.scm:283: mutex-unlock!	  
;; 	rmt.scm:287: extras-transport-succeded	  	<--
;; +-----------------------------------------------------------------------------+
;; | Exit Status    : 70  
;;  

	 (dat      (if (and (vector? dat-in) ;; ... check it is a correct size
			    (> (vector-length dat-in) 1))
		       dat-in
		       (vector #f (conc "communications fail (type 2), dat-in=" dat-in))))
	 (success  (if (vector? dat) (vector-ref dat 0) #f))
	 (res      (if (vector? dat) (vector-ref dat 1) #f)))
    (if (and (vector? conninfo) (< 5 (vector-length conninfo)))
	(http-transport:server-dat-update-last-access conninfo) ;; refresh access time
	(begin
	  (debug:print 0 *default-log-port* "INFO: Should not get here! conninfo=" conninfo)
	  (set! conninfo #f)

Modified runs.scm from [5d58c5f129] to [70ec443715].

14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28







-
+







;; 
;;     You should have received a copy of the GNU General Public License
;;     along with Megatest.  If not, see <http://www.gnu.org/licenses/>.

;;  strftime('%m/%d/%Y %H:%M:%S','now','localtime')

(use (prefix sqlite3 sqlite3:) srfi-1 posix regex regex-case srfi-69 (srfi 18) 
     posix-extras directory-utils pathname-expand typed-records format)
     posix-extras directory-utils pathname-expand typed-records format  sxml-serializer sxml-modifications)

(declare (unit runs))
(declare (uses db))
(declare (uses common))
(declare (uses items))
(declare (uses runconfig))
(declare (uses tests))
530
531
532
533
534
535
536









537
538
539
540
541
542
543
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552







+
+
+
+
+
+
+
+
+







    (runs:update-all-test_meta #f)

    ;; run the run prehook if there are no tests yet run for this run:
    ;;
    (runs:run-pre-hook run-id)
    ;; mark all test launced flag as false in the meta table 
    (rmt:set-var (conc "lunch-complete-" run-id) "no")
    (debug:print-info 1 *default-log-port* "Setting end-of-run to no")
    (let* ((config-reruns      (let ((x (configf:lookup *configdat* "setup" "reruns")))
			       (if x (string->number x) #f)))
	  (config-rerun-cnt (if config-reruns
			config-reruns
			1)))
    (if (eq? config-rerun-cnt run-count)
      (rmt:set-var (conc "end-of-run-" run-id) "no")))

    (rmt:set-run-state-status run-id "new" "n/a")
    ;; now add non-directly referenced dependencies (i.e. waiton)
    ;;======================================================================
    ;; refactoring this block into tests:get-full-data
    ;;
    ;; What happended, this code is now duplicated in tests!?
    ;;
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
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







-
+
+



-
+
-
-




+







	    (if (> run-count 0) ;; handle reruns
		(begin
		  (if (not (hash-table-ref/default flags "-preclean" #f))
		      (hash-table-set! flags "-preclean" #t))
		  (if (not (hash-table-ref/default flags "-rerun" #f))
		      (hash-table-set! flags "-rerun" "STUCK/DEAD,n/a,ZERO_ITEMS"))
		  ;; recursive call to self
      (runs:run-tests target runname test-patts user flags run-count: (- run-count 1)))))
      (runs:run-tests target runname test-patts user flags run-count: (- run-count 1)))
                  (launch:end-of-run-check run-id)))
	  (debug:print-info 0 *default-log-port* "No tests to run")))
    (debug:print-info 4 *default-log-port* "All done by here")
    ;; TODO: try putting post hook call here
    ;(if (eq? run-count 0)
      
    ; (begin  
    ;  (debug:print-info 0 *default-log-port* "Calling Post Hook")  
    ;  (debug:print-info 2 *default-log-port* " run-count " run-count)
    ;  (runs:run-post-hook run-id))
    ;  (debug:print-info 2 *default-log-port* "Not calling post hook runcount = " run-count ))   
    (rmt:tasks-set-state-given-param-key task-key "done")
     
    ;; (sqlite3:finalize! tasks-db)
    ))


;; loop logic. These are used in runs:run-tests-queue to make it a bit more readable.
;;
;; If reg not full and have items in tal then loop with (car tal)(cdr tal) reg reruns
1676
1677
1678
1679
1680
1681
1682
1683
1684


1685
1686
1687
1688
1689
1690
1691
1685
1686
1687
1688
1689
1690
1691


1692
1693
1694
1695
1696
1697
1698
1699
1700







-
-
+
+







	  (debug:print-info 0 *default-log-port* "Have leftovers!")
	  (loop (car reg)(cdr reg) '() reruns))
	 (else
          (debug:print-info 4 *default-log-port* "cond branch - "  "rtq-9")
	  (debug:print-info 4 *default-log-port* "Exiting loop with...\n  hed=" hed "\n  tal=" tal "\n  reruns=" reruns))
	 ))) ;; end loop on sorted test names
    ;; this is the point where everything is launched and now you can mark the run in metadata table as all launched 
    (rmt:set-var (conc "lunch-complete-" run-id) "yes")
  
    (rmt:set-var (conc "lunch-complete-" run-id) "yes")  
        
    ;; now *if* -run-wait we wait for all tests to be done
    ;; Now wait for any RUNNING tests to complete (if in run-wait mode)
    (thread-sleep! 10) ;; I think there is a race condition here. Let states/statuses settle
    (let wait-loop ((num-running      (rmt:get-count-tests-running-for-run-id run-id))
		    (prev-num-running 0))
      ;; (debug:print-info 13 *default-log-port* "num-running=" num-running ", prev-num-running=" prev-num-running)
      (if (and (or (args:get-arg "-run-wait")
2083
2084
2085
2086
2087
2088
2089









2090
2091
2092
2093
2094
2095
2096
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114







+
+
+
+
+
+
+
+
+







			))
		   actions))))
          sorted)))
     ;; (print "Sorted: " (map simple-run-event_time sorted))
     ;; (print "Remove: " (map simple-run-event_time to-remove))))
     (hash-table-keys runs-ht))
    runs-ht))

(define (remove-last-path-directory path-in)
  (let* ((dparts  (string-split path-in "/"))
    (path-out (conc "/" (string-intersperse (take dparts (- (length dparts) 1)) "/")))
    )
    path-out
  )
)


;; (define (runs:remove-all-but-last-n-runs-per-target target-patts runpatt num-to-keep)
;;   (let ((data (runs:get-all-but-most-recent-n-per-target target-patts runpatt num-to-keep)))
;;     (for-each
;;      (lambda (target)
;;        (let ((runs-to-remove (hash-table-ref data target )))
;;          (for-each
2152
2153
2154
2155
2156
2157
2158


2159
2160
2161
2162
2163
2164
2165
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185







+
+







		(run-state (db:get-value-by-header run header "state"))
		(run-name  (db:get-value-by-header run header "runname"))
		(tests     (if (not (equal? run-state "locked"))
			       (proc-get-tests run-id)
			       '()))
		(lasttpath "/does/not/exist/I/hope")
		(lastrealpath "/does/not/exist/I/hope")
                ;; there may be a number of different disks used in the same run.
                (run-paths-hash (make-hash-table))
		(worker-thread #f))
	   (debug:print-info 4 *default-log-port* "runs:operate-on run=" run ", header=" header)
	   (if (not (null? tests))
	       (begin
		 (case action
                   ((kill-runs)
                    (tasks:kill-runner target run-name "%")
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348






























2349
2350
2351
2352
2353
2354
2355
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







-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







                                              (mt:test-set-state-status-by-id run-id (db:test-get-id test) "KILLREQ" "n/a" #f)
                                              (thread-sleep! 1)))
                                        ;; NOTE: This is suboptimal as the testdata will be used later and the state/status may have changed ...
                                        (if (null? tal)
                                            (loop new-test-dat tal)
                                            (loop (car tal)(append tal (list new-test-dat)))))
                                      (begin
                                        (set! lasttpath (db:test-get-rundir new-test-dat)) ;; remember this path for run removal
                                        (if (file-exists? lasttpath) 
                                          (set! lastrealpath (resolve-pathname lasttpath))
                                          (set! lastrealpath lasttpath))
                                        (runs:remove-test-directory new-test-dat mode) ;; 'remove-all)

                                        (if (not (null? tal))
                                            (loop (car tal)(cdr tal)))))))
                                       (let ((rundir (db:test-get-rundir new-test-dat)))
                                        (if (and (not (string=  rundir "/tmp/badname")) 
                                             (file-exists? rundir)
                                             (substring-index run-name rundir)
                                             (substring-index target rundir)
                                             )
                                          (begin
                                            (set! lasttpath (db:test-get-rundir new-test-dat)) ;; remember this path for run removal
                                            (set! lastrealpath (remove-last-path-directory (resolve-pathname lasttpath)))
                                            (hash-table-set! run-paths-hash lastrealpath 1)
                                            (runs:remove-test-directory new-test-dat mode) ;; 'remove-all)
                                          )
                                          (begin
                                            (debug:print 2 *default-log-port* "Not removing directory " rundir " because either it doesn't exist or has a bad name")
                                            (debug:print 2 *default-log-port* "Is /tmp/badname: " (string=  rundir "/tmp/badname"))
                                            (debug:print 2 *default-log-port* "Exists: " (file-exists? rundir))
                                            (debug:print 2 *default-log-port* "Has run-name: " (substring-index run-name rundir))
                                            (debug:print 2 *default-log-port* "Has target: " (substring-index target rundir))
                                            ;;PJH remove record from db no need to cleanup directory
                                            (case mode
                                               ((remove-data-only)(mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) (db:test-get-state test)(db:test-get-status test) #f))
                                               ((archive-remove)  (mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) "ARCHIVED" #f #f))
                                               (else (rmt:delete-test-records (db:test-get-run_id test) (db:test-get-id test))))

                                          )
                                        )
                                      )

                                      (if (not (null? tal))
                                         (loop (car tal)(cdr tal)))))))
				(rmt:update-run-stats run-id (rmt:get-raw-run-stats run-id)))
                               ((kill-runs)
                                ;; RUNNING -> KILLREQ
                                ;; LAUNCHED,RUNNING,REMOTEHOSTSTART -> NOT STARTED
                                (cond
                                 ((and has-subrun (member test-state (list "RUNNING" "LAUNCHED" "REMOTEHOSTSTART" "KILLREQ")))
                                  (common:send-thunk-to-background-thread
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
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







-
-
+
+
-
-
-
-
-
+

+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+

+
-
-
-
+
+
+
+
+







                   (common:join-backgrounded-threads))))
	   
	   ;; remove the run if zero tests remain
	   (if (eq? action 'remove-runs)
	       (let* ((run-id   (db:get-value-by-header run header "id")) ;; NB// masks run-id from above?
                      (remtests (mt:get-tests-for-run run-id #f '("DELETED") '("n/a") not-in: #t)))
		 (if (null? remtests) ;; no more tests remaining
         ;; Remove the last dir from the path.
         ;; And same for the link-resolved path
	           (let* ((linkspath (remove-last-path-directory lasttpath))
                          (runpaths (hash-table-keys run-paths-hash))
		     (let* ((dparts  (string-split lasttpath "/"))
			      (linkspath (conc "/" (string-intersperse (take dparts (- (length dparts) 1)) "/")))
            (real-dparts (string-split lastrealpath "/"))
			      (realpath (conc "/" (string-intersperse (take real-dparts (- (length real-dparts) 1)) "/")))
            )
                    )

                    (debug:print 2 *default-log-port* "run-paths-hash: " (hash-table-keys run-paths-hash))

            (debug:print 1 *default-log-port* "Removing run: " linkspath)
            (if (not keep-records)
               (begin
                 (debug:print 1 *default-log-port* "Removing DB records for the run.")
                 (rmt:delete-run run-id)
                 (rmt:delete-old-deleted-test-records))
            )
	          (debug:print 1 *default-log-port* "Recursively removing links dir " linkspath)
            (runs:recursive-delete-with-error-msg linkspath)
                    (debug:print 1 *default-log-port* "Removing target " target "run: " run-name)
                    (if (not keep-records)
                      (begin
                        (debug:print 1 *default-log-port* "Removing DB records for the run.")
                        (rmt:delete-run run-id)
                        (rmt:delete-old-deleted-test-records))
                    )
                    (if (not (equal?  linkspath "/does/not/exist/I"))
	               (begin 
                         (debug:print 1 *default-log-port* "Recursively removing links dir " linkspath)
                         (runs:recursive-delete-with-error-msg linkspath)))

                   (for-each (lambda(runpath)
            (debug:print 1 *default-log-port* "Recursively removing real dir " realpath)
            (runs:recursive-delete-with-error-msg realpath)

                       (debug:print 1 *default-log-port* "Recursively removing runs dir " runpath)
                       (runs:recursive-delete-with-error-msg runpath)
                     )
                     runpaths
                   )
		       )))))
	 ))
     runs)
    ;; special case - archive get
    (if (equal? (args:get-arg "-archive") "get")
	(archive:bup-get-data "get" #f #f test-records rp-mutex bup-mutex))
    )
2697
2698
2699
2700
2701
2702
2703




























































































2704
2705
2706
2707
2708
2709
2710
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	    (sqlite3:execute 
	     db 
	     (conc "INSERT OR REPLACE INTO test_data (test_id,category,variable,value,expected,tol,units,comment) "
		   "SELECT " (db:test-get-id new-testdat) ",category,variable,value,expected,tol,units,comment FROM test_data WHERE test_id=?;")
	     (db:test-get-id testdat))))
	 ))
     prev-tests)))

(define doc-template 
  '(*TOP*
    (*PI* xml "version='1.0'")
    (testsuite)))

(define (runs:update-junit-test-reporter-xml run-id)
  (let*	(
	 (junit-test-reporter	(configf:lookup *configdat* "runs" "junit-test-reporter-xml"))
	 (junit-test-report-dir  (configf:lookup *configdat* "runs" "junit-test-report-dir"))
	 (xml-dir		(if (and junit-test-reporter (equal? junit-test-reporter "yes" ))
				    (if junit-test-report-dir
					junit-test-report-dir
					(conc (getenv "MT_LINKTREE") "/" (getenv "MT_TARGET") "/" (getenv "MT_RUNNAME")))
				    #f))
	 (xml-ts-name		(if xml-dir
				    (conc (getenv "MT_TESTSUITENAME")"."(string-translate (getenv "MT_TARGET") "/" ".") "." (getenv "MT_RUNNAME"))
				    #f))
         (keyname               (if xml-ts-name (common:get-signature xml-ts-name) #f))
	 (xml-path		(if xml-dir
				    (conc xml-dir "/" keyname ".xml")
				    #f))

	 (test-data		(if xml-dir
				    (rmt:get-tests-for-run run-id "%" '() '() ;; run-id testpatt states statuses
							   #f #f ;; offset limit
							   #f ;; not-in
							   #f ;; sort-by
							   #f ;; sort-order
							   #f ;; get full data (not 'shortlist)
							   0 ;; (runs:gendat-inc-results-last-update *runs:general-data*) ;; last update time
							   #f)
				    '()))
	 (tests-count		(if xml-dir (length test-data) #f)))
    (if (and junit-test-reporter (equal? junit-test-reporter "yes" ))
	(begin
					;((sxml-modify! `("testsuite" insert-into (@ (name ,xml-ts-name) (tests ,tests-count)))) doc)

	  (let loop	((test		(car test-data))
			 (tail		(cdr test-data))
			 (doc		doc-template)
			 (fail-cnt	0)
			 (error-cnt	0))
	    (let*	((test-name	(vector-ref test 2))
			 (test-itempath	(vector-ref test 11))
			 (tc-name	(conc test-name (if (and test-itempath (not (equal? test-itempath ""))) (conc "." (string-translate test-itempath "/" "." )) "")))
			 (test-state	(vector-ref test 3))
			 (comment	(vector-ref test 14))   
			 (test-status	(vector-ref test 4))
			 (exc-msg	(conc "No bucket for State " test-state " Status " test-status))
			 (new-doc	(cond 
						((member test-state (list "RUNNING" ))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (inProgress)))) doc))
						((member test-state (list "LAUNCHED" "REMOTEHOSTSTART"  "NOT_STARTED"))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (inQueue)))) doc))
						((member test-status (list "PASS" "WARN" "WAIVED"))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name))))) doc))
						((member test-status (list "FAIL" "CHECK"))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (failure (@ (message ,comment) (type "failure")))))) doc)) 
						((member test-status (list "DEAD" "KILLED" "ABORT" "PREQ_FAIL" "PREQ_DISCARDED"))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (failure (@ (message ,comment) (type "error")))))) doc))
						((member test-status (list "SKIP"))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (skipped (@ (type "skipped")))))) doc))
						(else 
							(debug:print 0 *default-log-port* (conc "What do I do with State " test-state " Status " test-status))
							((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (failure (@ (message ,exc-msg) (type "error")))))) doc))))
			(new-error-cnt	(if (member test-status (list "DEAD" "KILLED" "ABORT" "PREQ_FAIL" "PREQ_DISCARDED"))
						(+ error-cnt 1) 
						error-cnt))
			(new-fail-cnt	(if (member test-status (list "FAIL" "CHECK"))
						(+ fail-cnt 1)
						  fail-cnt)))
 	      (if (null? tail)
		    (let* ((final-doc ((sxml-modify `("testsuite" insert-into (@ (name ,xml-ts-name) (tests ,tests-count) (errors ,error-cnt) (failures ,fail-cnt)))) new-doc)))
		    (debug:print 0 *default-log-port* "modify attrib error=" error-cnt " fail= " fail-cnt)
		    (handle-exceptions
		     exn
		     (let*	((msg	((condition-property-accessor 'exn 'message) exn)))
		       (debug:print 0 *default-log-port* (conc "WARNING: Failed to update file" xml-path". Message:" msg)))
		     		   
		     (if (not (file-exists? xml-dir)) 
			 (create-directory xml-dir #t))
                     (if (not (rmt:no-sync-get/default keyname #f)) 
                       (begin
			 (rmt:no-sync-set  keyname "on")
			 (debug:print 0 *default-log-port* "creating xml at " xml-path)
		         (with-output-to-file xml-path
		         (lambda ()
			   (print (sxml-serializer#serialize-sxml final-doc  ns-prefixes: (list (cons 'gnm "http://foo"))))))
                           (rmt:no-sync-del! keyname))
                          (debug:print 0 *default-log-port*  "Could not get the lock. Skip writing the xml file."))))
		  (loop (car tail) (cdr tail) new-doc new-fail-cnt new-error-cnt))))))))
	 
     
;; clean cache files
(define (runs:clean-cache target runname toppath)
  (if target
      (if runname
	  (let* ((linktree (common:get-linktree)) ;; (if toppath (configf:lookup *configdat* "setup" "linktree")))

Modified utils/mtrunner from [726df7dae8] to [68e483031e].

24
25
26
27
28
29
30
31

24
25
26
27
28
29
30

31







-
+
  unset ${var}
done
cd $1
shift
export PATH="$1:$PATH"
shift 

"$@"
exec "$@"