Mini-language as Model-View-Controller

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


An Example

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.

Command-line controller

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

Input script

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

Model

The model itself consists of two files, "yield.tcl" and "crop.tcl".

yield.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
}

crop.tcl

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

Data file "sampledata.dat"

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