EKB This gives an example of what I think is a particularly Tcl-ish use of Model / View / Controller. I use this frequently in my own work and it certainly makes it easier to incrementally develop an application.
The architecture is pretty basic, something like this:
+--------------------+ | | | Core Program | | | +---------+----------+ | | / \ / \ / \ Mini- GUI(s) language/ CLI
The core program has no user interface capability. It just has programmatic hooks. In MVC, it is the model. Usually I use Snit for this.
Because this is Tcl, building the model, as a program with hooks, basically results in a mini-language. It is easy to implement a command-line program that gives access to the model. The CLI itself is the controller and the system console is the view (at least, I think this is a correct interpretation of MVC).
Although I often don't have to go to the next step, the MVC pattern makes it very easy to access the model via a Tk GUI, which would involve a further controller (a layer between the GUI code and the model) and the view (the GUI itself).
This is an example from my own work to show the approach. I'm just using it to illustrate the approach, but the application itself might be interesting to people who are into hydrology, agricultural economics, or (maybe) agronomy.
First, here's the command-line controller. It is very simple and basic, and I pretty much recycle this code whenever I make this use of the MVC pattern. It just calls the core program, which is inside the two files "crop.tcl" and "yield.tcl":
package require snit source "crop.tcl" source "yield.tcl" if {$argc != 1} { puts "Usage:" puts " yield inputfile.yld" puts "" puts "Your file is \"inputfile.yld\". It does not have" puts "to have a .yld extension, but must have all of" puts "the elements required for a yield input file." exit } namespace eval yield { source [lindex $argv 0] } # Run it! yield::run
The CLI sources an input script, which basically makes use of the model as a mini-language. (There is also a data file, which I include for completeness at the end.) It should properly use safe interps for sourcing, but I haven't done that here.
# Define all crops, using FAO data # Setting maxyield = 1.0 gives a relative yield compared to max # Root depth is in meters crop tomato -days {30 40 40 25} -kc {0.6 1.15 0.8} \ -ky {0.4 1.1 0.8 0.4} -maxyield 1.0 -minlai 0.5 \ -maxlai 4.0 -rootdepth {0.25 1.0} crop soybean1 -days {15 15 40 15} -kc {0.5 1.15 0.5} \ -ky {0.2 0.8 0.0 1.0} -maxyield 1.0 -minlai 0.5 \ -maxlai 4.0 -rootdepth {0.3 1.0} crop soybean2 -days {15 15 40 15} -kc {0.5 1.15 0.5} \ -ky {0.2 0.8 0.0 1.0} -maxyield 1.0 -minlai 0.5 \ -maxlai 4.0 -rootdepth {0.3 1.0} # Say when each crop will start (first show above ground), relative to # the start of the data file start tomato 320 start soybean1 0 start soybean2 10+tomato ;# This means "10 days after the tomato growing period" # Initialize values for the land # conductivity: Vertical hydraulic conductivity # maxsoilcap: Maximum soil water capacity # satfrac: Initial soil moisture, as fraction of max capacity # fallowLAI: The leaf area index on fallow land # fallowKc: The crop coefficient for fallow land # plantavailwater: PAW coefficient, the ratio of water depth to wetted soil depth # For runoff, either: # soilmoistureshape: The shape parameter for the soil moisture # storage curve of the ARNO rainfall-runoff model # or # runoffresistance: The WEAP runoff resistance factor # For runoffresistance, set to "LAI" and not a number to use # the LAI as the runoff resistance factor land -conductivity 6.0 -maxsoilcap 200.0 \ -satfrac 0.5 -fallowLAI 0.1 -fallowKc 0.1 \ -runoffresistance 3 -plantavailwater 0.15 # Irrigation parameters # efficiency: Efficiency of delivering water for T rather than E to the crop # lowerthreshold: When soil moisture gets below this threshold, start irrigating # upperthreshold: when soil moisture is above this threshold, stop irrigating irrigation -efficiency 0.80 -lowerthreshold 0.5 \ -upperthreshold 0.8 # Get data from file. Data are in the order: # irrigation, ET0, Precip # Specify order here using I E P getdata "sampledata.dat" I E P
The model itself consists of two files, "yield.tcl" and "crop.tcl".
namespace eval yield {} { namespace export start land irrigation getdata variable land set land(Ks) 6.0 set land(S) 1000.0 set land(fLAI) 0.1 set land(fKc) 0.1 set land(z0) 0.5 set land(ARNOb) 0.5 set land(WEAPro) LAI set land(PAW) 0.15 set land(runoff) WEAP variable irr set irr(eff) 0.0 set irr(lthresh) 0.5 set irr(uthresh) 0.9 set irr(Novak) 0.463 ;# Novak parameter for LAI dependence of T vs E variable inputs variable start variable crops {} } proc yield::land {args} { variable land foreach {arg val} $args { switch -- $arg { -conductivity {set land(Ks) $val} -maxsoilcap {set land(S) $val} -fallowLAI {set land(fLAI) $val} -fallowKc {set land(fKc) $val} -satfrac {set land(z0) $val} -soilmoistureshape { set land(ARNOb) $val set land(runoff) ARNO } -runoffresistance { set land(WEAPro) $val set land(runoff) WEAP } -plantavailwater {set land(PAW) $val} default { error "Values can be one of: [join [lsort [array names $land]] ,]" } } } } proc yield::irrigation {args} { variable irr foreach {arg val} $args { switch -- $arg { -efficiency {set irr(eff) $val} -lowerthreshold {set irr(lthresh) $val} -upperthreshold {set irr(uthresh) $val} -novak {set irr(Novak) $val} default { error "Values can be one of: [join [lsort [array names $irr]] ,]" } } } } proc yield::outfile {s} { variable file set file(output) $s return $s } # The args give the order in which the variables are entered # The names *must* be I, E, or P (for Irrigation, ET0, and Precip) # The first line of the file is ignored if it has text # E.g.: getdata myfile I E P proc yield::getdata {infile args} { variable inputs if [catch {open $infile r} fhndl] { error "Could not open file $file(input): $fhndl" return } # Ignore first line if it has text; otherwise, read it gets $fhndl line if {![regexp -- {[A-Za-z]} $line]} { # Rewind to first line seek $fhndl 0 } set inputs(I) {} set inputs(E) {} set inputs(P) {} while {[gets $fhndl line] >= 0} { foreach item $line lname $args { lappend inputs($lname) $item } } close $fhndl } proc yield::start {crop d} { variable start variable crops regexp {(\d+)(\+(\w+))?} $d -> day + refcrop if {$refcrop ne ""} { set day [expr {$start($refcrop) + [::$refcrop LGP] + $day}] } set start($crop) $day lappend crops $crop } proc yield::run {{outfile ""}} { variable crops variable run variable inputs variable land variable irr variable start if {$outfile eq ""} { set fhndl stdout } else { if [catch {open $outfile w} fhndl] { error "Cannot open file $outfile: $fhndl" } } set croplist [join $crops " Yield\t"] puts $fhndl "Day\tIrrigation Depth\t$croplist Yield\tRoot Zone Storage (frac.)" set i 0 set z $land(z0) set irrigating false foreach ET0 $inputs(E) P $inputs(P) Iavail $inputs(I) { # Note: This assumes cropping periods do not overlap set Kc $land(fKc) set LAI $land(fLAI) set fallow true foreach crop [array names start] { set inGrowingPeriod($crop) [expr {$i > $start($crop) && $i < $start($crop) + [::$crop LGP]}] if $inGrowingPeriod($crop) { set Kc [::$crop Kc] set LAI [::$crop LAI] set rootdepth [::$crop rootdepth] set fallow false } } if {$land(runoff) eq "ARNO"} { set PHI [expr {$P - $ET0 * $Kc}] if {$PHI <= 0} { set runoff 0 } else { set temp1 [expr {1.0 * $land(S)/($land(ARNOb) + 1.0)}] # Note that z should not be greater than 1: but catch anyway set temp2 [expr {$z >= 1 ? 0.0 : pow(1.0 - $z, $land(ARNOb) + 1.0)}] if {$PHI < $land(S) * (1.0 - $z)} { set runoff [expr {$PHI - $temp1 * ($temp2 - pow(1.0 - $z - 1.0 * $PHI/$land(S), $land(ARNOb) + 1.0))}] } else { set runoff [expr {$PHI - $temp1 * $temp2}] } } } else { # If not ARNO, using WEAP (set by default) if {$land(WEAPro) eq "LAI"} { set k $LAI } else { set k $land(WEAPro) } set runoff [expr {($P + $Iavail) * ($z >= 1 ? 1.0 : pow(max(0, $z), $k))}] } set ET [expr {$ET0 * $Kc * (5.0 * $z - 2.0 * $z * $z)/3.0}] set ETpart [expr {exp(-$irr(Novak) * $LAI)}] set irred 1 if {1.0 - (1.0 - $irr(eff)) * $ETpart > 1.0e-7} { set irrred [expr {(1.0 - $ETpart) / (1.0 - (1.0 - $irr(eff)) * $ETpart)}] } if $fallow { set irrigating false } else { # Convert to: water depth, millimeters set rdwater [expr {1000 * $rootdepth * $land(PAW)}] if {$z * $land(S) < $irr(lthresh) * $rdwater} { set irrigating true } else { if {$z * $land(S) > $irr(uthresh) * $rdwater} { set irrigating false } } } if {$irrigating} { set Ineed [expr {$irr(uthresh) * $rdwater - $z *$land(S)}] set Iwithd [expr {$irred * $Ineed > $Iavail ? $Iavail : $irred * $Ineed}] if {$Iavail < 1.0e-7} { set I 0.0 } else { set I [expr {$Ineed * (1.0 * $Iwithd/$Iavail)}] } } else { set I 0.0 } set zprov [expr {$z + ($P + $I - $runoff - \ $ET - $land(Ks) * $z * $z) / \ (1.0 * $land(S))}] # Keep in bounds for extreme values set z [expr {min(1.0, max($zprov, 0.0))}] foreach crop [array names start] { if $inGrowingPeriod($crop) { ::$crop grow $ET $ET0 } } incr i set outline [format "%d\t\%4.4f" $i [expr {$irred * $I}]] foreach crop $crops { set outline [format "%s\t%5.4f" $outline [::$crop yield]] } set outline [format "%s\t%0.4f" $outline $z] puts $fhndl $outline } # Close the file or, if stdout, flush close $fhndl }
snit::type crop { option -days {1 1 1 1} option -kc {1 1 1} option -ky {1 1 1 1} option -rootdepth {0.3 1} ;# In meters option -minlai 1 option -maxlai 5 option -maxyield 1 variable potyield variable currday variable currstage variable cumET variable cumPET constructor {args} { $self configurelist $args $self reset } typevariable stages [list \ {Initial} \ {Crop Development} \ {Mid-Season} \ {Late} \ ] method yield {} { variable potyield return $potyield } method day {} { variable currday return $currday } method reset {} { variable potyield variable currday variable currstage variable cumET variable cumPET set potyield [$self cget -maxyield] set currday 0 set currstage 1 set cumET 0 set cumPET 0 } # This is the main method: # increase day by 1 # set new internal variables if needed method grow {ET ET0} { variable potyield variable currday variable currstage variable cumET variable cumPET set cumET [expr {$cumET + $ET}] set cumPET [expr {$cumPET + [$self Kc $currday] * $ET0}] incr currday if {[$self stage $currday] > $currstage} { set ymax [$self cget -maxyield] set Ky [lindex [$self cget -ky] [expr {$currstage - 1}]] set tempyield [expr {$ymax * (1.0 - $Ky * (1.0 - 1.0 * $cumET/$cumPET))}] set potyield [expr {$potyield < $tempyield ? $potyield : $tempyield}] incr currstage # Reset variables set cumET 0 set cumPET 0 } } # Get the stage (1-4) for the day (from start of growing season) method stage {{d -1}} { variable currday if {$d == -1} { set d $currday } set stage 0 set totdays 0 foreach stagedays [$self cget -days] { incr stage incr totdays $stagedays if {$totdays > $d} { break } } return $stage } method LGP {} { set LGP 0 foreach days [$self cget -days] { incr LGP $days } return $LGP } method stagename {{d -1}} { variable currday if {$d == -1} { set d $currday } set stage [$self stage $d] incr stage -1 return [lindex $stages $stage] } method startofstage {n} { set stagedays [$self cget -days] set startofstage 0 for {set i 0} {$i < $n - 1} {incr i} { incr startofstage [lindex $stagedays $i] } return $startofstage } method Ky {{d -1}} { variable currday if {$d == -1} { set d $currday } set stage [$self stage $d] incr stage -1 return [lindex [$self cget -ky] $stage] } method rootdepth {{d -1}} { variable currday if {$d == -1} { set d $currday } set rd0 [lindex [$self cget -rootdepth] 0] set rd1 [lindex [$self cget -rootdepth] 1] set stage [$self stage $d] set stagedays [$self cget -days] set s12days [expr {[lindex $stagedays 0] + [lindex $stagedays 1]}] switch $stage { 1 - 2 { return [expr {$rd0 + 1.0 * ($rd1 - $rd0) * $d/$s12days}] } 3 - 4 { return $rd1 } default { error "Invalid stage: $stage" } } } method LAI {{d -1}} { variable potyield variable currday if {$d == -1} { set d $currday } set stage [$self stage $d] set minlai [$self cget -minlai] set maxlai [$self cget -maxlai] set maxyield [$self cget -maxyield] # Adjust maxlai set maxlai [expr {$minlai + ($maxlai - $minlai) * (1.0 * $potyield)/$maxyield}] # Are we already past the end of the growing period? Back to background level if {$d > [$self LGP]} { return $minlai } switch $stage { 1 { return $minlai } 2 { set delta [expr {$d - [$self startofstage $stage]}] set tot [lindex [$self cget -days] [expr {$stage - 1}]] return [expr {$minlai + (1.0 * $delta/$tot) * ($maxlai - $minlai)}] } 3 { return $maxlai } 4 { set delta [expr {$d - [$self startofstage $stage]}] set tot [lindex [$self cget -days] [expr {$stage - 1}]] return [expr {$maxlai + (1.0 * $delta/$tot) * ($minlai - $maxlai)}] } default { error "Invalid stage: $stage" } } } method Kc {{d -1}} { variable potyield variable currday if {$d == -1} { set d $currday } set maxyield [$self cget -maxyield] set f [expr {1.0 - [$self Ky $d] * (1.0 - 1.0 * $potyield/$maxyield)}] set stage [$self stage $d] for {set i 0} {$i < 3} {incr i} { set Kc$i [expr {$f * [lindex [$self cget -kc] $i]}] } # Are we already past the end of the growing period? if {$d > [$self LGP]} { 0 } switch $stage { 1 { return $Kc0 } 2 { set delta [expr {$d - [$self startofstage $stage]}] set tot [lindex [$self cget -days] [expr {$stage - 1}]] return [expr {$Kc0 + (1.0 * $delta/$tot) * ($Kc1 - $Kc0)}] } 3 { return $Kc1 } 4 { set delta [expr {$d - [$self startofstage $stage]}] set tot [lindex [$self cget -days] [expr {$stage - 1}]] return [expr {$Kc2 + (1.0 * $delta/$tot) * ($Kc2 - $Kc1)}] } default { error "Invalid stage: $stage" } } } }
As promised, here is the data file for completeness.
Max irr E0 Eff Precip 0 5.761037898 14.5 0 5.771466728 42 0 5.531450084 14 0 5.87035102 0 0 5.875572161 12 0 5.552812377 0.5 0 5.583264969 14.5 0 5.989502567 3.5 0 6.207994445 0 0 6.246897367 0 0 5.500260589 7 0 5.63167217 5.5 0 5.772573608 0.5 0 5.446567484 23.5 0 5.721110544 3 0 6.069274763 0 0 6.135673459 0 1.967215737 6.328683513 0 2.08882289 6.497996403 0 1.967215737 6.735380691 0 0 6.096134278 16 0 6.056112197 1 0 6.432478207 0 2.05033654 6.4569194 0 2.049087858 6.519006469 0 2.048034683 6.270449246 0 0 5.656067718 22 0 5.712704201 1 0 5.652089173 15 0 5.797380052 8 0 5.965051451 1 0 6.099939409 0 0 6.353557745 0 0 6.377253604 0 1.967224626 6.290576763 0 2.050596818 6.376762687 0 2.049290424 6.508631494 0 0 5.947126415 39 0 5.872732487 0 0 5.962959618 6.5 0 6.187439414 0 0 6.296725436 0 0 6.370383616 0.5 0 5.988837944 4.5 0 6.396236881 0 0 6.750263009 0 1.967224276 6.704741097 0 2.050442118 6.689124078 0 2.08369624 5.923003526 1 0 5.773998766 25 0 5.558454509 0.5 0 5.460817903 22.5 0 5.266971861 13.5 0 5.423064318 0 0 5.488208851 0.5 0 5.425444442 10.5 0 5.218218546 2.5 0 5.467129271 0.5 0 5.388585802 16 0 5.082228914 52 0 5.201373007 15 0 5.099514774 1 0 5.235563988 12.5 0 5.04075724 2 0 5.303735895 0.5 0 4.939714548 10 0 5.412009188 0 0 5.734534539 0 0 5.742756721 0 0 5.225588632 4.5 0 5.35690206 1.5 0 5.305882921 9.5 0 4.982072474 6.5 0 4.973786861 0.5 0 4.930213788 6.5 0 4.943025032 25 0 5.051629305 1.5 0 5.222545573 0 0 5.220650262 0 0 5.226944571 0 0 5.170762196 0.5 0 5.365088979 0 0 5.416879271 0 0 5.302346993 0 0 5.574893489 0 0 5.535950484 0 0 5.428155689 0 0 5.433485117 0 1.967216438 5.36429517 0 0 5.450908178 0 1.967216269 5.283361298 0 0 5.047356206 0 1.967216145 4.989441552 0 0 5.095622698 0 1.967216047 5.298409244 0 0 5.159767772 0 1.872215268 5.11727978 0 2.140544379 5.180350038 0 1.967215917 5.130020013 0 2.140544379 4.987379983 0 1.967215875 4.900668985 0 2.087948193 4.914507427 0 1.967215842 4.974824488 0 2.08804661 4.697326493 0 1.967215818 4.840112871 0 0 4.662405778 12.5 0 4.263837264 0 0 4.209747233 0 0 4.482103779 0 0 4.52360566 0 2.084491234 4.628711713 0 2.083135317 4.560905699 0 1.967229737 4.456066638 0 2.085575647 4.359319564 0 2.084144824 4.397296923 0 1.967238629 4.532112129 0 2.08601227 4.69707729 0 2.084546454 4.411296654 0 2.08324803 4.235163966 0 1.967246104 4.390911161 0 2.084523076 4.453290197 0 2.08326151 4.327160787 0 2.082150272 4.20465183 0 2.08112643 4.315361958 0 2.080199677 4.333249231 0 2.079400404 4.089525809 0 2.078680594 4.047971444 0 2.078021348 4.07997839 0 2.077699563 3.86510014 1 2.077150273 3.831435419 0 2.076654489 3.768095064 0 2.076148738 4.252473249 0 2.075675588 4.403617052 0 2.044680453 4.085049374 0 2.044416928 3.502140402 0 2.044175719 3.461823289 0 2.0439459 3.542884318 0 2.04370582 3.978621899 0 2.043482422 4.020591927 0 2.043291617 3.757776235 0 2.043125218 3.565630904 0 2.042937691 4.220159438 0 2.042743837 4.691299149 0 2.042584539 4.337282345 0 2.042449584 4.113028816 0 2.04233952 3.771770695 0 2.042243497 3.608232731 0 2.04215096 3.660230035 0 2.042063692 3.652562004 0 2.041977795 3.741866545 0 2.04191219 3.305725349 0 2.041984703 3.710441579 0 2.041905776 3.695907009 0 2.041828895 3.721920632 0 2.041754244 3.731075945 0 2.041667814 4.164737669 0 2.04157619 4.460395398 0 2.04150221 4.066273205 0 2.041447266 3.551436729 0 2.041397711 3.381920242 0 2.041347836 3.340431581 0 2.04129319 3.423620657 0 2.071206748 3.575119272 0 1.895342151 3.765872092 0 2.074278792 3.916573178 0 2.073968281 3.910460675 0 2.042322114 3.621195795 0 1.892160873 3.523693919 0 2.076787505 3.646818313 0 2.076296574 3.57797656 0 1.967254736 3.749491357 0 2.046574523 3.762332136 0 2.046053072 3.888901286 0 1.967258272 3.910590921 0 2.048172383 3.383440535 0 2.047523167 3.759074532 0 1.967260765 3.999615977 0 2.049484534 3.866941301 0 1.967258879 3.978901152 0 2.051170731 4.46567334 0 2.050159967 4.357597148 0 1.967259348 4.017611608 0 2.088846936 3.595474003 0 1.967250696 3.53165456 0 2.088849902 4.07136338 0 1.967243072 4.043924899 0 0 3.625693391 0 2.088849906 3.475563413 0 1.967235456 3.446673901 0 0 3.624508643 0 2.05090978 3.900319863 0 1.967237608 3.752010092 0 2.088851735 3.679982694 0 0 3.61309884 0 2.049443869 3.471040842 0 1.967238172 3.242617014 0 2.088856577 3.428101025 0 1.967233686 3.937244729 0 0 3.97107732 0 2.051028086 3.80397881 0 1.967236314 4.044293197 0 2.08885649 4.23703381 0 1.967231692 4.341256643 0 2.088858202 4.594168353 0 0 4.29826782 0 1.967226759 4.045715151 0 2.088856897 3.884975906 0 1.967224478 4.019431081 0 2.088859203 4.112569976 0 1.967222582 4.126078683 0 0 4.402392128 0 2.088857173 4.819610386 0 1.967220413 4.429965097 0 2.088859262 4.113506398 0 1.967219427 4.204965467 0 0 4.614478214 0 2.050651997 4.287155602 0 1.967226603 3.88984427 0 2.088858227 4.652601423 0 1.967224072 4.843851998 0 2.088859423 5.201680832 0 1.967222075 4.645744418 0 2.088860883 4.858989604 0 1.967220615 4.277012991 0 0 5.028196713 0 2.051255304 5.452929878 0 2.050355001 3.624369476 0 1.967234802 3.784565331 0 2.088863909 3.982693213 0 0 4.129533803 0 1.967229088 4.622384796 0 2.088861548 4.678186374 0 1.967226204 4.171670962 0 2.088863374 4.753353209 0 1.967223727 5.201336433 0 0 5.088513724 0 2.05076702 4.796621202 0 2.049740881 4.644862089 0 1.967236193 4.946330327 0 2.088863116 5.568887605 0 1.967231021 5.931707497 0 2.051272386 5.782592977 0 2.049900126 6.364131334 0 1.967240454 5.819233514 0 2.051379937 6.312836982 0 2.05006761 6.089480955 0 2.048897358 6.051836822 0 2.081283412 5.602790721 0 1.876658596 5.52905239 0 2.083584045 6.105065902 0 2.081977085 6.171969108 0 1.96725664 6.863116125 2.5 0 5.367548594 2.5 2.084975452 6.28879517 0.5 2.083218817 6.144300523 0 2.081706776 5.867549397 0 2.080273375 6.300828636 0 1.967262178 5.295769076 3.5 0 5.232643319 3.5 0 4.812689479 4 1.967251051 5.812995447 0 2.140544379 5.536364375 0 2.08376636 5.736854671 0 0 6.456665592 5 0 4.518588784 17.5 0 4.448568503 3 0 4.788055766 0 0 4.842088739 0 0 5.537950067 0 1.96723528 6.411392135 0 2.085099094 6.522784035 0 2.083098862 7.378587153 0 2.081487358 6.689264443 0 2.079611369 6.878151386 0 2.078964057 5.812406559 4.5 1.96724716 5.998611373 12.5 1.967242775 4.778379619 0 2.08403183 5.31193109 0 2.0798017 5.919695963 0 2.075729226 5.99688475 0 2.039721564 6.090257284 0 2.036205279 6.273597972 0 2.032884746 6.084728322 0.5 2.046870282 6.584234023 0 2.040849479 6.597532697 0 2.03526775 6.781567801 0 2.030081658 6.647963882 0 2.025221041 6.626830294 0 2.020644825 6.412361243 0 2.016249924 7.375852817 0 2.012091428 6.609955855 0 2.009402749 6.598854788 6.5 2.044491515 5.507184662 1 2.044885301 5.809974285 3.5 0 5.722913119 44 0 5.852866984 0 0 5.822596978 0 0 5.368355146 10 0 4.879991918 76 0 4.349349514 0 0 4.809179261 0 0 5.339547525 0 0 5.447512632 0 0 4.893626506 0 0 5.497121338 0 0 5.944004338 0 0 6.394222129 0 0 6.345615812 0 0 5.695494097 8.5 0 5.677040574 47.5 0 5.097513868 5 0 5.5729635 0 0 5.600292532 25 0 5.808134146 40 0 5.163434792 0.5 0 5.258498253 0.5 0 5.334000815 8 0 5.892128512 0 0 6.232182257 0 0 5.86950428 0 0 5.735016857 26.5 0 5.617433318 0 0 5.302491025 29 0 5.567993395 1.5 0 5.490724079 11 0 5.699463871 0.5 0 6.224950298 4 0 5.660958991 1.5 0 5.81612703 0 0 5.861291995 41.5 0 5.898253609 12.5 0 5.886459979 7 0 5.618605592 0.5 0 5.62323324 0 0 5.715852746 0 0 5.654001217 0 0 5.539656707 5.5 0 5.142361374 13 0 5.111418988 25.5 0 5.162186183 4.5 0 5.529636164 6 0 5.840125097 26 0 5.841853674 0 0 6.253020517 0 0 6.279650253 0 0 6.072899228 0 0 5.849350759 0.5 0 5.861996369 31.5 0 5.88638236 1.5 0 5.570375844 20.5 0 5.622675085 1 0 6.050322752 0 0 5.929646949 2.5 0 6.101142315 0 0 6.12662214 0 0 5.710179246 2.5 0 5.626265253 63.5 0 4.776274346 69.5 0 4.921751245 3 0 5.452368184 11.5 0 6.008460641 0.5 0 5.884066072 21.5 0 5.733126474 13.5 0 5.563072781 6 0 5.644989648 16 0 5.761037898 14.5 0 5.771466728 42 0 5.531450084 14 0 5.87035102 0 0 5.875572161 12 0 5.552812377 0.5 0 5.583264969 14.5 0 5.989502567 3.5 0 6.207994445 0 0 6.246897367 0 0 5.500260589 7 0 5.63167217 5.5 0 5.772573608 0.5 0 5.446567484 23.5 0 5.721110544 3 0 6.069274763 0 0 6.135673459 0 1.967215737 6.328683513 0 2.08882289 6.497996403 0 1.967215737 6.735380691 0 0 6.096134278 16 0 6.056112197 1 0 6.432478207 0 2.05033654 6.4569194 0 2.049087858 6.519006469 0 2.048034683 6.270449246 0 0 5.656067718 22 0 5.712704201 1 0 5.652089173 15 0 5.797380052 8 0 5.965051451 1 0 6.099939409 0 0 6.353557745 0 0 6.377253604 0 1.967224626 6.290576763 0 2.050596818 6.376762687 0 2.049290424 6.508631494 0 0 5.947126415 39 0 5.872732487 0 0 5.962959618 6.5 0 6.187439414 0 0 6.296725436 0 0 6.370383616 0.5 0 5.988837944 4.5 0 6.396236881 0 0 6.750263009 0 1.967224276 6.704741097 0 2.050442118 6.689124078 0 2.08369624 5.923003526 1 0 5.773998766 25 0 5.558454509 0.5 0 5.460817903 22.5 0 5.266971861 13.5 0 5.423064318 0 0 5.488208851 0.5 0 5.425444442 10.5 0 5.218218546 2.5 0 5.467129271 0.5 0 5.388585802 16 0 5.082228914 52 0 5.201373007 15 0 5.099514774 1 0 5.235563988 12.5 0 5.04075724 2 0 5.303735895 0.5 0 4.939714548 10 0 5.412009188 0 0 5.734534539 0 0 5.742756721 0 0 5.225588632 4.5 0 5.35690206 1.5 0 5.305882921 9.5 0 4.982072474 6.5 0 4.973786861 0.5 0 4.930213788 6.5 0 4.943025032 25 0 5.051629305 1.5 0 5.222545573 0 0 5.220650262 0 0 5.226944571 0 0 5.170762196 0.5 0 5.365088979 0 0 5.416879271 0 0 5.302346993 0 0 5.574893489 0 0 5.535950484 0 0 5.428155689 0 0 5.433485117 0 1.967216438 5.36429517 0 0 5.450908178 0 1.967216269 5.283361298 0 0 5.047356206 0 1.967216145 4.989441552 0 0 5.095622698 0 1.967216047 5.298409244 0 0 5.159767772 0 1.872215268 5.11727978 0 2.140544379 5.180350038 0 1.967215917 5.130020013 0 2.140544379 4.987379983 0 1.967215875 4.900668985 0 2.087948193 4.914507427 0 1.967215842 4.974824488 0 2.08804661 4.697326493 0 1.967215818 4.840112871 0 0 4.662405778 12.5 0 4.263837264 0 0 4.209747233 0 0 4.482103779 0 0 4.52360566 0 2.084491234 4.628711713 0 2.083135317 4.560905699 0 1.967229737 4.456066638 0 2.085575647 4.359319564 0 2.084144824 4.397296923 0 1.967238629 4.532112129 0 2.08601227 4.69707729 0 2.084546454 4.411296654 0 2.08324803 4.235163966 0 1.967246104 4.390911161 0 2.084523076 4.453290197 0 2.08326151 4.327160787 0 2.082150272 4.20465183 0 2.08112643 4.315361958 0 2.080199677 4.333249231 0 2.079400404 4.089525809 0 2.078680594 4.047971444 0 2.078021348 4.07997839 0 2.077699563 3.86510014 1 2.077150273 3.831435419 0 2.076654489 3.768095064 0 2.076148738 4.252473249 0 2.075675588 4.403617052 0 2.044680453 4.085049374 0 2.044416928 3.502140402 0 2.044175719 3.461823289 0 2.0439459 3.542884318 0 2.04370582 3.978621899 0 2.043482422 4.020591927 0 2.043291617 3.757776235 0 2.043125218 3.565630904 0 2.042937691 4.220159438 0 2.042743837 4.691299149 0 2.042584539 4.337282345 0 2.042449584 4.113028816 0 2.04233952 3.771770695 0 2.042243497 3.608232731 0 2.04215096 3.660230035 0 2.042063692 3.652562004 0 2.041977795 3.741866545 0 2.04191219 3.305725349 0 2.041984703 3.710441579 0 2.041905776 3.695907009 0 2.041828895 3.721920632 0 2.041754244 3.731075945 0 2.041667814 4.164737669 0 2.04157619 4.460395398 0 2.04150221 4.066273205 0 2.041447266 3.551436729 0 2.041397711 3.381920242 0 2.041347836 3.340431581 0 2.04129319 3.423620657 0 2.071206748 3.575119272 0 1.895342151 3.765872092 0 2.074278792 3.916573178 0 2.073968281 3.910460675 0 2.042322114 3.621195795 0 1.892160873 3.523693919 0 2.076787505 3.646818313 0 2.076296574 3.57797656 0 1.967254736 3.749491357 0 2.046574523 3.762332136 0 2.046053072 3.888901286 0 1.967258272 3.910590921 0 2.048172383 3.383440535 0 2.047523167 3.759074532 0 1.967260765 3.999615977 0 2.049484534 3.866941301 0 1.967258879 3.978901152 0 2.051170731 4.46567334 0 2.050159967 4.357597148 0 1.967259348 4.017611608 0 2.088846936 3.595474003 0 1.967250696 3.53165456 0 2.088849902 4.07136338 0 1.967243072 4.043924899 0 0 3.625693391 0 2.088849906 3.475563413 0 1.967235456 3.446673901 0 0 3.624508643 0 2.05090978 3.900319863 0 1.967237608 3.752010092 0 2.088851735 3.679982694 0 0 3.61309884 0 2.049443869 3.471040842 0 1.967238172 3.242617014 0 2.088856577 3.428101025 0 1.967233686 3.937244729 0 0 3.97107732 0 2.051028086 3.80397881 0 1.967236314 4.044293197 0 2.08885649 4.23703381 0 1.967231692 4.341256643 0 2.088858202 4.594168353 0 0 4.29826782 0 1.967226759 4.045715151 0 2.088856897 3.884975906 0 1.967224478 4.019431081 0 2.088859203 4.112569976 0 1.967222582 4.126078683 0 0 4.402392128 0 2.088857173 4.819610386 0 1.967220413 4.429965097 0 2.088859262 4.113506398 0 1.967219427 4.204965467 0 0 4.614478214 0 2.050651997 4.287155602 0 1.967226603 3.88984427 0 2.088858227 4.652601423 0 1.967224072 4.843851998 0 2.088859423 5.201680832 0 1.967222075 4.645744418 0 2.088860883 4.858989604 0 1.967220615 4.277012991 0 0 5.028196713 0 2.051255304 5.452929878 0 2.050355001 3.624369476 0 1.967234802 3.784565331 0 2.088863909 3.982693213 0 0 4.129533803 0 1.967229088 4.622384796 0 2.088861548 4.678186374 0 1.967226204 4.171670962 0 2.088863374 4.753353209 0 1.967223727 5.201336433 0 0 5.088513724 0 2.05076702 4.796621202 0 2.049740881 4.644862089 0 1.967236193 4.946330327 0 2.088863116 5.568887605 0 1.967231021 5.931707497 0 2.051272386 5.782592977 0 2.049900126 6.364131334 0 1.967240454 5.819233514 0 2.051379937 6.312836982 0 2.05006761 6.089480955 0 2.048897358 6.051836822 0 2.081283412 5.602790721 0 1.876658596 5.52905239 0 2.083584045 6.105065902 0 2.081977085 6.171969108 0 1.96725664 6.863116125 2.5 0 5.367548594 2.5 2.084975452 6.28879517 0.5 2.083218817 6.144300523 0 2.081706776 5.867549397 0 2.080273375 6.300828636 0 1.967262178 5.295769076 3.5 0 5.232643319 3.5 0 4.812689479 4 1.967251051 5.812995447 0 2.140544379 5.536364375 0 2.08376636 5.736854671 0 0 6.456665592 5 0 4.518588784 17.5 0 4.448568503 3 0 4.788055766 0 0 4.842088739 0 0 5.537950067 0 1.96723528 6.411392135 0 2.085099094 6.522784035 0 2.083098862 7.378587153 0 2.081487358 6.689264443 0 2.079611369 6.878151386 0 2.078964057 5.812406559 4.5 1.96724716 5.998611373 12.5 1.967242775 4.778379619 0 2.08403183 5.31193109 0 2.0798017 5.919695963 0 2.075729226 5.99688475 0 2.039721564 6.090257284 0 2.036205279 6.273597972 0 2.032884746 6.084728322 0.5 2.046870282 6.584234023 0 2.040849479 6.597532697 0 2.03526775 6.781567801 0 2.030081658 6.647963882 0 2.025221041 6.626830294 0 2.020644825 6.412361243 0 2.016249924 7.375852817 0 2.012091428 6.609955855 0 2.009402749 6.598854788 6.5 2.044491515 5.507184662 1 2.044885301 5.809974285 3.5 0 5.722913119 44 0 5.852866984 0 0 5.822596978 0 0 5.368355146 10 0 4.879991918 76 0 4.349349514 0 0 4.809179261 0 0 5.339547525 0 0 5.447512632 0 0 4.893626506 0 0 5.497121338 0 0 5.944004338 0 0 6.394222129 0 0 6.345615812 0 0 5.695494097 8.5 0 5.677040574 47.5 0 5.097513868 5 0 5.5729635 0 0 5.600292532 25 0 5.808134146 40 0 5.163434792 0.5 0 5.258498253 0.5 0 5.334000815 8 0 5.892128512 0 0 6.232182257 0 0 5.86950428 0 0 5.735016857 26.5 0 5.617433318 0 0 5.302491025 29 0 5.567993395 1.5 0 5.490724079 11 0 5.699463871 0.5 0 6.224950298 4 0 5.660958991 1.5 0 5.81612703 0 0 5.861291995 41.5 0 5.898253609 12.5 0 5.886459979 7 0 5.618605592 0.5 0 5.62323324 0 0 5.715852746 0 0 5.654001217 0 0 5.539656707 5.5 0 5.142361374 13 0 5.111418988 25.5 0 5.162186183 4.5 0 5.529636164 6 0 5.840125097 26 0 5.841853674 0 0 6.253020517 0 0 6.279650253 0 0 6.072899228 0 0 5.849350759 0.5 0 5.861996369 31.5 0 5.88638236 1.5 0 5.570375844 20.5 0 5.622675085 1 0 6.050322752 0 0 5.929646949 2.5 0 6.101142315 0 0 6.12662214 0 0 5.710179246 2.5 0 5.626265253 63.5 0 4.776274346 69.5 0 4.921751245 3 0 5.452368184 11.5 0 6.008460641 0.5 0 5.884066072 21.5 0 5.733126474 13.5 0 5.563072781 6 0 5.644989648 16