Check-in [46ce198ba0]

Not logged in
Tcl 2015 Conference, Manassas/VA, US, Oct 19-23
Send your abstracts to tclconference@googlegroups.com by Aug 24.

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

Overview
Comment:Extended the website generator with a facility to add arbitrary text assets into the website. The assets and the controlling map (asset to path) are all stored as templates. The example map and assets demonstrate registration and submission forms.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | active-on-core
Files: files | file ages | folders
SHA3-256:46ce198ba0b1b31d6415d28b4283a0322571c40004d5e957af581aa0199ea2ea
User & Date: aku 2018-02-15 04:57:19
Context
2018-10-29
23:03
Fixed example asset map to the new form file paths. Added more asset maps for partial use of forms (submission only, registration only, none). Added template for CFP page when submissions are closed. Extended generrator to take registration and campaign stati into account for assets, and CFP page. check-in: 42683e65da user: aku tags: active-on-core
2018-02-15
04:57
Extended the website generator with a facility to add arbitrary text assets into the website. The assets and the controlling map (asset to path) are all stored as templates. The example map and assets demonstrate registration and submission forms. check-in: 46ce198ba0 user: aku tags: active-on-core
2018-02-07
03:57
Add dummy variable to make_submission call where the data is not used. check-in: 1c18f4b5ac user: aku tags: active-on-core
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added .fossil-settings/ignore-glob.





>
>
1
2
web/*
web_out/*

Added examples/asset/forms2.tcl.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































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

package require html
namespace eval form2 {
    variable Form2
    array set Form2 {
        star.0 "" 
	star.1 *
	missing ""
	invalid ""
    }

    variable btag <p>   ;# Could be <li>
    variable qnum
    variable cols       45

}



################################################################
# proc form2::Form_MultiPostProcess {id fields nextPage serialNum}--
#    Process a form
# Arguments
#   id		The identifier for this form, and the name 
#               of the directory that will contain data and 
#               Membership numbers
#   fields	A list of elements to display in the form
# fields format
#  {type   req key {text/selections} post}
#   input  1/0 key Label-beside     {}
#   select 1/0 key Label-beside     {default choice list}    
#   submit {}  key {text}           postP
#   break  1/0 {}  {}               {}
#   nextPage	The final page for this mess, relative or full URL
#   serialNum	Optional value if serial number req'd
# 
# Results
#   
# 
proc form2::Form_MultiPostProcess {id fields nextPage {memberNum -1} } {
    global page 
    variable Form2

    # set of [open /tmp/argh w]
    # puts $of "id $id fields $fields nextPage $nextPage memberNum $memberNum "
    # puts $of "DOCROOT $::Config(docRoot)"

    if {[form2::empty formid]} {
	# First time through the page
	set firstPass 1
    } else {
	# Incoming form values, check them
	set firstPass 0
	set memberNum [form2::data memberNum]
    }

    set html "<!-- Self-posting. Next page is $nextPage -->\n"
    append html "<form action=\"$page(url)\" method=post>\n"
    append html "<input type=hidden name=formid value=$id>\n"
    append html "<input type=hidden name=memberNum value=$memberNum>\n"
    append html "<div class=\"$id\">\n"
    append html [form2::genForm2 $id $firstPass $fields]

    append html "</div></form>\n"

    if {! $firstPass} {
	set ok [form2::checkRequired $fields]
	if {$ok} {
	    
	    set ok [${id}::validate $fields]
	    if {[llength $Form2(missing)] == 0 && $ok} {

		# No missing fields, so advance to the next page.
		# In practice, you must save the existing fields 
		# at this point before redirecting to the next page.

		set new [genBlankPage $id $fields $nextPage]

		set of [open /tmp/tst2 w]
		# puts $of "$Form2($id.calculate) $fields $nextPage"
		catch {
		    puts $of "NEW: ..$new.. -- $nextPage"
		    close $of
		}

		#		 Doc_Redirect $new
		set rtn [Redirect_Self $new]
		set of [open /tmp/tst2 a]
		puts $of $rtn
		close $of
	    }
	}
	if {!$ok} {
	    set msgMissing ""
	    set msgInvalid ""
	    if {!$ok} {
		if {[llength $Form2(invalid)] == 1} {
		    set msgInvalid {<div class="alert">Please correct this field: }
		} elseif {[llength $Form2(invalid)] != 0} {
		    # Skip if corrections are not there - just missing
		    set msgInvalid {<div class="alert">Please correct these fields: }
		}
		append msgInvalid [join $Form2(invalid) "<br "]
		append msgInvalid "</div><p>"
	    }
	    if {[llength $Form2(missing)] > 0} {
		if {[llength $Form2(missing)] == 1 } {
		    set msgMissing {<div clsss="alert">Please fill in this field:  }
		} elseif {[llength $Form2(missing)] > 1} {
		    set msgMissing {<div class="alert">Please fill in these fields:<br> }
		}
		append msgMissing [join $Form2(missing) "<br> "] 
	    }
	    set html "<P>\n$msgMissing\n<P>\n$msgInvalid\n$html"
	}
    }
    # catch {close $of}
    return $html
}

proc form2::checkRequired {fields} {
    set result 1

    foreach {type required key label post} $fields {
	if {$required} {
	    set val [string trim [form2::data $key]]
	    if {[string equal {} $val]} {
		# form2::appendIndex invalid "Need to fill in $label"
		set result 0
	    }
	}
    }

    return $result
}


proc form2::makeUniqueFileName {prefix} {
    set uniq 0
    while {[file exists ${prefix}_$uniq]} {
	incr uniq
    }
    return ${prefix}_$uniq
}

proc html::input {name dflt args} {
    return "<input name=\"$name\" value=\"$dflt\">"
}

proc html::label {name args} {
    return "<B>$name</B>"
}
proc html::break {args} {
    return "<br>"
}

################################################################
# proc form2::item {firstPass type key label post}--
#    Return the HTML for an form element
# Arguments
#   firstPass	1 if first time (no check) else 0
#   key		Key/name for this page variable
#   
# 
# Results
#   
# 
proc form2::item {firstPass type key label post} {
    switch $type {
	label {
	    set text "	    [eval [list html::$type $key ]]\n"
	}
	textInput {
	    set text "       [eval [list html::$type $key {} $post ]]\n"
	}
        submit {
	    set text "       <input type=submit name=$key value=$label>\n"
	}
	hidden {
	    set text "       $post <input type=hidden name=$key value=\"$post\">\n"
	}
	select {
	    set text "       [html::select $key {} $post]\n"
	}
	exact {
	    set text "       $key\n"
	}
	default {
	    set text "       [eval [list html::$type $key $label $post]]\n"
	}
    }
    return "$text"
}

################################################################
# proc form2::getFontDesc {firstPass req key } --
#    Returns a list of font on/font off depending on whether
#  this is the first pass, data is filled in, etc.
# Arguments
#   firstPass	1 if first time (no check) else 0
#   req		Is this required (1)
#   key		Key/name for this page variable
# 
# Results
#   Returns a list which may be two empty strings, or 
#   will be a start/end font descriptor.
# 
proc form2::getFontDesc {firstPass req key } {
    variable Form2
    if {(!$firstPass) && $req && [form2::empty $key]} {
        set startFont {  <div class="alert">}
	set endFont {</div>}
    } else {
        set startFont {}
	set endFont {}
    }
    return [list $startFont $endFont]
}

################################################################
# proc form2::genForm2 {id firstPass lst}--
#    Return a body for a table
# Arguments
#   id 		The identifier for this input section
#   firstPass	1 if first time (no check) else 0
#   lst		A list of descriptors, see above for format.
#   missingVar	VarName for a variable to get the missing count, 
#               if not firstPass
# Results
#   Returns a set of table row definitions, but not <TABLE>/</TABLE>

proc form2::genForm2 {id firstPass lst } {
    variable Form2
    set Form2(missing) {}
    
    set html [formBody $id $firstPass $lst]

    set Form2(missing) [string trim $Form2(missing) ", "]
    #
    # Check for input fields before adding the "Continue/Reset buttons.
    #
    if {([string first {type="text"} $html] > 0) ||
	([string first {<select name=} $html] > 0)} {
	append html {<p><input type=submit name=submit value=Continue>}
	append html {<input type="reset">}
    }
    return $html  
}

proc form2::formBody {id firstPass lst } {
    variable Form2

    append html "<input type=hidden name=formid value=$id>\n"

    foreach {type req key label post} $lst {
	
	if {$req} {
	    set style [string map [list [clock format [clock seconds] -format %Y] ""] $id]_required
	    if {$post eq ""} {
		set post " required "
	    } else {
		append style " required "
	    }
	} else {
	    set style [string map [list [clock format [clock seconds] -format %Y] ""] $id]
	}

	foreach {startFont endFont} \
	    [getFontDesc $firstPass $req $key ] {}
	
	if {![string match [string trim $startFont] ""]} {
	    regexp {([0-9a-zA-Z\.\ ,\-_]+)} $label all a
	    lappend Form2(missing) [string trim $a]
	}

	switch $type {
	    label {
		append html "  [eval [list form2::item $firstPass $type $key $label $post]]\n"
	    }
	    exact {
		append html "  [eval [list form2::item $firstPass $type $key $label $post]]\n"
	    }
	    default {
		append html "  <br> $startFont <label class=\"$style\"> $label</label> $endFont\n"
		append html "       [eval [list form2::item $firstPass $type $key $label $post]]\n"
	    }
	}      
    }
    return $html  
}


# form2::empty --
#
#       Return true if the variable doesn't exist or is an empty string

proc form2::empty {name} {
    set x [ncgi::empty $name]
    if {[string match $x ""]} {
        set x 0
    }
    return $x
}


proc form2::startNumber {i} {
    variable qnum $i
}
proc form2::incrNumber {} {
    variable qnum
    incr qnum
}


proc form2::getFormInfo {} {
    global page
    set html ""
    if {![info exist page(query)]} {
	return "<!-- no query data -->\n"
    }
    foreach {name value} $page(query) {
	if {[string match submit_* $name] || [string match token $name]} {
	    continue
	}
	append html "<input type=hidden name=\"$name\" value=\"$value\">\n"
    }
    return $html
}

# form2::line --
#
#	Display an entry in a table row

proc form2::line {name question {value {}}} {
    set html "<tr><td>$question\n</td><td><input type=text size=30 [form2::value $name]></td></tr>\n"
    return $html
}

proc form2::text {lines name question {value {}}} {
    variable btag
    variable cols
    if {$lines == 1} {
	set html "$btag$question\n<br><input type=text name=\"$name\" size=$cols value=\"$value\">\n"
    } else {
	set html "$btag$question\n<br><textarea name=\"$name\" cols=$cols rows=$lines>$value</textarea>\n"
    }
    return $html
}

proc form2::checkbox {name question {value yes}} {
    variable btag
    set html "$btag<input type=checkbox name=\"$name\" value=$value> $question\n\n"
}

proc form2::selectplain {name size choices} {
    set namevalue {}
    foreach c $choices {
	lappend namevalue $c $c
    }
    return [form2::select $name $size $namevalue]
}

proc form2::select {name size choices} {
    global page

    if {![form2::empty $name]} {
	array set query $page(query)
	set current $query($name)
    } else {
	set current ""
    }
    set html "<select name=\"$name\" size=$size>\n"
    foreach {v label} $choices {
	if {[string match $current $v]} {
	    set SEL SELECTED
	} else {
	    set SEL ""
	}
	append html "<option value=\"$v\" $SEL>$label\n"
    }
    append html "</select>\n"
    return $html
}

proc form2::classboxStart {} {
    set html "<table cellpadding=2>\n<tr valign=top><th>Course Description</th><th># Students</th><th>Travel?</th></tr>\n"
}

proc form2::classbox {name desc} {
    append html "<tr><td><input type=checkbox name=\"$name\" value=yes> $desc</td>\n"
    append html "<td><input type=text name=\"${name}_size\" size=6></td>\n"
    append html "<td><input type=checkbox name=\"{$name}_travel\" value=yes></td>\n"
    append html </tr>\n
}
proc form2::classboxEnd {} {
    set html "</table>"
}



proc form2::submit {label {name submit}} {
    variable btag
    set html "$btag<input type=submit name=\"$name\" value=\"$label\">\n"
}

# Return a name and value pair, where the value is initialized
# from existing form data, if any.

proc form2::value {name} {
    global page
    if {[catch {array set query $page(query)}] ||
	![info exist query($name)]} {
	return "name=$name value=\"\""
    }
    return "name=$name value=\"$query($name)\""
}

# Return a form value, or "" if the element is not defined in the query data.

proc form2::data {name} {
    global page
    if {[catch {array set query $page(query)}] ||
	![info exist query($name)]} {
	return ""
    }
    return $query($name)
}

# Like form2::value, but for checkboxes that need CHECKED

proc form2::checkvalue {name {value 1}} {
    global page
    if {[catch {array set query $page(query)}] ||
	![info exist query($name)]} {
	return "name=$name value=\"$value\""
    }
    foreach {n v} $page(query) {
	if {[string compare $name $n] == 0 &&
	    [string compare $value $v] == 0} {
	    return "name=$name value=\"$value\" CHECKED"
	}
    }
    return "name=$name value=\"$value\""
}

# Like form2::value, but for radioboxes that need CHECKED

proc form2::radiovalue {name value} {
    global page
    if {[catch {array set query $page(query)}] ||
	![info exist query($name)] ||
	[string compare $query($name) $value] != 0} {
	return "name=$name value=\"$value\""
    }
    return "name=$name value=\"$value\" CHECKED"
}

# form2::radioset --
#
#	Display a set of radio buttons while looking for an existing
#	value from the query data, if any.

proc form2::radioset {key sep list} {
    global page
    if {[info exist page(query)]} {
	array set query $page(query)
	set html "<!-- radioset $key $page(query) -->\n"
    }
    foreach {v label} $list {
	if {![form2::empty $key] &&
	    [string match $v $query($key)]} {
	    set SEL CHECKED
	} else {
	    set SEL ""
	}
	append html "<input type=radio name=$key value=$v $SEL> $label$sep"
    }
    return $html
}

# form2::checkset --
#
#	Display a set of check buttons while looking for an existing
#	value from the query data, if any.

proc form2::checkset {key sep list} {
    global page
    if {[info exist page(query)]} {
	array set query $page(query)
    }
    foreach {v label} $list {
	if {![empty query($key)] &&
	    [lsearch $query($key) $v] >= 0} {
	    set SEL CHECKED
	} else {
	    set SEL ""
	}
	append html "<input type=checkbox name=$key value=$v $SEL> $label$sep"
    }
    return $html
}


proc form2::setProc {index procName {new 0}} {
    variable Form2
    if {![info exists Form2($index)] && (!$new)} {
        error "$index is a bad index" "$index is a bad index"
    }

    if {[string equal [info procs $procName] {} ]} {
        error "$procName is a bad procedure" "$procName is a bad procedure"
    }
    set Form2($index) $procName
    return ""
}

proc form2::appendIndex {index value} {
    variable Form2

    if {![info exists Form2($index)]} {
        error "$index is a bad index" "$index is a bad index"
    }
    lappend Form2($index) $value
}

proc form2::setIndex {index value} {
    variable Form2

    if {![info exists Form2($index)]} {
        error "$index is a bad index" "$index is a bad index"
    }
    set Form2($index) $value
    return ""
}

proc form2::getIndex {index } {
    variable Form2

    if {![info exists Form2($index)]} {
        error "$index is a bad index" "$index is a bad index"
    }
    return $Form2($index)
}

proc form2::renameFile {path id value} {

    if {![file exists $path/inProcess_$id]} {
	return "This transaction was already completed"
    }

    if {[string match $value OK]} {
	file rename $path/inProcess_$id $path/confirm_$id
	set html "Transaction is confirmed OK for $id"
    } else {
	file rename $path/inProcess_$id $path/cancel_$id
	set html "Transaction is cancelled for $id"
    }
    return $html
}
# KEY: "testID for http pages"


proc form2::BAD_CSS_list2tableBody {columnCount data} {
    set pos -1;
    while {$pos < [llength $data]} {
	append html " \n<BR> <div class=\"line\">"
	for {set i 0} {$i < $columnCount} {incr i} {
	    append html " <span margin-right=[expr {($i+1)*20}]> [lindex $data [incr pos]]</span>"
	}
	append html " </div>\n"
    }
    return $html
}

proc form2::BAD_FORM_list2tableBody {columnCount data} {
    set pos -1;
    while {$pos < [llength $data]} {
	append html " \n<BR>"
	set item {label"}
      for {set i 0} {$i < $columnCount} {incr i} {
        append html "\n  <$item>[lindex $data [incr pos]]</[lindex $item 0]>"
	set item {input type="text" size="20em"}
      }
    }
    return $html
}

proc form2::list2tableBody {columnCount data} {
    set pos -1;
    while {$pos < [llength $data]} {
	append html " \n<TR>"
	for {set i 0} {$i < $columnCount} {incr i} {
	    append html "\n  <TD>[lindex $data [incr pos]]</TD>"
	}
    }
    return $html
}

proc form2::pairs2tableBody {data} {
    set html ""
    set i 0
    foreach {lbl val} $data {
	if {[string trim $lbl] eq ""} {continue}
	if {[string trim $val] eq "-"} {continue}
	append html "\n<tr>"
	append html "  <td>$lbl</td>\n"
	append html "    <td>$val</td>\n"
    }
    return $html
}

proc form2::pairs2FormRows {data} {
    set html ""
    set i 0
    foreach {lbl val} $data {
	if {[string trim $lbl] eq ""} {continue}
	append html "\n<br>"
	append html "  <label>$lbl</label>\n"
	append html "    <input name=n[incr i] type=text value=\"$val\">$val</input>\n"
    }
    return $html
}

proc form2::Form_Survey {id postProcess selections nextpage} {
    global page
    if {![form2::empty formid]} {
	# Incoming form values, check them
	set check 1
    } else {
	# First time through the page
	set check 0
    }
    set html "<!-- Self-posting. Next page is $nextpage -->\n"
    append html "<form action=\"$page(url)\" method=post>\n"
    append html "<input type=hidden name=formid value=$id>\n"
    
    append html {<TABLE border="1">}
    
    foreach entry $selections {
	foreach {txt name param choices dflt} $entry {break} 
	#	    append html "<TR>   <TD> $txt \n    <TD>"
	#	    append html [html::select $name $param $choices $dflt]
	append html "<TR>\n  <TD> [html::select $name $param $choices $dflt]\n"
	append html "  <TD> <A HREF=\"#$name\"> $txt </A>"
	lappend fields [list $txt $name]
    }
    append html </TABLE>
    
    # puts "CHECK: $check -- [info exist missing]"
    if {$check} {
	# puts "FORMID:  [form2::data formid]"
	if {![info exist missing]} {

	    # No missing fields, so advance to the next page.
	    # In practice, you must save the existing fields 
	    # at this point before redirecting to the next page.
	    
	    # puts "Reqired fields: $fields"
	    foreach f $fields {
		foreach {txt key} $f {break}
		lappend d [list $txt $key [form2::data $key]]
		# puts "$txt -- $key -- [form2::data $key]"
	    }
	    
	    $postProcess $d

	    Doc_Redirect $nextpage
	} 
    }

    append html "<BR><input type=submit>\n</form>\n"

    return $html
}

proc form2::SurveyProcess {dataList} {
    global Doc
    catch {source $Doc(root)/surveyData.tcl}

    foreach entry $dataList {
	foreach {txt key val} $entry {break} 
	if {[info exists survey($key.$val)]} {
	    incr survey($key.$val)
	} else {
	    set survey($key.$val) 1
	    set survey($key.text) $txt
	}
    }
    set of [open $Doc(root)/surveyData.tcl w]
    puts $of "array set survey [list [array get survey]]"
    close $of
}

proc form2::SurveyReport {} {
    global Doc
    source $Doc(root)/surveyData.tcl
    
    set fields ""
    set labels ""
    set keys ""

    foreach f [lsort [array names survey]] {
	foreach {k v} [split $f "."] {break;}
	if {[string match $v "text"]} {continue}
	if {[lsearch $fields $v] < 0} {lappend fields $v}
	if {[lsearch $keys $k] < 0} {lappend keys $k}
    }

    set txt ""
    set page "<TABLE>"
    append page "<TR> <TH> Title\n"

    foreach v [lsort $fields] {
	set l [lrange [split $v -] 1 end]
	append page "   <TH> $l\n"
    }

    foreach k $keys {
	append page "\n <TR><TD> $survey($k.text)\n"
	foreach f [lsort $fields] {
	    if {[info exists survey($k.$f)]} {
		append page "   <TD> $survey($k.$f)\n"
	    } else {
		append page "   <TD> 0\n"
	    }
	}
    }
    
    append page "</TABLE>"
    return $page
}

proc form2::incrSerialNum {id} {
    global page
    set fileName [file root $page(filename)]/$id.ser
    if {[catch {
	set if [open $fileName r]
    }]} {
	# auto-handle missing serial by creating a suitable starting point
	set serialNum [clock format [clock seconds] -format %Y]0000
    } else {
	set serialNum [gets $if]
	close $if
    }
    incr serialNum
    set of [open $fileName w]
    puts $of $serialNum
    close $of
    return $serialNum
}

proc form2::genBlankPage {id fields nextPage} {
    if {[info exists ${id}::PayPalURL]} {
	return [genRegisterBlankPage $id $fields $nextPage]
    } else {
	return [genSubmitBlankPage $id $fields $nextPage]
    }
}

proc form2::genSubmitBlankPage {id fields nextPage} {

    foreach {type required key label post} $fields {
	set val [form2::data $key]
	if {![string match $label ""] && [string match $val ""]} {
	    set val "-"
	}
	lappend lst $label $val
	append mail "$label: $val\n"
    }    
    
    set serNum [form2::incrSerialNum $id]
    lappend lst "ID Number" $serNum

    set if [open [file root $::page(filename)].tml r]
    set blank [read $if]
    close $if

    set p1 [string first "DO NOT" $blank ]
    set p1 [string first "\[" $blank $p1]  
    set p2 [string last "DO NOT" $blank ] 
    set p2 [string last  "\]" $blank $p2]
    incr p1 -1
    incr p2

    set pre [string range $blank 0 $p1]
    set post [string range $blank $p2 end]
    
    set fileBase [file dirname $::page(filename)]/submit_$serNum
    set of [open $fileBase.tml w]
    puts $of $pre
    puts $of [set ${id}::ConfirmMsg]
    puts $of <table>
    puts $of [form2::pairs2tableBody $lst]
    puts $of "</table>\n"
    puts $of [format {
	<form action="%s" method="post">\
	    <input type="hidden" name="memberNum" value="%s">
	<input type="hidden" name="invoice" value="%s">
	<input type="hidden" name="cmd" value="_xclick">} $nextPage $serNum $serNum]

    puts $of { <p><input type=submit name="submit" value="Submit">
	<input type=submit name="submit" value="Cancel">
	</form>}

    puts $of $post

    close $of
    after 100
    return [string map [list [file normalize $::Config(docRoot)] ""] $fileBase.html]
}

proc form2::genRegisterBlankPage {id fields nextPage} {

    foreach {type required key label post} $fields {
	set val [form2::data $key]
	if {![string match $label ""] && [string match $val ""]} {
	    set val "-"
	}
	lappend lst $label $val
    }    
    
    set total [${id}::calculate $fields]
    
    lappend lst Total $total
    set serNum [form2::incrSerialNum $id]
    lappend lst "ID Number" $serNum

    set if [open [file root $::page(filename)].tml r]
    set blank [read $if]
    close $if

    set p1 [string first "DO NOT" $blank ]
    set p1 [string first "\[" $blank $p1]  
    set p2 [string last "DO NOT" $blank ] 
    set p2 [string last "\]" $blank $p2]
    incr p1 -1
    incr p2

    set pre [string range $blank 0 $p1]
    set post [string range $blank $p2 end]
    
    set fileBase [file dirname $::page(filename)]/register_$serNum
    set of [open $fileBase.tml w]
    puts $of $pre
    puts $of [set ${id}::ConfirmMsg]
    puts $of <table>
    puts $of [form2::pairs2tableBody $lst]
    puts $of "</table>\n"
    puts $of [format {
	<form action="%s" method="post">\
	    <input type="hidden" name="cmd" value="_xclick">\
	    <input type="hidden" name="amount" value="%5.2f">
	<input type="hidden" name="no_shipping" value="1">
	<input type="hidden" name="business" value="%s">
	<input type="hidden" name="quantity" value="1">
	<input type="hidden" name="item_name" value="%s">
	<input type="hidden" name="cpp_header_image" value="%s">
	<input type="hidden" name="page_style" value="Editomat">
	<input type="hidden" name="return"  value="%s">
	<input type="hidden" name="memberNum" value="%s">
	<input type="hidden" name="invoice" value="%s">
	<input type="hidden" name="custom" value="%s">} \
		  [set ${id}::PayPalURL] \
		  $total \
		  [set ${id}::PayPalBusiness] \
		  [set ${id}::PayPalItem] \
		  [set ${id}::PayPalImage] \
		  [set ${id}::PayPalReturnURL] \
		  $serNum \
		  $serNum \
		  $serNum ]

    puts $of { <p><input type=submit name="submit" value="Purchase">
	<input type=submit name="submit" value="Cancel">
	</form>}

    puts $of $post
    close $of
    return [string map [list [file normalize $::Config(docRoot)] ""] $fileBase.html]
}

Added examples/asset/register.tml.

























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
<!DOCTYPE html>
<html>    
  <head>
    <meta charset="UTF-8">   
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="canonical" href="https://core.tcl.tk/conference/tcl@c:year@/index.html">
      <link rel="icon" href="./images/favicon.png">
    <title>Register an attendant | @c:name@</title>  
    <!-- Bootstrap core CSS -->
    <link href="./external/bootstrap-3.3.1-dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap theme -->
    <link href="./external/bootstrap-3.3.1-dist/css/bootstrap-theme.min.css" rel="stylesheet">
    <!-- Custom stylesheets, if any -->
      <link href="./tclssg.css" rel="stylesheet">
  </head>

[Doc_Dynamic]

    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-colapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="index.html"><div class="pull-left"> <img src="http://www.tclcommunityassociation.org/wub/imgs/tcla_logo2c-tiny.gif" style="height: 33px; margin-top: -10px;"> @c:name@</div></a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
            <li><a href="http://www.tcl.tk/community/conferences.html">Related</a></li>
            <li><a href="./cfp.html">Call For Papers</a></li>
            <li><a href="./location.html">Location</a></li>
            <li><a href="./register.html">Registration</a></li>
            <li><a href="./tutorials.html">Tutorials</a></li>
            <li><a href="./schedule.html">Schedule</a></li>
            <li><a href="./proceedings.html">Proceedings</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </div>
   
<!-- DO NOT CHANGE CODE BETWEEN COMMENTS -->
[
# forms2.tcl and desSupport.tcl exist in "custom"
# EXCEPT on www.tcl.tk
#catch {
#set of [open /tmp/argh w]
#puts $of "START $::page(filename)"; flush $of
#puts $of "EXIST: [file exists $::page(filename)]"; flush $of
source [file dirname $::page(filename)]/forms2.tcl

#set formID "[file tail [ file root $page(filename)]][clock format [clock seconds] -format %Y ]"
set formID "[file tail [ file root $page(filename)]]"
#puts $of "FORMID: $formID"

namespace eval ::$formID {
  source [file root $page(filename)]/$formID.cfg

  if {[info procs validate] eq ""} {
    source [file root $page(filename)]/$formID.procs
  }

  ::form2::Form_MultiPostProcess $formID $formData confirm.html 1234
}
#} shit
#puts $of $shit
#close $of

]
<!-- DO NOT CHANGE CODE BETWEEN COMMENTS -->

</body>
</html>

Added examples/asset/register/register.cfg.















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#  {type   req key {text/selections} post}
#   input  1/0 key Label-beside     {}
#   select 1/0 key Label-beside     {default choice list}
#   submit {}  key {text}           postP
#   break  {}  {}  {}               {}

#  select    1 friday "Friday After-noon visit to Air and Space Museum (free)" {YES yes NO no}

#    "Tcl Tricks and Tips (Steve Landers)" "mam2" 

set formData {
  label     0 "Attendee Information" {} {}
  select    0 hon "Honorific:" { "" "" Mr Mr Mrs Mrs Ms Ms Dr Dr }
  textInput 1 fname "First Name:" {}
  textInput 1 lname "Last Name:" {}
  textInput 0 company "Company/Affiliation:" {}
  textInput 1 street1 "Street Address 1:" {}
  textInput 0 street2 "Street Address 2:" {}
  textInput 1 city "City:" {}
  textInput 1 state "State/Province:" {}
  textInput 1 zip "Zip/Post:" {}
  textInput 1 country "Country:" {}
  textInput 0 phone "Phone:" {}
  textInput 1 email "e-mail:" {}
  break     0 {} {} {}
  select    1 type "Payment Type:" {"" "" PLASTIC plastic CHECK check }
  break     0 {} {} {}
  label     0 "Registration Details" {} {}
  break     0 {} {} {}
  select    1 tech "Technical Sessions (395.00 US, less discount):" {YES yes NO no}
  break     0 {} {} {}
  label     0 "Tutorials : 195.00 US each (less volume discount) "  "" ""

  break  0 {} {} {}
  select 0 tutorialsMAM "Monday Morning Tutorial:" \
    {"" "" \
    "Intro to Tcl I (Clif Flynt)" "mam1" \
    "Sundry Advanced Topics-Ttk themes with TclOO, quadcode packaging, & Stuff (Sean Woods)" "mam2" \
    }
  select 0 tutorialsMPM "Monday Afternoon Tutorial:" {"" "" \
    "Intro to Tcl II (Clif Flynt)" "mpm1" \
    "Advanced Tcl with Raspberry Pi (Gerald Lester)" "mpm2" \
    }
  select 0 tutorialsTAM "Tuesday Morning Tutorial:" {"" "" \
    "New Tcl Features (Volunteer)" "tam1" \
    "Advanced Tcl: Namespaces and Packages (Clif Flynt)" "tam2" \
    }
  select 0 tutorialsTPM "Tuesday Afternoon Tutorial:" {"" "" \
    "Merging C/C++ and Tcl with CriTcl (Andreas Kupries)" "tpm1" \
    "Introduction to TclOO (Clif Flynt)" "tpm2" \
    }
  break  0 {} {} {}
  select 1 cd "Extra Memory Stick (5.00 US ea) :" {0 0 1 1 2 2 3 3 4 4 5 5 6 6}
  select 1 book "Printed Proceedings (20.00 US ea) :" {0 0 1 1 2 2 3 3 4 4 5 5 6 6}
  select 1 discount "Discounts:" {NONE none STUDENT student {STUDENT WITH MEALS} student-meal PRESENTER presenter CORPORATE corporate} 
  textInput 0 corpid "Co-Worker Membership number" {}
  break  0 {} {} {}
  }

set PayPalURL        https://www.paypal.com/cgi-bin/webscr
set PayPalBusiness   clif@noucorp.com
set PayPalItem       "Conference Registration"
set PayPalImage      "https://www.tcl.tk/community/images/tclassoc2.gif"
set PayPalReturnURL  http://www.tcl.tk/community/tcl@c:year@/confirm.html 

set ConfirmMsg	{Please confirm that these values are correct. If any values
are incorrect, press your browser's <b>Back</b> button to correct them.
<p>
If the values are correct, click <b>Purchase</b> to 
be transferred to Paypal to complete the transaction. 
<P> You do not need to have a PayPal account to purchase this product.}

Added examples/asset/register/register.procs.









































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
proc validate {fields} {
  set result 1

  foreach {type required key label post} $fields {
    if {[string match $key number]} {
      set label [string trim $label :]
      set payType [string trim [form2::data type]]
      set acct [string trim [form2::data number]]
      regsub -all {[ -]} $acct {} acct
      array set nums {{} 0 amex 15 visa 16 mastercard 16 discover 16 check 0}

      if {[string length $acct] != $nums($payType)} {
        form2::appendIndex invalid $label
        set result 0
      }
      set d2 [string trim [form2::data exp]]
      if {([string length $d2] != 4) && ![string equal "check" $payType]} {
        form2::appendIndex invalid "Expiration date"
        set result 0
      }
    }

    if {[string match $key discount]} {
      if {[string match "corporate" [form2::data discount]]} {
        set id [string trim [form2::data corpid]]
	if {$id >= [form2::data memberNum] ||
	    [string match $id ""]} {
              form2::appendIndex invalid "Co-Worker Membership number"
              set result 0
	    }
      }
    }

    if {$required} {
        set val [string trim [form2::data $key]]
	if {[string equal {} $val]} {
           form2::appendIndex invalid "Need to fill in $label"
           set result 0
	}
    }
  }

  return $result
}

################################################################
# proc calculate {fields nextPage}--
#    calculate final cost, create confirm page, 
#    put data into gpg encrypted file, keyed on formid value.
#    gpg --gen-key  to create key
#    gpg -r $formID -o InProcess_$memberNum -e --  to wrote file
#    use ::form2::saveEncrypted
# Arguments
#   
# 
# Results
#   
# 
proc calculate {fields} {
  global Config

  foreach {type required key label post} $fields {
    lappend d [list $key [form2::data $key]]
  }
  array set discount {none 0 usenix 50 
    student 395 student-meal 345 presenter 100 corporate 50}

  if {[string match [form2::data tech] "yes"]} {
    set total 395
    set total [expr $total - $discount([form2::data discount])]
  } else {
    set total 0
  }

  set tutorialCount 0

  foreach tutorial {tutorialsMAM tutorialsMPM
                    tutorialsTAM tutorialsTPM
                    tutorialsWAM tutorialsWPM} {
     if {![string match [form2::data $tutorial] ""]} {
         incr tutorialCount
     }
  }

  array set tutorialCost { 0   0 
                           1   195  
			   2   350  
			   3   500  
			   4   650  
			   5   800  
			   6   900} 

  set total [expr $total + [form2::data cd] * 5]
  set total [expr $total + [form2::data book] * 20]
  set total [expr $total + $tutorialCost($tutorialCount)]
  set total [format %.2f $total]

  return $total
}

Added examples/asset/submit.tml.

























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
<!DOCTYPE html>
<html>    
  <head>
    <meta charset="UTF-8">   
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="canonical" href="https://core.tcl.tk/conference/tcl@c:year@/index.html">
      <link rel="icon" href="./images/favicon.png">
    <title>Submit a paper | @c:name@</title>  
    <!-- Bootstrap core CSS -->
    <link href="./external/bootstrap-3.3.1-dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap theme -->
    <link href="./external/bootstrap-3.3.1-dist/css/bootstrap-theme.min.css" rel="stylesheet">
    <!-- Custom stylesheets, if any -->
      <link href="./tclssg.css" rel="stylesheet">
  </head>

[Doc_Dynamic]

    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-colapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="index.html"><div class="pull-left"> <img src="http://www.tclcommunityassociation.org/wub/imgs/tcla_logo2c-tiny.gif" style="height: 33px; margin-top: -10px;"> @c:name@</div></a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
            <li><a href="http://www.tcl.tk/community/conferences.html">Related</a></li>
            <li><a href="./cfp.html">Call For Papers</a></li>
            <li><a href="./location.html">Location</a></li>
            <li><a href="./register.html">Registration</a></li>
            <li><a href="./tutorials.html">Tutorials</a></li>
            <li><a href="./schedule.html">Schedule</a></li>
            <li><a href="./proceedings.html">Proceedings</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </div>
   
<!-- DO NOT CHANGE CODE BETWEEN COMMENTS -->
[
# forms2.tcl exists as sibling
# EXCEPT on www.tcl.tk
# catch {
# set of [open /tmp/argh w]
# puts $of "START $::page(filename)"; flush $of
# puts $of "EXIST: [file exists $::page(filename)]"; flush $of
source [file dirname $::page(filename)]/forms2.tcl
#set formID "[file tail [ file root $page(filename)]][clock format [clock seconds] -format %Y ]"
set formID "[file tail [ file root $page(filename)]]"
#puts $of "FORMID: $formID"

namespace eval ::$formID {
  source [file root $page(filename)]/$formID.cfg

#  if {[info procs validate] eq ""} {
    source [file root $page(filename)]/$formID.procs
#  }

  ::form2::Form_MultiPostProcess $formID $formData thanks.html 1234
}
# } shit
#puts $of $shit
#puts $of $::errorInfo
#close $of
#set shit
]
<!-- DO NOT CHANGE CODE BETWEEN COMMENTS -->

</body>
</html>

Added examples/asset/submit/submit.cfg.

































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#  {type   req key {text/selections} post}
#   input  1/0 key Label-beside     {}
#   select 1/0 key Label-beside     {default choice list}
#   submit {}  key {text}           postP
#   break  {}  {}  {}               {}

#  select    1 friday "Friday After-noon visit to Air and Space Museum (free)" {YES yes NO no}

#    "Tcl Tricks and Tips (Steve Landers)" "mam2" 

set formData {
  label     0 "Attendee Information" {} {}
  textInput 1 fname   "First Name:" {}
  textInput 1 lname   "Last Name:" {}
  textInput 0 company "Company/Affiliation:" {}
  textInput 0 phone   "Phone:" {}
  textInput 1 email   "e-mail:" {}
  break     0 {} {} {}

  label     0 "Paper Proposal" {} {}
  textInput 1 title    "Title"  {}
  textarea  1 abstract Abstract {}
}

set ConfirmMsg {Please confirm that these values are correct. If any values
are incorrect, press your browser's <b>Back</b> button to correct them.
<p>If the values are correct, click <b>OK</b> to complete the transaction.}

# Full set of possible form fields
##
# label     0 "Attendee Information" {} {}
# select    0 hon "Honorific:" { "" "" Mr Mr Mrs Mrs Ms Ms Dr Dr }
# textInput 1 fname "First Name:" {}
# textInput 1 lname "Last Name:" {}
# textInput 0 company "Company/Affiliation:" {}
# textInput 1 street1 "Street Address 1:" {}
# textInput 0 street2 "Street Address 2:" {}
# textInput 1 city "City:" {}
# textInput 1 state "State/Province:" {}
# textInput 1 zip "Zip/Post:" {}
# textInput 1 country "Country:" {}
# textInput 0 phone "Phone:" {}
# textInput 1 email "e-mail:" {}
# break     0 {} {} {}

  # label     0 "Paper Proposal" {} {}
  # textInput 1 title "Title" {}
  # textarea 1 abstract Abstract {}

Added examples/asset/submit/submit.procs.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# -*- tcl -*-

proc validate {fields} {
    set result 1

    foreach {type required key label post} $fields {
	if {[string match $key number]} {
	    set label [string trim $label :]
	    set payType [string trim [form2::data type]]
	    set acct [string trim [form2::data number]]
	    regsub -all {[ -]} $acct {} acct
	    array set nums {{} 0 amex 15 visa 16 mastercard 16 discover 16 check 0}

	    if {[string length $acct] != $nums($payType)} {
		form2::appendIndex invalid $label
		set result 0
	    }
	    set d2 [string trim [form2::data exp]]
	    if {([string length $d2] != 4) && ![string equal "check" $payType]} {
		form2::appendIndex invalid "Expiration date"
		set result 0
	    }
	}

	if {[string match $key discount]} {
	    if {[string match "corporate" [form2::data discount]]} {
		set id [string trim [form2::data corpid]]
		if {$id >= [form2::data memberNum] ||
		    [string match $id ""]} {
		    form2::appendIndex invalid "Co-Worker Membership number"
		    set result 0
		}
	    }
	}

	if {$required} {
	    set val [string trim [form2::data $key]]
	    if {[string equal {} $val]} {
		form2::appendIndex invalid "Need to fill in $label"
		set result 0
	    }
	}
    }

    return $result
}

################################################################
# proc calculate {fields nextPage}--
#    calculate final cost, create confirm page, 
#    put data into gpg encrypted file, keyed on formid value.
#    gpg --gen-key  to create key
#    gpg -r $formID -o InProcess_$memberNum -e --  to wrote file
#    use ::form2::saveEncrypted
# Arguments
#   
# 
# Results
#   
# 
proc calculate {fields} {
    global Config
    return 0
}

Added examples/template.www-assets.















>
>
>
>
>
>
>
1
2
3
4
5
6
7
www-forms2		forms2.tcl    
www-regform		register_form.tml  
www-register-config	register/register.cfg
www-register-procs	register/register.procs
www-subform		submit_form.tml
www-submit-config	submit/submit.cfg
www-submit-procs	submit/submit.procs

Changes to examples/template.www-cfp.




1
2
3
4
5
6
7



The program committee is asking for papers and presentation proposals
from anyone using or developing with Tcl/Tk (and extensions). Past
conferences have seen submissions covering a wide variety of topics
including:

   * Scientific and engineering applications
   * Industrial controls
>
>
>







1
2
3
4
5
6
7
8
9
10

[Online Submission Form](https://www.tcl.tk/community/tcl@c:year@/submit_form.html)

The program committee is asking for papers and presentation proposals
from anyone using or developing with Tcl/Tk (and extensions). Past
conferences have seen submissions covering a wide variety of topics
including:

   * Scientific and engineering applications
   * Industrial controls

Changes to examples/template.www-regopen.

1
2
3
4
5
6
7
8
9
10
11
12
## How to register

You may register for the conference by

* [Online form](https://www.tcl.tk/community/tcl@c:year@/regForm.html)
* [Hardcopy Mail/Fax](register_paper.html)
* At the door. 

If you register in advance, You will receive a $100 discount
over the at-the-door conference rate.

You can register at the door when you arrive at the @h:hotel@.




|







1
2
3
4
5
6
7
8
9
10
11
12
## How to register

You may register for the conference by

* [Online form](https://www.tcl.tk/community/tcl@c:year@/register_form.html)
* [Hardcopy Mail/Fax](register_paper.html)
* At the door. 

If you register in advance, You will receive a $100 discount
over the at-the-door conference rate.

You can register at the door when you arrive at the @h:hotel@.

Added examples/template.www-thanks.















>
>
>
>
>
>
>
1
2
3
4
5
6
7

Thank you for submitting a paper proposal with Tcl'@c:year@, the @c:name@.

Your proposal has been saved, and the program chair will be notified
of it (Once per day).

Feel free to contact us if there are questions

Changes to lib/conference.tcl.

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
...
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
....
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
....
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
....
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
....
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
....
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
....
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
....
3458
3459
3460
3461
3462
3463
3464

3465
3466


3467
3468
3469
3470
3471
3472
3473
....
3495
3496
3497
3498
3499
3500
3501





































3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
....
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
....
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
....
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
....
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
....
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
....
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
....
4668
4669
4670
4671
4672
4673
4674





4675
4676
4677
4678
4679
4680
4681
....
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
....
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
....
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
....
5073
5074
5075
5076
5077
5078
5079

5080
5081
5082
5083
5084
5085
5086
....
5125
5126
5127
5128
5129
5130
5131

5132
5133
5134
5135
5136
5137
5138
....
5145
5146
5147
5148
5149
5150
5151

5152
5153
5154
5155
5156
5157
5158
....
5192
5193
5194
5195
5196
5197
5198

5199
5200
5201
5202
5203
5204
5205
....
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
....
5331
5332
5333
5334
5335
5336
5337































5338
5339
5340
5341
5342
5343
5344
....
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
....
6742
6743
6744
6745
6746
6747
6748


6749
6750
6751
6752
6753
6754
6755
....
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
....
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
....
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
....
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
....
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
....
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
....
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
proc ::cm::conference::cmd_list {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set cid [config get* @current-conference {}]
    set ne  [$config @no-errors]
    
    # FUTURE: Options to sort by
    # - C.title
    # - CC.name, CC.state, CC.nation

    [table t {{} Name Start End City} {
	db do eval {
	    SELECT C.id                    AS id,
................................................................................
    set entry      [$config @event]
    set shift      [$config @shift]

    puts "Shift \"[get-timeline $entry]\"\nOf    \"[color name [get $conference]]\"\nBy    $shift days"

    db do transaction {
	set old [db do onecolumn {
	    SELECT date 
	    FROM   timeline
	    WHERE  con  = :conference
	    AND    type = :entry
	}]

	set new [clock add $old $shift days]

................................................................................

proc ::cm::conference::cmd_submission_setsummary {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set submission [$config @submission] 
    set summary    [string trim [read stdin]]

    puts -nonewline "Set summary of \"[color name [get-submission $submission]]\" in conference \"[color name [get $conference]]\" ... "
    flush stdout

    db do eval {
	UPDATE submission
................................................................................

proc ::cm::conference::cmd_submission_setabstract {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set submission [$config @submission] 
    set abstract   [string trim [read stdin]]

    puts -nonewline "Set abstract of \"[color name [get-submission $submission]]\" in conference \"[color name [get $conference]]\" ... "
    flush stdout

    db do eval {
	UPDATE submission
................................................................................

proc ::cm::conference::cmd_submission_show {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set submission [$config @submission] 

    set w [util tspace [expr {[string length Abstract]+7}] 72]

    puts [color name [get $conference]]
    [table t {Property Value} {
	db do eval {
	    SELECT id, title, abstract, summary, invited, submitdate
................................................................................

proc ::cm::conference::cmd_registration {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set newstatus  [$config @status] 

    puts -nonewline "Conference \"[color name [get $conference]]\" registration = [get-rstatus $newstatus] ... "
    flush stdout

    db do eval {
	UPDATE conference
	SET    rstatus = :newstatus
................................................................................

proc ::cm::conference::cmd_proceedings {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set newvisible [$config @status] 

    puts -nonewline "Conference \"[color name [get $conference]]\" proceedings = [get-pvisible $newvisible] ... "
    flush stdout

    db do eval {
	UPDATE conference
	SET    pvisible = :newvisible
................................................................................
    db show-location

    set link  [$config @link]
    set title [$config @title]
    set id    [current]

    if {$title eq {}} { set title $link }
    
    puts -nonewline "Add link \"[color name $link]\" to \"[color name [get $id]]\" ... "
    flush stdout

    db do transaction {
	db do eval {
	    INSERT INTO clink
	    VALUES (NULL, :id, :link, :title)
................................................................................
    flush stdout

    if {$xpschedule eq {}} {
	util user-error {No schedule defined}
    }

    set pslabel [pschedule piece $xpschedule dname]
    puts "Schedule \"[color name $pslabel]\": " 

    if {[$config @merged]} {
	set map       [ScheduleMap $conference]
	set pschedule $xpschedule

	set psd       [pschedule details $xpschedule]
	dict with psd {} ;# xid, xdname, xname, xactive{day,track,item,open}
................................................................................
    flush stdout

    if {$xpschedule eq {}} {
	util user-error {No schedule defined}
    }

    set pslabel [pschedule piece $xpschedule dname]
    puts -nonewline "Schedule \"[color name $pslabel]\": " 
    flush stdout

    set slot  [$config @label]
    set sname [$config @label string]
    set type  [$config @type]
    set value [$config @value]

    puts -nonewline "Slot \"[color name $sname]\" := " 
    flush stdout

    # TODO: Ensure uniqueness of talk/tutorial assignments.

    switch -exact $type {
	talk {
	    # value = talk-id
	    set title [get-talk-title $value]
	    puts -nonewline "Talk \"[color name $title]\" ... " 
	    flush stdout

	    schedule set_talk $slot $value
	}
	tutorial {
	    # value = (scheduled-id day half tutorial)
	    lassign $value value _ _ _
	    set title [cm::tutorial get-scheduled $value]
	    puts -nonewline "Tutorial \"[color name $title]\" ... " 
	    flush stdout

	    schedule set_tutorial $slot $value
	}
	fixed {
	    # value = string
	    puts -nonewline "\"$value\" ... " 
	    flush stdout

	    schedule set_fixed $slot $value
	}
    }

    puts [color good OK]
................................................................................
    } else {
	lappend navbar {*}[make_page Proceedings  proceedings make_proceedings_none $conference]
    }

    #lappend navbar {*}[make_page Contact           contact     make_contact]
    make_page                    Disclaimer        disclaimer  make_disclaimer
    make_page   {Registration Confirmation}        confirm     make_confirm


    make_internal_page Administrivia __dwarf make_admin $conference



    # # ## ### ##### ######## #############
    # Configuration file.
    puts "\tWebsite configuration"

    # NOTE: website.conf TODO - treat template as the semi-dict it is, prog access.
    #       Do programmatic access, instead of text manipulation.
................................................................................
    #exec >@stdout 2>@stderr <@stdin ssg {*}$args
    exec 2>@stderr <@stdin ssg {*}$args
    return
}

# # ## ### ##### ######## ############# ######################
## Internal import support commands.






































proc ::cm::conference::make_page {title fname args} {
    debug.cm/conference {}

    set generatorcmd $args
    upvar 1 dstdir dstdir conference conference
    puts \t${title}...

    set text [make_page_header $title]

    try {
	append text \n [uplevel 1 $generatorcmd]
    } on error {e o} {
	puts "\t\t[color bad ERROR:] [color bad $e]"
................................................................................
}

proc ::cm::conference::make_internal_page {title fname args} {
    debug.cm/conference {}

    set generatorcmd $args
    upvar 1 dstdir dstdir conference conference
    puts "\t${title}... ([color note Internal])"

    set text [make_internal_page_header $title]

    try {
	append text \n [uplevel 1 $generatorcmd]
    } on error {e o} {
	puts "\t\t[color bad ERROR:] [color bad $e]"
................................................................................

    lassign [cm::tutorial dayrange   $conference] daymin   daymax   daylast
    lassign [cm::tutorial trackrange $conference] trackmin trackmax tracklast

    set start [dict get [details $conference] xstart]

    # Table header
    # 
    # - | morning | afternoon | evening |
    # 
    append text |  ;# empty header cell, top left corner
    append sep  |- ;# empty header cell, top left corner
    db do eval {
	SELECT id   AS half,
	text AS dhalf
	FROM   dayhalf
	ORDER  BY id
................................................................................
		set tag      ${stag}:[dict get $tdetails xtag]

		append text | [link $title {} $tag]

		# Keep information to make assembly of the next
		# section easier, no need to query the databse again.
		dict set map $tutorial [list $title $tag $speaker $stag $desc $req]
	    }	    
	    append text |\n ;# close row of current track
	    set wday ""     ;# clear prefix following tracks
	}
    }
    append text \n\n

    append text "# Tutorial Information" \n\n
................................................................................
            if {$trackname eq {}} {incr idx ; continue }

	    #puts __|$entry|==T|$trackname|==S|$start|==E|$end|

	    set col      [dict get $cmap $trackname]
            set rowstart [dict get $rmap $start]
            set rowend   [dict get $rmap $end]
            set rspan    [expr {$rowend - $rowstart}]      

            # Mark the shadowed areas for this item.
            for {set r $rowstart} {$r < $rowend} {incr r} {
		M set cell $col $r [list -1 $rowstart]
	    }

            M set cell $col $rowstart [list 1 $rspan $idx]
................................................................................
	    # Ignore items linked specific tracks.
            if {$trackname ne {}} { incr idx ; continue }

	    #puts __|$entry|==T|$trackname|==S|$start|==E|$end|

	    set rowstart [dict get $rmap $start]
	    set rowend   [dict get $rmap $end]
	    set rspan    [expr {$rowend - $rowstart}]	   
	    set cspan    [M columns]

	    # Mark row/col shadowed area for this cell.
	    for {set r $rowstart} {$r < $rowend} {incr r} {
		M set cell 0 $r [list -1 $rowstart]
	    }
	    for {set c 0} {$c < $cspan} {incr c} { M set cell $c $rowstart -1 }
................................................................................
	set speakers [join [link-speakers [talk-speakers $talk]] {, }]
	append text [anchor T$talk] \n
	append text "\#\# Keynote &mdash; $title\n\n$speakers\n\n$abstract\n\n"
    }

    foreach {talk title abstract} [general-abstracts $conference] {
	if {[string trim $abstract] eq {}} {
	    set abstract "__Missing abstract__" 
	}
	set speakers [join [link-speakers [talk-speakers $talk]] {, }]
	append text [anchor T$talk] \n
	append text "\#\# $title\n\n$speakers\n\n$abstract\n\n"
    }
    return $text
}
................................................................................
    return
}

proc ::cm::conference::make_confirm {} {
    debug.cm/conference {}
    return [template use www-confirm]
}






proc ::cm::conference::make_disclaimer {} {
    debug.cm/conference {}
    return [template use www-disclaimer]
}

proc ::cm::conference::make_proceedings {conference} {
................................................................................

    set links [links $conference]
    if {[llength $links]} {
	lappend map @links@ [md-links $links]
	return [string map $map [template use www-proceedings.none+links]]
    } else {
	return [template use www-proceedings.none]
    }	
}

proc ::cm::conference::make_admin {conference} {
    debug.cm/conference {}
    upvar 1 dstdir dstdir

    set issues [issues [details $conference]]
................................................................................
	append text [anchor issues] \n
	append text "# Issues\n\n"
	append text [fmt-issues-web $issues]
	append text \n
    }

    set materials {}
    
    make_admin_registered  $conference text registered
    make_admin_booked      $conference text booked
    make_admin_accepted    $conference text accepted    materials
    make_admin_submissions $conference text submissions
    make_admin_campaign    $conference text campaign
    make_admin_timeline    $conference text events
    make_admin_schedule    $conference text schedule
................................................................................
    append text [anchor $tag] \n
    append text "# Materials\n\n"

    if {![llength $materials]} {
	append text "__No materials available__" \n
	return
    }
    
    append text |Talk|Attachment|\n|-|-|\n
    foreach {title links} $materials {
	foreach link $links {
	    append text | $title | $link |\n
	    set title ""
	}
    }
................................................................................
    # Table of accepted submissions, i.e. talks, plus one side page
    # per talk to hold the larger associated texts (abstract, summary, attachments).

    append text \n
    append text [anchor $tag] \n
    append text "# Accepted Talks\n\n"


    set first 1
    set n 1
    db do eval {
	SELECT S.id         AS id,
	       S.submitdate AS submitdate,
	       S.invited    AS invited,
	       S.abstract   AS abstract,
................................................................................
	    ([string trim $summary] eq {})} {
	    set issue "__Missing abstract/summary__"
	}

	append text | $n | [hdate $submitdate] | $issue | $invited | $submitters | [link $title __s${id}.html] |\n
	incr n
    }


    if {$first} {
	append text "No accepted talks" \n
    }

    append text \n
    return
................................................................................
    # Table of submissions received so far, plus one side page per to
    # hold the larger associated texts.

    append text \n
    append text [anchor $tag] \n
    append text "# Submissions\n\n"


    set first 1
    set n 1
    db do eval {
	SELECT S.id         AS id,
	       S.submitdate AS submitdate,
	       S.invited    AS invited,
	       S.abstract   AS abstract,
................................................................................
	    ([string trim $summary] eq {})} {
	    set issue "__Missing abstract/summary__"
	}

	append text | $n | [hdate $submitdate] | $issue | $invited | $submitters | [link $title __s${id}.html] |\n
	incr n
    }


    if {$first} {
	append text "No submissions yet" \n
    }

    append text \n
    return
................................................................................
	}]

	export_attachments $dstdir $talk $attachments

	set prefix Attachment
	foreach {aid title} $attachments {
	    lappend materials [link $title assets/talk$talk/$title]
	    
	    append text | $prefix | [link $title assets/talk$talk/$title] |\n
	    set prefix {}
	}
    }
    append text \n

    if {[string trim $abstract] eq {}} { set abstract "__No abstract__" }
................................................................................

	    $t add "$text" [hdate $date]
	}
    }] show return]
    append sidebar </table>
    return [insert $conference $sidebar]
}
































proc ::cm::conference::link {name page {tag {}}} {
    debug.cm/conference {}
    append link \[ $name \]( $page
    if {$tag ne {}} { append link \# $tag }
    append link )
    return $link
................................................................................
    }
    return [join $result \n]
}

proc ::cm::conference::issues {details} {
    debug.cm/conference {}
    dict with details {}
    # xconference 
    # xyear       
    # xmanagement 
    # xsubmission 
    # xcity       
    # xhotel      
    # xfacility   
    # xstart      
    # xend        
    # xalign      
    # xlength     
    # xtalklen    
    # xsesslen    
    # xrstatus
    # xpvisible

    set issues {}

    foreach {var message} {
	xcity      "Location is not known"
................................................................................
    }]
}

# # ## ### ##### ######## ############# ######################

proc ::cm::conference::Setup {} {
    debug.cm/conference {}



    ::cm::config::core::Setup
    ::cm::city::Setup
    ::cm::location::Setup
    ::cm::contact::Setup

    ::cm::tutorial::Setup
................................................................................
    if {![dbutil initialize-schema ::cm::db::do error conference {
	{
	    id		INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
	    title	TEXT	NOT NULL UNIQUE,
	    year	INTEGER NOT NULL,

	    series	INTEGER	NOT NULL REFERENCES series,	-- Overall con series
	    
	    management	INTEGER	NOT NULL REFERENCES contact,	-- Org/company/person managing the conference
	    submission	INTEGER	NOT NULL REFERENCES email,	-- Email to receive submissions.

	    city	INTEGER REFERENCES city,
	    hotel	INTEGER REFERENCES location, -- We do not immediately know where we will be
	    facility	INTEGER REFERENCES location, -- While sessions are usually at the hotel, they may not be.

................................................................................

    if {![dbutil initialize-schema ::cm::db::do error timeline_type {
	{
	    -- The possible types of action items in the conference timeline
	    -- public items are for use within mailings, the website, etc.
	    -- internal items are for the mgmt only.
	    -- the offset [in days] is used to compute the initial proposal
	    -- of a timeline for the conference. 

	    id		INTEGER NOT NULL PRIMARY KEY,
	    ispublic	INTEGER NOT NULL,
	    offset	INTEGER NOT NULL,	-- >0 => days after conference start
	    					-- <0 => days before start
	    key		TEXT    NOT NULL UNIQUE,	-- internal key for the type
	    text	TEXT    NOT NULL UNIQUE		-- human-readable
................................................................................
	} {
	    conference link
	}
    }]} {
	db setup-error link $error
    }

    
    # Shortcircuit further calls
    proc ::cm::conference::Setup {args} {}
    return
}


proc ::cm::conference::Dump {} {
................................................................................
	cm dump save \
	    conference registration [get-rstatus $rstatus]

	cm dump save \
	    conference proceedings [get-pvisible $pvisible]

	# timeline
	cm dump step 
	cm dump save \
	    conference timeline-init
	db do eval {
	    SELECT T.date AS date,
	           E.key  AS text,
	           T.done AS done
	    FROM   timeline      T,
................................................................................
	    FROM   rate
	    WHERE  conference = :id
	    AND    location   = :hotel
	} {
	    set factor 10e$decimal
	    set rate [format %.${decimal}f [expr {$rate / $factor}]]

	    cm dump step 
	    cm dump save \
		conference rate \
		-G $groupcode \
		-F [isodate $begindate] \
		-T [isodate $enddate] \
		-D [isodate $deadline] \
		-P [isodate $pdeadline] \
................................................................................

		cm dump save \
		    submission attach $title $type $mime \
		    < [cm dump write attachment$aid $value \
			   -encoding binary \
			   -translation binary]
	    }
	    
	    cm dump step
	}

	# (attached links)
	set first 1
	db do eval {
	    SELECT C.title AS title
................................................................................
		    conference schedule-edit $label $type $value
	    }
	}

	# Campaign for the conference.
	cm::campaign::Dump $id

	cm dump step 
    }
    return
}

proc ::cm::conference::TN {tid} {
    return [cm tutorial get [db do onecolumn {
	SELECT tutorial







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







|








|








|






|







 







>


>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|







 







|







 







|

|







 







|







 







|







 







|







 







|







 







>
>
>
>
>







 







|







 







|







 







|







 







>







 







>







 







>







 







>







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
|
|
|
|
|
|
|
|
|
|
|







 







>
>







 







|







 







|







 







|







 







|







 







|







 







|







 







|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
...
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
....
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
....
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
....
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
....
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
....
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
....
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
....
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
....
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
....
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
....
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
....
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
....
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
....
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
....
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
....
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
....
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
....
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
....
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
....
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
....
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
....
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
....
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
....
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
....
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
....
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
....
6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
....
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
....
6936
6937
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950
....
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
....
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
....
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
....
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
....
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
proc ::cm::conference::cmd_list {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set cid [config get* @current-conference {}]
    set ne  [$config @no-errors]

    # FUTURE: Options to sort by
    # - C.title
    # - CC.name, CC.state, CC.nation

    [table t {{} Name Start End City} {
	db do eval {
	    SELECT C.id                    AS id,
................................................................................
    set entry      [$config @event]
    set shift      [$config @shift]

    puts "Shift \"[get-timeline $entry]\"\nOf    \"[color name [get $conference]]\"\nBy    $shift days"

    db do transaction {
	set old [db do onecolumn {
	    SELECT date
	    FROM   timeline
	    WHERE  con  = :conference
	    AND    type = :entry
	}]

	set new [clock add $old $shift days]

................................................................................

proc ::cm::conference::cmd_submission_setsummary {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set submission [$config @submission]
    set summary    [string trim [read stdin]]

    puts -nonewline "Set summary of \"[color name [get-submission $submission]]\" in conference \"[color name [get $conference]]\" ... "
    flush stdout

    db do eval {
	UPDATE submission
................................................................................

proc ::cm::conference::cmd_submission_setabstract {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set submission [$config @submission]
    set abstract   [string trim [read stdin]]

    puts -nonewline "Set abstract of \"[color name [get-submission $submission]]\" in conference \"[color name [get $conference]]\" ... "
    flush stdout

    db do eval {
	UPDATE submission
................................................................................

proc ::cm::conference::cmd_submission_show {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set submission [$config @submission]

    set w [util tspace [expr {[string length Abstract]+7}] 72]

    puts [color name [get $conference]]
    [table t {Property Value} {
	db do eval {
	    SELECT id, title, abstract, summary, invited, submitdate
................................................................................

proc ::cm::conference::cmd_registration {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set newstatus  [$config @status]

    puts -nonewline "Conference \"[color name [get $conference]]\" registration = [get-rstatus $newstatus] ... "
    flush stdout

    db do eval {
	UPDATE conference
	SET    rstatus = :newstatus
................................................................................

proc ::cm::conference::cmd_proceedings {config} {
    debug.cm/conference {}
    Setup
    db show-location

    set conference [current]
    set newvisible [$config @status]

    puts -nonewline "Conference \"[color name [get $conference]]\" proceedings = [get-pvisible $newvisible] ... "
    flush stdout

    db do eval {
	UPDATE conference
	SET    pvisible = :newvisible
................................................................................
    db show-location

    set link  [$config @link]
    set title [$config @title]
    set id    [current]

    if {$title eq {}} { set title $link }

    puts -nonewline "Add link \"[color name $link]\" to \"[color name [get $id]]\" ... "
    flush stdout

    db do transaction {
	db do eval {
	    INSERT INTO clink
	    VALUES (NULL, :id, :link, :title)
................................................................................
    flush stdout

    if {$xpschedule eq {}} {
	util user-error {No schedule defined}
    }

    set pslabel [pschedule piece $xpschedule dname]
    puts "Schedule \"[color name $pslabel]\": "

    if {[$config @merged]} {
	set map       [ScheduleMap $conference]
	set pschedule $xpschedule

	set psd       [pschedule details $xpschedule]
	dict with psd {} ;# xid, xdname, xname, xactive{day,track,item,open}
................................................................................
    flush stdout

    if {$xpschedule eq {}} {
	util user-error {No schedule defined}
    }

    set pslabel [pschedule piece $xpschedule dname]
    puts -nonewline "Schedule \"[color name $pslabel]\": "
    flush stdout

    set slot  [$config @label]
    set sname [$config @label string]
    set type  [$config @type]
    set value [$config @value]

    puts -nonewline "Slot \"[color name $sname]\" := "
    flush stdout

    # TODO: Ensure uniqueness of talk/tutorial assignments.

    switch -exact $type {
	talk {
	    # value = talk-id
	    set title [get-talk-title $value]
	    puts -nonewline "Talk \"[color name $title]\" ... "
	    flush stdout

	    schedule set_talk $slot $value
	}
	tutorial {
	    # value = (scheduled-id day half tutorial)
	    lassign $value value _ _ _
	    set title [cm::tutorial get-scheduled $value]
	    puts -nonewline "Tutorial \"[color name $title]\" ... "
	    flush stdout

	    schedule set_tutorial $slot $value
	}
	fixed {
	    # value = string
	    puts -nonewline "\"$value\" ... "
	    flush stdout

	    schedule set_fixed $slot $value
	}
    }

    puts [color good OK]
................................................................................
    } else {
	lappend navbar {*}[make_page Proceedings  proceedings make_proceedings_none $conference]
    }

    #lappend navbar {*}[make_page Contact           contact     make_contact]
    make_page                    Disclaimer        disclaimer  make_disclaimer
    make_page   {Registration Confirmation}        confirm     make_confirm
    make_page   {Submission Confirmation}          thanks      make_thanks

    make_internal_page Administrivia __dwarf make_admin $conference

    make_templated_assets $conference

    # # ## ### ##### ######## #############
    # Configuration file.
    puts "\tWebsite configuration"

    # NOTE: website.conf TODO - treat template as the semi-dict it is, prog access.
    #       Do programmatic access, instead of text manipulation.
................................................................................
    #exec >@stdout 2>@stderr <@stdin ssg {*}$args
    exec 2>@stderr <@stdin ssg {*}$args
    return
}

# # ## ### ##### ######## ############# ######################
## Internal import support commands.

proc ::cm::conference::make_templated_assets {conference} {
    debug.cm/conference {}

    if {![template have www-assets]} {
	puts "\tNo configured assets ..."
	return
    }
    
    upvar 1 dstdir dstdir
    set assetmap [split [string trim [template use www-assets]] \n]
    # dict of assets: template --> site path (under /static, always)

    puts "\tPlacing configured assets ..."
    incr a
    foreach line $assetmap {
	#puts <<$line>>
	lassign [split [L $line]] template path
	incr a
	puts "\tAsset:\t[color name $template] as [color note $path] ..."
	#continue
	file mkdir [file dirname $dstdir/static/$path]
	fileutil::writeFile $dstdir/static/$path \
	    [insert $conference [template use $template]]
    }

    if {$a} return

    puts "\t[color bad {No assets}]"
    return
}

proc ::cm::conference::L {x} {
    set x [string trim $x]
    regsub -all {[ 	]+} $x { } x
    return $x
}

proc ::cm::conference::make_page {title fname args} {
    debug.cm/conference {}

    set generatorcmd $args
    upvar 1 dstdir dstdir conference conference
    puts \t[prefix?]${title}...

    set text [make_page_header $title]

    try {
	append text \n [uplevel 1 $generatorcmd]
    } on error {e o} {
	puts "\t\t[color bad ERROR:] [color bad $e]"
................................................................................
}

proc ::cm::conference::make_internal_page {title fname args} {
    debug.cm/conference {}

    set generatorcmd $args
    upvar 1 dstdir dstdir conference conference
    puts "\t[prefix?]${title}... ([color note Internal])"

    set text [make_internal_page_header $title]

    try {
	append text \n [uplevel 1 $generatorcmd]
    } on error {e o} {
	puts "\t\t[color bad ERROR:] [color bad $e]"
................................................................................

    lassign [cm::tutorial dayrange   $conference] daymin   daymax   daylast
    lassign [cm::tutorial trackrange $conference] trackmin trackmax tracklast

    set start [dict get [details $conference] xstart]

    # Table header
    #
    # - | morning | afternoon | evening |
    #
    append text |  ;# empty header cell, top left corner
    append sep  |- ;# empty header cell, top left corner
    db do eval {
	SELECT id   AS half,
	text AS dhalf
	FROM   dayhalf
	ORDER  BY id
................................................................................
		set tag      ${stag}:[dict get $tdetails xtag]

		append text | [link $title {} $tag]

		# Keep information to make assembly of the next
		# section easier, no need to query the databse again.
		dict set map $tutorial [list $title $tag $speaker $stag $desc $req]
	    }
	    append text |\n ;# close row of current track
	    set wday ""     ;# clear prefix following tracks
	}
    }
    append text \n\n

    append text "# Tutorial Information" \n\n
................................................................................
            if {$trackname eq {}} {incr idx ; continue }

	    #puts __|$entry|==T|$trackname|==S|$start|==E|$end|

	    set col      [dict get $cmap $trackname]
            set rowstart [dict get $rmap $start]
            set rowend   [dict get $rmap $end]
            set rspan    [expr {$rowend - $rowstart}]

            # Mark the shadowed areas for this item.
            for {set r $rowstart} {$r < $rowend} {incr r} {
		M set cell $col $r [list -1 $rowstart]
	    }

            M set cell $col $rowstart [list 1 $rspan $idx]
................................................................................
	    # Ignore items linked specific tracks.
            if {$trackname ne {}} { incr idx ; continue }

	    #puts __|$entry|==T|$trackname|==S|$start|==E|$end|

	    set rowstart [dict get $rmap $start]
	    set rowend   [dict get $rmap $end]
	    set rspan    [expr {$rowend - $rowstart}]
	    set cspan    [M columns]

	    # Mark row/col shadowed area for this cell.
	    for {set r $rowstart} {$r < $rowend} {incr r} {
		M set cell 0 $r [list -1 $rowstart]
	    }
	    for {set c 0} {$c < $cspan} {incr c} { M set cell $c $rowstart -1 }
................................................................................
	set speakers [join [link-speakers [talk-speakers $talk]] {, }]
	append text [anchor T$talk] \n
	append text "\#\# Keynote &mdash; $title\n\n$speakers\n\n$abstract\n\n"
    }

    foreach {talk title abstract} [general-abstracts $conference] {
	if {[string trim $abstract] eq {}} {
	    set abstract "__Missing abstract__"
	}
	set speakers [join [link-speakers [talk-speakers $talk]] {, }]
	append text [anchor T$talk] \n
	append text "\#\# $title\n\n$speakers\n\n$abstract\n\n"
    }
    return $text
}
................................................................................
    return
}

proc ::cm::conference::make_confirm {} {
    debug.cm/conference {}
    return [template use www-confirm]
}

proc ::cm::conference::make_thanks {} {
    debug.cm/conference {}
    return [template use www-thanks]
}

proc ::cm::conference::make_disclaimer {} {
    debug.cm/conference {}
    return [template use www-disclaimer]
}

proc ::cm::conference::make_proceedings {conference} {
................................................................................

    set links [links $conference]
    if {[llength $links]} {
	lappend map @links@ [md-links $links]
	return [string map $map [template use www-proceedings.none+links]]
    } else {
	return [template use www-proceedings.none]
    }
}

proc ::cm::conference::make_admin {conference} {
    debug.cm/conference {}
    upvar 1 dstdir dstdir

    set issues [issues [details $conference]]
................................................................................
	append text [anchor issues] \n
	append text "# Issues\n\n"
	append text [fmt-issues-web $issues]
	append text \n
    }

    set materials {}

    make_admin_registered  $conference text registered
    make_admin_booked      $conference text booked
    make_admin_accepted    $conference text accepted    materials
    make_admin_submissions $conference text submissions
    make_admin_campaign    $conference text campaign
    make_admin_timeline    $conference text events
    make_admin_schedule    $conference text schedule
................................................................................
    append text [anchor $tag] \n
    append text "# Materials\n\n"

    if {![llength $materials]} {
	append text "__No materials available__" \n
	return
    }

    append text |Talk|Attachment|\n|-|-|\n
    foreach {title links} $materials {
	foreach link $links {
	    append text | $title | $link |\n
	    set title ""
	}
    }
................................................................................
    # Table of accepted submissions, i.e. talks, plus one side page
    # per talk to hold the larger associated texts (abstract, summary, attachments).

    append text \n
    append text [anchor $tag] \n
    append text "# Accepted Talks\n\n"

    prefix+ "Acc:\t"
    set first 1
    set n 1
    db do eval {
	SELECT S.id         AS id,
	       S.submitdate AS submitdate,
	       S.invited    AS invited,
	       S.abstract   AS abstract,
................................................................................
	    ([string trim $summary] eq {})} {
	    set issue "__Missing abstract/summary__"
	}

	append text | $n | [hdate $submitdate] | $issue | $invited | $submitters | [link $title __s${id}.html] |\n
	incr n
    }
    prefix-

    if {$first} {
	append text "No accepted talks" \n
    }

    append text \n
    return
................................................................................
    # Table of submissions received so far, plus one side page per to
    # hold the larger associated texts.

    append text \n
    append text [anchor $tag] \n
    append text "# Submissions\n\n"

    prefix+ "Sub:\t"
    set first 1
    set n 1
    db do eval {
	SELECT S.id         AS id,
	       S.submitdate AS submitdate,
	       S.invited    AS invited,
	       S.abstract   AS abstract,
................................................................................
	    ([string trim $summary] eq {})} {
	    set issue "__Missing abstract/summary__"
	}

	append text | $n | [hdate $submitdate] | $issue | $invited | $submitters | [link $title __s${id}.html] |\n
	incr n
    }
    prefix-

    if {$first} {
	append text "No submissions yet" \n
    }

    append text \n
    return
................................................................................
	}]

	export_attachments $dstdir $talk $attachments

	set prefix Attachment
	foreach {aid title} $attachments {
	    lappend materials [link $title assets/talk$talk/$title]

	    append text | $prefix | [link $title assets/talk$talk/$title] |\n
	    set prefix {}
	}
    }
    append text \n

    if {[string trim $abstract] eq {}} { set abstract "__No abstract__" }
................................................................................

	    $t add "$text" [hdate $date]
	}
    }] show return]
    append sidebar </table>
    return [insert $conference $sidebar]
}

# Indentation control for stdout (operational logging)
proc ::cm::conference::prefix-init {} {
    debug.cm/conference {}
    variable cprefix {}
    variable sprefix {}
    return
}

proc ::cm::conference::prefix? {} {
    debug.cm/conference {}
    variable cprefix
    return $cprefix
}

proc ::cm::conference::prefix+ {prefix} {
    debug.cm/conference {}
    variable cprefix
    variable sprefix
    lappend sprefix $cprefix
    set cprefix $prefix
    return
}

proc ::cm::conference::prefix- {} {
    debug.cm/conference {}
    variable cprefix
    variable sprefix
    set sprefix [lreverse [lassign [lreverse $sprefix] cprefix]]
    return
}

proc ::cm::conference::link {name page {tag {}}} {
    debug.cm/conference {}
    append link \[ $name \]( $page
    if {$tag ne {}} { append link \# $tag }
    append link )
    return $link
................................................................................
    }
    return [join $result \n]
}

proc ::cm::conference::issues {details} {
    debug.cm/conference {}
    dict with details {}
    # xconference
    # xyear
    # xmanagement
    # xsubmission
    # xcity
    # xhotel
    # xfacility
    # xstart
    # xend
    # xalign
    # xlength
    # xtalklen
    # xsesslen
    # xrstatus
    # xpvisible

    set issues {}

    foreach {var message} {
	xcity      "Location is not known"
................................................................................
    }]
}

# # ## ### ##### ######## ############# ######################

proc ::cm::conference::Setup {} {
    debug.cm/conference {}

    prefix-init

    ::cm::config::core::Setup
    ::cm::city::Setup
    ::cm::location::Setup
    ::cm::contact::Setup

    ::cm::tutorial::Setup
................................................................................
    if {![dbutil initialize-schema ::cm::db::do error conference {
	{
	    id		INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
	    title	TEXT	NOT NULL UNIQUE,
	    year	INTEGER NOT NULL,

	    series	INTEGER	NOT NULL REFERENCES series,	-- Overall con series

	    management	INTEGER	NOT NULL REFERENCES contact,	-- Org/company/person managing the conference
	    submission	INTEGER	NOT NULL REFERENCES email,	-- Email to receive submissions.

	    city	INTEGER REFERENCES city,
	    hotel	INTEGER REFERENCES location, -- We do not immediately know where we will be
	    facility	INTEGER REFERENCES location, -- While sessions are usually at the hotel, they may not be.

................................................................................

    if {![dbutil initialize-schema ::cm::db::do error timeline_type {
	{
	    -- The possible types of action items in the conference timeline
	    -- public items are for use within mailings, the website, etc.
	    -- internal items are for the mgmt only.
	    -- the offset [in days] is used to compute the initial proposal
	    -- of a timeline for the conference.

	    id		INTEGER NOT NULL PRIMARY KEY,
	    ispublic	INTEGER NOT NULL,
	    offset	INTEGER NOT NULL,	-- >0 => days after conference start
	    					-- <0 => days before start
	    key		TEXT    NOT NULL UNIQUE,	-- internal key for the type
	    text	TEXT    NOT NULL UNIQUE		-- human-readable
................................................................................
	} {
	    conference link
	}
    }]} {
	db setup-error link $error
    }


    # Shortcircuit further calls
    proc ::cm::conference::Setup {args} {}
    return
}


proc ::cm::conference::Dump {} {
................................................................................
	cm dump save \
	    conference registration [get-rstatus $rstatus]

	cm dump save \
	    conference proceedings [get-pvisible $pvisible]

	# timeline
	cm dump step
	cm dump save \
	    conference timeline-init
	db do eval {
	    SELECT T.date AS date,
	           E.key  AS text,
	           T.done AS done
	    FROM   timeline      T,
................................................................................
	    FROM   rate
	    WHERE  conference = :id
	    AND    location   = :hotel
	} {
	    set factor 10e$decimal
	    set rate [format %.${decimal}f [expr {$rate / $factor}]]

	    cm dump step
	    cm dump save \
		conference rate \
		-G $groupcode \
		-F [isodate $begindate] \
		-T [isodate $enddate] \
		-D [isodate $deadline] \
		-P [isodate $pdeadline] \
................................................................................

		cm dump save \
		    submission attach $title $type $mime \
		    < [cm dump write attachment$aid $value \
			   -encoding binary \
			   -translation binary]
	    }

	    cm dump step
	}

	# (attached links)
	set first 1
	db do eval {
	    SELECT C.title AS title
................................................................................
		    conference schedule-edit $label $type $value
	    }
	}

	# Campaign for the conference.
	cm::campaign::Dump $id

	cm dump step
    }
    return
}

proc ::cm::conference::TN {tid} {
    return [cm tutorial get [db do onecolumn {
	SELECT tutorial

Changes to lib/template.tcl.

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
213
214
215
216
217
218
219






220
221
222
223
224
225
226
namespace eval ::cm {
    namespace export template
    namespace ensemble create
}
namespace eval ::cm::template {
    namespace export \
	cmd_create cmd_remove cmd_set cmd_list cmd_show \
	get details known select find find-by-name use
    namespace ensemble create

    namespace import ::cmdr::color
    namespace import ::cmdr::ask
    namespace import ::cm::db
    namespace import ::cm::util

................................................................................
	util user-error "Template \"$name\" not found"
	#$p undefined!
    }

    # Map to id
    return [dict get $templates $name]
}







proc ::cm::template::find {name p} {
    debug.cm/template {}
    return [find-by-name $name]
}

proc ::cm::template::select {p} {







|







 







>
>
>
>
>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
namespace eval ::cm {
    namespace export template
    namespace ensemble create
}
namespace eval ::cm::template {
    namespace export \
	cmd_create cmd_remove cmd_set cmd_list cmd_show \
	get details known select find find-by-name use have
    namespace ensemble create

    namespace import ::cmdr::color
    namespace import ::cmdr::ask
    namespace import ::cm::db
    namespace import ::cm::util

................................................................................
	util user-error "Template \"$name\" not found"
	#$p undefined!
    }

    # Map to id
    return [dict get $templates $name]
}

proc ::cm::template::have {name} {
    debug.cm/template {}
    # dict: label -> id
    return [dict exists [known] $name]
}

proc ::cm::template::find {name p} {
    debug.cm/template {}
    return [find-by-name $name]
}

proc ::cm::template::select {p} {