summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes 'josch' Schauer <josch@mister-muffin.de>2020-10-23 08:27:38 +0200
committerJohannes 'josch' Schauer <josch@mister-muffin.de>2020-10-23 08:27:38 +0200
commit3b91637afd9716881bec3a34c3ace369c82ef61c (patch)
tree2445bd2a7aadd1fd90bc76e5ab7491a8403d6f75
parent2b00fcb77bb6e7b769ee34a114679838e00156d1 (diff)
New upstream version 6.0+dfsg
-rw-r--r--.dockerignore93
-rw-r--r--.gitignore149
-rw-r--r--.travis.yml213
-rw-r--r--AUTHOR3
-rw-r--r--CHANGELOG220
-rw-r--r--COPYING621
-rw-r--r--Dockerfile22
-rw-r--r--Doxyfile2397
-rw-r--r--INSTALL32
-rw-r--r--LICENSE674
-rw-r--r--LICENSE.FuzzyLite634
-rw-r--r--NEWS52
-rw-r--r--README.md457
-rw-r--r--THANKS22
-rw-r--r--appveyor.yml40
-rw-r--r--documentation/ui/figure.R491
-rw-r--r--documentation/ui/figure/bell.svg260
-rw-r--r--documentation/ui/figure/binary.svg261
-rw-r--r--documentation/ui/figure/concave.svg253
-rw-r--r--documentation/ui/figure/cosine.svg260
-rw-r--r--documentation/ui/figure/discrete.svg310
-rw-r--r--documentation/ui/figure/gaussian.svg260
-rw-r--r--documentation/ui/figure/gaussianProduct.svg264
-rw-r--r--documentation/ui/figure/piShape.svg260
-rw-r--r--documentation/ui/figure/power.svg227
-rw-r--r--documentation/ui/figure/ramp.svg261
-rw-r--r--documentation/ui/figure/rectangle.svg260
-rw-r--r--documentation/ui/figure/sShape.svg260
-rw-r--r--documentation/ui/figure/sigmoid.svg261
-rw-r--r--documentation/ui/figure/sigmoidDifference.svg260
-rw-r--r--documentation/ui/figure/sigmoidProduct.svg252
-rw-r--r--documentation/ui/figure/spike.svg260
-rw-r--r--documentation/ui/figure/terms.svg4955
-rw-r--r--documentation/ui/figure/trapezoid.svg260
-rw-r--r--documentation/ui/figure/triangle.svg260
-rw-r--r--documentation/ui/figure/zShape.svg260
-rw-r--r--documentation/ui/footer.html22
-rw-r--r--documentation/ui/header.html77
-rw-r--r--documentation/ui/image/android-chrome-144x144.pngbin0 -> 6532 bytes
-rw-r--r--documentation/ui/image/android-chrome-192x192.pngbin0 -> 8956 bytes
-rw-r--r--documentation/ui/image/android-chrome-36x36.pngbin0 -> 1735 bytes
-rw-r--r--documentation/ui/image/android-chrome-48x48.pngbin0 -> 2280 bytes
-rw-r--r--documentation/ui/image/android-chrome-72x72.pngbin0 -> 3171 bytes
-rw-r--r--documentation/ui/image/android-chrome-96x96.pngbin0 -> 4447 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-114x114.pngbin0 -> 6890 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-120x120.pngbin0 -> 7417 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-144x144.pngbin0 -> 8862 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-152x152.pngbin0 -> 9766 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-180x180.pngbin0 -> 11090 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-57x57.pngbin0 -> 3699 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-60x60.pngbin0 -> 3861 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-72x72.pngbin0 -> 4563 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-76x76.pngbin0 -> 5054 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon-precomposed.pngbin0 -> 12911 bytes
-rw-r--r--documentation/ui/image/apple-touch-icon.pngbin0 -> 11090 bytes
-rw-r--r--documentation/ui/image/browserconfig.xml12
-rw-r--r--documentation/ui/image/favicon-16x16.pngbin0 -> 813 bytes
-rw-r--r--documentation/ui/image/favicon-32x32.pngbin0 -> 1502 bytes
-rw-r--r--documentation/ui/image/favicon-96x96.pngbin0 -> 4447 bytes
-rw-r--r--documentation/ui/image/favicon.icobin0 -> 15086 bytes
-rw-r--r--documentation/ui/image/manifest.json41
-rw-r--r--documentation/ui/image/mstile-144x144.pngbin0 -> 6557 bytes
-rw-r--r--documentation/ui/image/mstile-150x150.pngbin0 -> 6806 bytes
-rw-r--r--documentation/ui/image/mstile-310x150.pngbin0 -> 7390 bytes
-rw-r--r--documentation/ui/image/mstile-310x310.pngbin0 -> 14321 bytes
-rw-r--r--documentation/ui/image/mstile-70x70.pngbin0 -> 4487 bytes
-rw-r--r--documentation/ui/image/safari-pinned-tab.svg28
-rw-r--r--documentation/ui/stylesheet.css0
-rw-r--r--examples/README.md13
-rw-r--r--examples/application/CMakeLists.txt140
-rwxr-xr-xexamples/application/clean.sh1
-rw-r--r--examples/application/compile.bat24
-rwxr-xr-xexamples/application/compile.sh25
-rw-r--r--examples/application/src/main.cpp16
-rw-r--r--examples/examples.R16
-rw-r--r--examples/hybrid/ObstacleAvoidance.R86
-rw-r--r--examples/hybrid/ObstacleAvoidance.cpp75
-rw-r--r--examples/hybrid/ObstacleAvoidance.fcl49
-rw-r--r--examples/hybrid/ObstacleAvoidance.fis43
-rw-r--r--examples/hybrid/ObstacleAvoidance.fld1025
-rw-r--r--examples/hybrid/ObstacleAvoidance.fll43
-rw-r--r--examples/hybrid/ObstacleAvoidance.java86
-rw-r--r--examples/hybrid/ObstacleAvoidance.pdfbin0 -> 45584 bytes
-rw-r--r--examples/hybrid/tipper.R109
-rw-r--r--examples/hybrid/tipper.cpp92
-rw-r--r--examples/hybrid/tipper.fcl66
-rw-r--r--examples/hybrid/tipper.fis57
-rw-r--r--examples/hybrid/tipper.fld1025
-rw-r--r--examples/hybrid/tipper.fll63
-rw-r--r--examples/hybrid/tipper.java103
-rw-r--r--examples/hybrid/tipper.pdfbin0 -> 32309 bytes
-rw-r--r--examples/mamdani/AllTerms.R111
-rw-r--r--examples/mamdani/AllTerms.cpp103
-rw-r--r--examples/mamdani/AllTerms.fcl90
-rw-r--r--examples/mamdani/AllTerms.fis86
-rw-r--r--examples/mamdani/AllTerms.fld1025
-rw-r--r--examples/mamdani/AllTerms.fll79
-rw-r--r--examples/mamdani/AllTerms.java114
-rw-r--r--examples/mamdani/AllTerms.pdfbin0 -> 24280 bytes
-rw-r--r--examples/mamdani/Laundry.R91
-rw-r--r--examples/mamdani/Laundry.cpp78
-rw-r--r--examples/mamdani/Laundry.fcl58
-rw-r--r--examples/mamdani/Laundry.fis51
-rw-r--r--examples/mamdani/Laundry.fld1025
-rw-r--r--examples/mamdani/Laundry.fll46
-rw-r--r--examples/mamdani/Laundry.java89
-rw-r--r--examples/mamdani/Laundry.pdfbin0 -> 30166 bytes
-rw-r--r--examples/mamdani/ObstacleAvoidance.R57
-rw-r--r--examples/mamdani/ObstacleAvoidance.cpp49
-rw-r--r--examples/mamdani/ObstacleAvoidance.fcl34
-rw-r--r--examples/mamdani/ObstacleAvoidance.fis32
-rw-r--r--examples/mamdani/ObstacleAvoidance.fld1025
-rw-r--r--examples/mamdani/ObstacleAvoidance.fll25
-rw-r--r--examples/mamdani/ObstacleAvoidance.java60
-rw-r--r--examples/mamdani/ObstacleAvoidance.pdfbin0 -> 25210 bytes
-rw-r--r--examples/mamdani/SimpleDimmer.R60
-rw-r--r--examples/mamdani/SimpleDimmer.cpp52
-rw-r--r--examples/mamdani/SimpleDimmer.fcl37
-rw-r--r--examples/mamdani/SimpleDimmer.fis35
-rw-r--r--examples/mamdani/SimpleDimmer.fld1025
-rw-r--r--examples/mamdani/SimpleDimmer.fll28
-rw-r--r--examples/mamdani/SimpleDimmer.java63
-rw-r--r--examples/mamdani/SimpleDimmer.pdfbin0 -> 22872 bytes
-rw-r--r--examples/mamdani/SimpleDimmerChained.R85
-rw-r--r--examples/mamdani/SimpleDimmerChained.cpp70
-rw-r--r--examples/mamdani/SimpleDimmerChained.fcl51
-rw-r--r--examples/mamdani/SimpleDimmerChained.fis46
-rw-r--r--examples/mamdani/SimpleDimmerChained.fld1025
-rw-r--r--examples/mamdani/SimpleDimmerChained.fll42
-rw-r--r--examples/mamdani/SimpleDimmerChained.java81
-rw-r--r--examples/mamdani/SimpleDimmerChained.pdfbin0 -> 42431 bytes
-rw-r--r--examples/mamdani/SimpleDimmerInverse.R85
-rw-r--r--examples/mamdani/SimpleDimmerInverse.cpp70
-rw-r--r--examples/mamdani/SimpleDimmerInverse.fcl51
-rw-r--r--examples/mamdani/SimpleDimmerInverse.fis46
-rw-r--r--examples/mamdani/SimpleDimmerInverse.fld1025
-rw-r--r--examples/mamdani/SimpleDimmerInverse.fll42
-rw-r--r--examples/mamdani/SimpleDimmerInverse.java81
-rw-r--r--examples/mamdani/SimpleDimmerInverse.pdfbin0 -> 41795 bytes
-rw-r--r--examples/mamdani/octave/COPYING674
-rw-r--r--examples/mamdani/octave/DESCRIPTION12
-rw-r--r--examples/mamdani/octave/investment_portfolio.R67
-rw-r--r--examples/mamdani/octave/investment_portfolio.cpp62
-rw-r--r--examples/mamdani/octave/investment_portfolio.fcl46
-rw-r--r--examples/mamdani/octave/investment_portfolio.fis42
-rw-r--r--examples/mamdani/octave/investment_portfolio.fld1025
-rw-r--r--examples/mamdani/octave/investment_portfolio.fll34
-rw-r--r--examples/mamdani/octave/investment_portfolio.java73
-rw-r--r--examples/mamdani/octave/investment_portfolio.pdfbin0 -> 19163 bytes
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.R90
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.cpp77
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.fcl57
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.fis50
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.fld1025
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.fll45
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.java88
-rw-r--r--examples/mamdani/octave/mamdani_tip_calculator.pdfbin0 -> 31675 bytes
-rw-r--r--examples/original/mamdani/AllTerms.fis84
-rw-r--r--examples/original/mamdani/AllTerms.fll78
-rw-r--r--examples/original/mamdani/Laundry.fll44
-rw-r--r--examples/original/mamdani/SimpleDimmer.fis39
-rw-r--r--examples/original/mamdani/SimpleDimmer.fll27
-rw-r--r--examples/original/mamdani/SimpleDimmerInverse.fll41
-rw-r--r--examples/original/mamdani/octave/COPYING674
-rw-r--r--examples/original/mamdani/octave/DESCRIPTION12
-rw-r--r--examples/original/mamdani/octave/investment_portfolio.fis64
-rw-r--r--examples/original/mamdani/octave/investment_portfolio.fll32
-rw-r--r--examples/original/mamdani/octave/mamdani_tip_calculator.fis72
-rw-r--r--examples/original/mamdani/octave/mamdani_tip_calculator.fll43
-rw-r--r--examples/original/takagi-sugeno/SimpleDimmer.fis41
-rw-r--r--examples/original/takagi-sugeno/SimpleDimmer.fll27
-rw-r--r--examples/original/takagi-sugeno/approximation.fis80
-rw-r--r--examples/original/takagi-sugeno/approximation.fll64
-rw-r--r--examples/original/takagi-sugeno/octave/COPYING674
-rw-r--r--examples/original/takagi-sugeno/octave/DESCRIPTION12
-rw-r--r--examples/original/takagi-sugeno/octave/cubic_approximator.fis81
-rw-r--r--examples/original/takagi-sugeno/octave/cubic_approximator.fll51
-rw-r--r--examples/original/takagi-sugeno/octave/heart_disease_risk.fis90
-rw-r--r--examples/original/takagi-sugeno/octave/heart_disease_risk.fll49
-rw-r--r--examples/original/takagi-sugeno/octave/linear_tip_calculator.fis64
-rw-r--r--examples/original/takagi-sugeno/octave/linear_tip_calculator.fll32
-rw-r--r--examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fis98
-rw-r--r--examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fll60
-rw-r--r--examples/original/tsukamoto/tsukamoto.fis65
-rw-r--r--examples/original/tsukamoto/tsukamoto.fll60
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.R57
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.cpp49
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.fcl33
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.fis32
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.fld1025
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.fll25
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.java60
-rw-r--r--examples/takagi-sugeno/ObstacleAvoidance.pdfbin0 -> 25090 bytes
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.R60
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.cpp52
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.fcl35
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.fis35
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.fld1025
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.fll28
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.java63
-rw-r--r--examples/takagi-sugeno/SimpleDimmer.pdfbin0 -> 22975 bytes
-rw-r--r--examples/takagi-sugeno/approximation.R119
-rw-r--r--examples/takagi-sugeno/approximation.cpp97
-rw-r--r--examples/takagi-sugeno/approximation.fcl70
-rw-r--r--examples/takagi-sugeno/approximation.fis66
-rw-r--r--examples/takagi-sugeno/approximation.fld1025
-rw-r--r--examples/takagi-sugeno/approximation.fll65
-rw-r--r--examples/takagi-sugeno/approximation.java108
-rw-r--r--examples/takagi-sugeno/approximation.pdfbin0 -> 65783 bytes
-rw-r--r--examples/takagi-sugeno/octave/COPYING674
-rw-r--r--examples/takagi-sugeno/octave/DESCRIPTION12
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.R84
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.cpp76
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.fcl59
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.fis59
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.fld1025
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.fll52
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.java87
-rw-r--r--examples/takagi-sugeno/octave/cubic_approximator.pdfbin0 -> 24950 bytes
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.R84
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.cpp79
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.fcl60
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.fis59
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.fld1025
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.fll51
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.java90
-rw-r--r--examples/takagi-sugeno/octave/heart_disease_risk.pdfbin0 -> 16865 bytes
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.R67
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.cpp62
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.fcl43
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.fis42
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.fld1025
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.fll34
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.java73
-rw-r--r--examples/takagi-sugeno/octave/linear_tip_calculator.pdfbin0 -> 18236 bytes
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.R119
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.cpp98
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.fcl69
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.fis64
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.fld1025
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.fll62
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.java109
-rw-r--r--examples/takagi-sugeno/octave/sugeno_tip_calculator.pdfbin0 -> 41451 bytes
-rw-r--r--examples/tsukamoto/tsukamoto.R126
-rw-r--r--examples/tsukamoto/tsukamoto.cpp97
-rw-r--r--examples/tsukamoto/tsukamoto.fcl65
-rw-r--r--examples/tsukamoto/tsukamoto.fis59
-rw-r--r--examples/tsukamoto/tsukamoto.fld1025
-rw-r--r--examples/tsukamoto/tsukamoto.fll61
-rw-r--r--examples/tsukamoto/tsukamoto.java108
-rw-r--r--examples/tsukamoto/tsukamoto.pdfbin0 -> 85574 bytes
-rw-r--r--fuzzylite.pngbin0 -> 262929 bytes
-rw-r--r--fuzzylite.svg42
-rw-r--r--fuzzylite/CMakeLists.txt301
-rw-r--r--fuzzylite/FL_HEADERS111
-rw-r--r--fuzzylite/FL_SOURCES102
-rw-r--r--fuzzylite/FL_TESTS16
-rw-r--r--fuzzylite/build.bat122
-rwxr-xr-xfuzzylite/build.sh98
-rw-r--r--fuzzylite/fl/Benchmark.h400
-rw-r--r--fuzzylite/fl/Complexity.h297
-rw-r--r--fuzzylite/fl/Console.h155
-rw-r--r--fuzzylite/fl/Engine.h478
-rw-r--r--fuzzylite/fl/Exception.h140
-rw-r--r--fuzzylite/fl/Headers.h148
-rw-r--r--fuzzylite/fl/Operation.h1069
-rw-r--r--fuzzylite/fl/activation/Activation.h95
-rw-r--r--fuzzylite/fl/activation/First.h104
-rw-r--r--fuzzylite/fl/activation/General.h73
-rw-r--r--fuzzylite/fl/activation/Highest.h86
-rw-r--r--fuzzylite/fl/activation/Last.h103
-rw-r--r--fuzzylite/fl/activation/Lowest.h87
-rw-r--r--fuzzylite/fl/activation/Proportional.h71
-rw-r--r--fuzzylite/fl/activation/Threshold.h183
-rw-r--r--fuzzylite/fl/defuzzifier/Bisector.h64
-rw-r--r--fuzzylite/fl/defuzzifier/Centroid.h63
-rw-r--r--fuzzylite/fl/defuzzifier/Defuzzifier.h76
-rw-r--r--fuzzylite/fl/defuzzifier/IntegralDefuzzifier.h73
-rw-r--r--fuzzylite/fl/defuzzifier/LargestOfMaximum.h67
-rw-r--r--fuzzylite/fl/defuzzifier/MeanOfMaximum.h67
-rw-r--r--fuzzylite/fl/defuzzifier/SmallestOfMaximum.h67
-rw-r--r--fuzzylite/fl/defuzzifier/WeightedAverage.h71
-rw-r--r--fuzzylite/fl/defuzzifier/WeightedAverageCustom.h77
-rw-r--r--fuzzylite/fl/defuzzifier/WeightedDefuzzifier.h90
-rw-r--r--fuzzylite/fl/defuzzifier/WeightedSum.h71
-rw-r--r--fuzzylite/fl/defuzzifier/WeightedSumCustom.h78
-rw-r--r--fuzzylite/fl/factory/ActivationFactory.h46
-rw-r--r--fuzzylite/fl/factory/CloningFactory.h226
-rw-r--r--fuzzylite/fl/factory/ConstructionFactory.h202
-rw-r--r--fuzzylite/fl/factory/DefuzzifierFactory.h75
-rw-r--r--fuzzylite/fl/factory/FactoryManager.h154
-rw-r--r--fuzzylite/fl/factory/FunctionFactory.h61
-rw-r--r--fuzzylite/fl/factory/HedgeFactory.h44
-rw-r--r--fuzzylite/fl/factory/SNormFactory.h44
-rw-r--r--fuzzylite/fl/factory/TNormFactory.h44
-rw-r--r--fuzzylite/fl/factory/TermFactory.h45
-rw-r--r--fuzzylite/fl/fuzzylite.h427
-rw-r--r--fuzzylite/fl/hedge/Any.h60
-rw-r--r--fuzzylite/fl/hedge/Extremely.h55
-rw-r--r--fuzzylite/fl/hedge/Hedge.h77
-rw-r--r--fuzzylite/fl/hedge/HedgeFunction.h82
-rw-r--r--fuzzylite/fl/hedge/Not.h51
-rw-r--r--fuzzylite/fl/hedge/Seldom.h56
-rw-r--r--fuzzylite/fl/hedge/Somewhat.h52
-rw-r--r--fuzzylite/fl/hedge/Very.h50
-rw-r--r--fuzzylite/fl/imex/CppExporter.h161
-rw-r--r--fuzzylite/fl/imex/Exporter.h74
-rw-r--r--fuzzylite/fl/imex/FclExporter.h105
-rw-r--r--fuzzylite/fl/imex/FclImporter.h74
-rw-r--r--fuzzylite/fl/imex/FisExporter.h121
-rw-r--r--fuzzylite/fl/imex/FisImporter.h80
-rw-r--r--fuzzylite/fl/imex/FldExporter.h248
-rw-r--r--fuzzylite/fl/imex/FllExporter.h168
-rw-r--r--fuzzylite/fl/imex/FllImporter.h91
-rw-r--r--fuzzylite/fl/imex/Importer.h71
-rw-r--r--fuzzylite/fl/imex/JavaExporter.h152
-rw-r--r--fuzzylite/fl/imex/RScriptExporter.h246
-rw-r--r--fuzzylite/fl/norm/Norm.h75
-rw-r--r--fuzzylite/fl/norm/SNorm.h51
-rw-r--r--fuzzylite/fl/norm/TNorm.h50
-rw-r--r--fuzzylite/fl/norm/s/AlgebraicSum.h53
-rw-r--r--fuzzylite/fl/norm/s/BoundedSum.h54
-rw-r--r--fuzzylite/fl/norm/s/DrasticSum.h55
-rw-r--r--fuzzylite/fl/norm/s/EinsteinSum.h52
-rw-r--r--fuzzylite/fl/norm/s/HamacherSum.h52
-rw-r--r--fuzzylite/fl/norm/s/Maximum.h51
-rw-r--r--fuzzylite/fl/norm/s/NilpotentMaximum.h56
-rw-r--r--fuzzylite/fl/norm/s/NormalizedSum.h52
-rw-r--r--fuzzylite/fl/norm/s/SNormFunction.h81
-rw-r--r--fuzzylite/fl/norm/s/UnboundedSum.h52
-rw-r--r--fuzzylite/fl/norm/t/AlgebraicProduct.h52
-rw-r--r--fuzzylite/fl/norm/t/BoundedDifference.h52
-rw-r--r--fuzzylite/fl/norm/t/DrasticProduct.h55
-rw-r--r--fuzzylite/fl/norm/t/EinsteinProduct.h52
-rw-r--r--fuzzylite/fl/norm/t/HamacherProduct.h52
-rw-r--r--fuzzylite/fl/norm/t/Minimum.h51
-rw-r--r--fuzzylite/fl/norm/t/NilpotentMinimum.h55
-rw-r--r--fuzzylite/fl/norm/t/TNormFunction.h81
-rw-r--r--fuzzylite/fl/rule/Antecedent.h185
-rw-r--r--fuzzylite/fl/rule/Consequent.h138
-rw-r--r--fuzzylite/fl/rule/Expression.h133
-rw-r--r--fuzzylite/fl/rule/Rule.h305
-rw-r--r--fuzzylite/fl/rule/RuleBlock.h233
-rw-r--r--fuzzylite/fl/term/Activated.h107
-rw-r--r--fuzzylite/fl/term/Aggregated.h212
-rw-r--r--fuzzylite/fl/term/Bell.h114
-rw-r--r--fuzzylite/fl/term/Binary.h132
-rw-r--r--fuzzylite/fl/term/Concave.h110
-rw-r--r--fuzzylite/fl/term/Constant.h81
-rw-r--r--fuzzylite/fl/term/Cosine.h101
-rw-r--r--fuzzylite/fl/term/Discrete.h280
-rw-r--r--fuzzylite/fl/term/Function.h399
-rw-r--r--fuzzylite/fl/term/Gaussian.h99
-rw-r--r--fuzzylite/fl/term/GaussianProduct.h138
-rw-r--r--fuzzylite/fl/term/Linear.h179
-rw-r--r--fuzzylite/fl/term/PiShape.h137
-rw-r--r--fuzzylite/fl/term/Ramp.h135
-rw-r--r--fuzzylite/fl/term/Rectangle.h102
-rw-r--r--fuzzylite/fl/term/SShape.h109
-rw-r--r--fuzzylite/fl/term/Sigmoid.h120
-rw-r--r--fuzzylite/fl/term/SigmoidDifference.h131
-rw-r--r--fuzzylite/fl/term/SigmoidProduct.h132
-rw-r--r--fuzzylite/fl/term/Spike.h98
-rw-r--r--fuzzylite/fl/term/Term.h165
-rw-r--r--fuzzylite/fl/term/Trapezoid.h129
-rw-r--r--fuzzylite/fl/term/Triangle.h118
-rw-r--r--fuzzylite/fl/term/ZShape.h111
-rw-r--r--fuzzylite/fl/variable/InputVariable.h60
-rw-r--r--fuzzylite/fl/variable/OutputVariable.h226
-rw-r--r--fuzzylite/fl/variable/Variable.h298
-rw-r--r--fuzzylite/fuzzylite.139
-rw-r--r--fuzzylite/fuzzylite.pc.in10
-rw-r--r--fuzzylite/src/Benchmark.cpp460
-rw-r--r--fuzzylite/src/Complexity.cpp283
-rw-r--r--fuzzylite/src/Console.cpp1023
-rw-r--r--fuzzylite/src/Engine.cpp716
-rw-r--r--fuzzylite/src/Exception.cpp184
-rw-r--r--fuzzylite/src/activation/First.cpp122
-rw-r--r--fuzzylite/src/activation/General.cpp77
-rw-r--r--fuzzylite/src/activation/Highest.cpp120
-rw-r--r--fuzzylite/src/activation/Last.cpp121
-rw-r--r--fuzzylite/src/activation/Lowest.cpp122
-rw-r--r--fuzzylite/src/activation/Proportional.cpp91
-rw-r--r--fuzzylite/src/activation/Threshold.cpp170
-rw-r--r--fuzzylite/src/defuzzifier/Bisector.cpp68
-rw-r--r--fuzzylite/src/defuzzifier/Centroid.cpp68
-rw-r--r--fuzzylite/src/defuzzifier/IntegralDefuzzifier.cpp44
-rw-r--r--fuzzylite/src/defuzzifier/LargestOfMaximum.cpp65
-rw-r--r--fuzzylite/src/defuzzifier/MeanOfMaximum.cpp77
-rw-r--r--fuzzylite/src/defuzzifier/SmallestOfMaximum.cpp65
-rw-r--r--fuzzylite/src/defuzzifier/WeightedAverage.cpp100
-rw-r--r--fuzzylite/src/defuzzifier/WeightedAverageCustom.cpp117
-rw-r--r--fuzzylite/src/defuzzifier/WeightedDefuzzifier.cpp76
-rw-r--r--fuzzylite/src/defuzzifier/WeightedSum.cpp97
-rw-r--r--fuzzylite/src/defuzzifier/WeightedSumCustom.cpp112
-rw-r--r--fuzzylite/src/factory/ActivationFactory.cpp42
-rw-r--r--fuzzylite/src/factory/DefuzzifierFactory.cpp73
-rw-r--r--fuzzylite/src/factory/FactoryManager.cpp129
-rw-r--r--fuzzylite/src/factory/FunctionFactory.cpp169
-rw-r--r--fuzzylite/src/factory/HedgeFactory.cpp40
-rw-r--r--fuzzylite/src/factory/SNormFactory.cpp46
-rw-r--r--fuzzylite/src/factory/TNormFactory.cpp42
-rw-r--r--fuzzylite/src/factory/TermFactory.cpp70
-rw-r--r--fuzzylite/src/fuzzylite.cpp53
-rw-r--r--fuzzylite/src/hedge/Any.cpp47
-rw-r--r--fuzzylite/src/hedge/Extremely.cpp46
-rw-r--r--fuzzylite/src/hedge/HedgeFunction.cpp63
-rw-r--r--fuzzylite/src/hedge/Not.cpp41
-rw-r--r--fuzzylite/src/hedge/Seldom.cpp45
-rw-r--r--fuzzylite/src/hedge/Somewhat.cpp41
-rw-r--r--fuzzylite/src/hedge/Very.cpp41
-rw-r--r--fuzzylite/src/imex/CppExporter.cpp267
-rw-r--r--fuzzylite/src/imex/Exporter.cpp37
-rw-r--r--fuzzylite/src/imex/FclExporter.cpp200
-rw-r--r--fuzzylite/src/imex/FclImporter.cpp587
-rw-r--r--fuzzylite/src/imex/FisExporter.cpp423
-rw-r--r--fuzzylite/src/imex/FisImporter.cpp484
-rw-r--r--fuzzylite/src/imex/FldExporter.cpp312
-rw-r--r--fuzzylite/src/imex/FllExporter.cpp210
-rw-r--r--fuzzylite/src/imex/FllImporter.cpp316
-rw-r--r--fuzzylite/src/imex/Importer.cpp42
-rw-r--r--fuzzylite/src/imex/JavaExporter.cpp251
-rw-r--r--fuzzylite/src/imex/RScriptExporter.cpp234
-rw-r--r--fuzzylite/src/main.cpp50
-rw-r--r--fuzzylite/src/norm/s/AlgebraicSum.cpp41
-rw-r--r--fuzzylite/src/norm/s/BoundedSum.cpp43
-rw-r--r--fuzzylite/src/norm/s/DrasticSum.cpp46
-rw-r--r--fuzzylite/src/norm/s/EinsteinSum.cpp41
-rw-r--r--fuzzylite/src/norm/s/HamacherSum.cpp44
-rw-r--r--fuzzylite/src/norm/s/Maximum.cpp43
-rw-r--r--fuzzylite/src/norm/s/NilpotentMaximum.cpp46
-rw-r--r--fuzzylite/src/norm/s/NormalizedSum.cpp43
-rw-r--r--fuzzylite/src/norm/s/SNormFunction.cpp65
-rw-r--r--fuzzylite/src/norm/s/UnboundedSum.cpp43
-rw-r--r--fuzzylite/src/norm/t/AlgebraicProduct.cpp41
-rw-r--r--fuzzylite/src/norm/t/BoundedDifference.cpp43
-rw-r--r--fuzzylite/src/norm/t/DrasticProduct.cpp46
-rw-r--r--fuzzylite/src/norm/t/EinsteinProduct.cpp41
-rw-r--r--fuzzylite/src/norm/t/HamacherProduct.cpp44
-rw-r--r--fuzzylite/src/norm/t/Minimum.cpp44
-rw-r--r--fuzzylite/src/norm/t/NilpotentMinimum.cpp47
-rw-r--r--fuzzylite/src/norm/t/TNormFunction.cpp66
-rw-r--r--fuzzylite/src/rule/Antecedent.cpp447
-rw-r--r--fuzzylite/src/rule/Consequent.cpp244
-rw-r--r--fuzzylite/src/rule/Expression.cpp83
-rw-r--r--fuzzylite/src/rule/Rule.cpp264
-rw-r--r--fuzzylite/src/rule/RuleBlock.cpp227
-rw-r--r--fuzzylite/src/term/Activated.cpp110
-rw-r--r--fuzzylite/src/term/Aggregated.cpp247
-rw-r--r--fuzzylite/src/term/Bell.cpp93
-rw-r--r--fuzzylite/src/term/Binary.cpp96
-rw-r--r--fuzzylite/src/term/Concave.cpp107
-rw-r--r--fuzzylite/src/term/Constant.cpp64
-rw-r--r--fuzzylite/src/term/Cosine.cpp89
-rw-r--r--fuzzylite/src/term/Discrete.cpp230
-rw-r--r--fuzzylite/src/term/Function.cpp578
-rw-r--r--fuzzylite/src/term/Gaussian.cpp86
-rw-r--r--fuzzylite/src/term/GaussianProduct.cpp117
-rw-r--r--fuzzylite/src/term/Linear.cpp115
-rw-r--r--fuzzylite/src/term/PiShape.cpp123
-rw-r--r--fuzzylite/src/term/Ramp.cpp119
-rw-r--r--fuzzylite/src/term/Rectangle.cpp87
-rw-r--r--fuzzylite/src/term/SShape.cpp116
-rw-r--r--fuzzylite/src/term/Sigmoid.cpp124
-rw-r--r--fuzzylite/src/term/SigmoidDifference.cpp108
-rw-r--r--fuzzylite/src/term/SigmoidProduct.cpp107
-rw-r--r--fuzzylite/src/term/Spike.cpp84
-rw-r--r--fuzzylite/src/term/Term.cpp65
-rw-r--r--fuzzylite/src/term/Trapezoid.cpp128
-rw-r--r--fuzzylite/src/term/Triangle.cpp113
-rw-r--r--fuzzylite/src/term/ZShape.cpp116
-rw-r--r--fuzzylite/src/variable/InputVariable.cpp44
-rw-r--r--fuzzylite/src/variable/OutputVariable.cpp226
-rw-r--r--fuzzylite/src/variable/Variable.cpp295
-rw-r--r--fuzzylite/test/BenchmarkTest.cpp131
-rw-r--r--fuzzylite/test/Catch.License23
-rw-r--r--fuzzylite/test/MainTest.cpp34
-rw-r--r--fuzzylite/test/QuickTest.cpp128
-rw-r--r--fuzzylite/test/activation/ThresholdTest.cpp65
-rw-r--r--fuzzylite/test/catch.hpp11282
-rw-r--r--fuzzylite/test/hedge/HedgeFunctionTest.cpp141
-rw-r--r--fuzzylite/test/imex/FldExporterTest.cpp45
-rw-r--r--fuzzylite/test/imex/FllImporterTest.cpp56
-rw-r--r--fuzzylite/test/imex/RScriptExporterTest.cpp103
-rw-r--r--fuzzylite/test/norm/NormFunctionTest.cpp202
-rw-r--r--fuzzylite/test/term/AggregatedTest.cpp52
-rw-r--r--fuzzylite/test/term/DiscreteTest.cpp125
-rw-r--r--fuzzylite/test/term/FunctionTest.cpp115
-rw-r--r--fuzzylite/test/term/TrapezoidTest.cpp53
-rw-r--r--fuzzylite/test/term/TriangleTest.cpp66
-rw-r--r--fuzzylite/test/variable/VariableTest.cpp74
491 files changed, 88342 insertions, 0 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..5d73f37
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,93 @@
+#Ignore documentation to be generated by doxygen
+fuzzylite/release/
+fuzzylite/debug/
+documentation/html/
+documentation/man/
+
+# Created by https://www.gitignore.io/api/git,windows,linux,osx,netbeans,cmake
+
+### Git ###
+*.orig
+
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+
+### OSX ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+.nb-gradle/
+
+
+### CMake ###
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Makefile
+cmake_install.cmake
+install_manifest.txt
+CTestTestfile.cmake \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fb98d86
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,149 @@
+# Created by https://www.gitignore.io
+
+### Linux ###
+*~
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### OSX ###
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### C++ ###
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+
+### NetBeans ###
+nbproject/
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+nb-configuration.xml
+.nb-gradle/
+
+
+### Eclipse ###
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# PDT-specific
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# TeXlipse plugin
+.texlipse
+
+
+### CMake ###
+CMakeCache.txt
+CMakeFiles
+Makefile
+cmake_install.cmake
+install_manifest.txt
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..71dbd88
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,213 @@
+language: generic
+dist: trusty
+sudo: required
+
+services:
+ - docker
+
+git:
+ depth: 1
+
+before_script:
+ - docker build -t fuzzylite -f Dockerfile --build-arg CXX_COMPILER=${CXX_COMPILER} .
+
+script:
+ - docker run -e CXX=${CXX_COMPILER} -e FL_CPP98=${FL_CPP98} -e FL_USE_FLOAT=${FL_USE_FLOAT} -e FL_BUILD_TESTS=ON -t fuzzylite release
+
+ - docker run -e CXX=${CXX_COMPILER} -e FL_CPP98=${FL_CPP98} -e FL_USE_FLOAT=${FL_USE_FLOAT} -e FL_BUILD_TESTS=ON -t fuzzylite debug
+
+ - docker run -t fuzzylite documentation
+
+matrix:
+ include:
+ # - osx:
+
+#g++-6
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-6 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-6 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-6 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-6 FL_CPP98=ON FL_USE_FLOAT=ON
+
+##clang-3.8
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.8 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.8 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.8 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.8 FL_CPP98=ON FL_USE_FLOAT=ON
+
+#g++-5
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-5 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-5 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-5 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-5 FL_CPP98=ON FL_USE_FLOAT=ON
+
+##clang-3.7
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.7 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.7 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.7 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.7 FL_CPP98=ON FL_USE_FLOAT=ON
+
+#g++-4.9
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.9 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.9 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.9 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.9 FL_CPP98=ON FL_USE_FLOAT=ON
+
+##clang-3.6
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.6 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.6 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.6 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.6 FL_CPP98=ON FL_USE_FLOAT=ON
+
+#g++-4.8
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.8 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.8 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.8 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.8 FL_CPP98=ON FL_USE_FLOAT=ON
+
+##clang-3.5
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.5 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.5 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.5 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: clang
+ env: CXX_COMPILER=clang++-3.5 FL_CPP98=ON FL_USE_FLOAT=ON
+
+#g++-4.7
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.7 FL_CPP98=OFF FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.7 FL_CPP98=OFF FL_USE_FLOAT=ON
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.7 FL_CPP98=ON FL_USE_FLOAT=OFF
+ - os: linux
+ compiler: g++
+ env: CXX_COMPILER=g++-4.7 FL_CPP98=ON FL_USE_FLOAT=ON
+
+# #clang-3.4 does not install properly in ubuntu (clang++-3.4 command not found)
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.4 FL_CPP98=OFF FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.4 FL_CPP98=OFF FL_USE_FLOAT=ON
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.4 FL_CPP98=ON FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.4 FL_CPP98=ON FL_USE_FLOAT=ON
+
+# #g++-4.6 does not have an installation candidate in ubuntu
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.6 FL_CPP98=OFF FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.6 FL_CPP98=OFF FL_USE_FLOAT=ON
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.6 FL_CPP98=ON FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.6 FL_CPP98=ON FL_USE_FLOAT=ON
+
+
+# #clang-3.3 does not install properly in ubuntu (clang++-3.4 command not found)
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.3 FL_CPP98=OFF FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.3 FL_CPP98=OFF FL_USE_FLOAT=ON
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.3 FL_CPP98=ON FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: clang
+# env: CXX_COMPILER=clang++-3.3 FL_CPP98=ON FL_USE_FLOAT=ON
+
+# #g++-4.5 does not have an installation candidate in ubuntu
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.5 FL_CPP98=OFF FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.5 FL_CPP98=OFF FL_USE_FLOAT=ON
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.5 FL_CPP98=ON FL_USE_FLOAT=OFF
+# - os: linux
+# compiler: g++
+# env: CXX_COMPILER=g++-4.5 FL_CPP98=ON FL_USE_FLOAT=ON
+
+notifications:
+ email:
+ recipients:
+ - jcrada@fuzzylite.com
+ on_success: always
+ on_failure: always
diff --git a/AUTHOR b/AUTHOR
new file mode 100644
index 0000000..eb752b0
--- /dev/null
+++ b/AUTHOR
@@ -0,0 +1,3 @@
+Juan Rada-Vilela, Ph.D.
+jcrada@fuzzylite.com
+http://www.fuzzylite.com/jcrada \ No newline at end of file
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..640dacb
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,220 @@
+Version 6.0
+===========
+
+Overview
+--------
+* The FuzzyLite Libraries, namely fuzzylite and jfuzzylite, both in version 6.0, are licensed under the GNU General Public License version 3.
+
+* By default, fuzzylite builds using C++11 instead of C++98.
+
+* Important performance improvements.
+
+* Refactored the following names for the operation of engines: from activation operator to implication operator, from accumulation operator to aggregation operator.
+
+* Renamed the term `Accumulated` to `Aggregated`.
+
+* New activation methods decouple the activation of rules from the rule block and provide different methods for activating rules (see Activation Methods).
+
+* New class `ActivationFactory` provides a factory of activation methods.
+
+* New class `Benchmark` to evaluate the performance and accuracy of engines.
+
+* New class `Complexity` to estimate the computational complexity of an engine.
+
+* New class `RScriptExporter` to export the surfaces of an engine using the `ggplot2` library.
+
+* New class `Binary` term for binary edges.
+
+* New `UnboundedSum` S-Norm in `SNormFactory`.
+
+* New classes `SNormFunction` and `TNormFunction` to create custom functions on any two values using the `Function` class.
+
+* Added description strings to `Engine`, `Variable` and `RuleBlock`
+
+* Privatized previously protected members of classes and subclasses of `Term`, `Variable`, `Rule`, `Defuzzifier`, `[Cloning|Construction]Factory`, `Importer`, `Exporter`, amongst others.
+
+* Improved portability by replacing `int` for `std::size_t` where necessary, thereby additionally removing warnings in Windows 64bit
+
+* Deleted `Operation.cpp` and inlined its methods into `Operation.h`
+
+* Updated `.travis.yml` to use Docker, and build using g++ (versions 6, 5, 4.9, 4.8, 4.7) and clang (versions 3.8, 3.7, 3.6, and 3.5).
+
+* Added `appveyor.yml` to use continuous integration in Windows under Visual Studio 2013 and 2015.
+
+* Added some unit tests and support for future unit tests.
+
+* Bug fixes.
+
+* New example of hybrid engines.
+
+* New example on obstacle avoidance for Mamdani, Takagi-Sugeno, and Hybrid engines.
+
+* New R scripts for each example and its respective surfaces in `pdf` formats.
+
+
+Activation Method
+-----------------
+* New activation methods determine the activation of rules in a rule block. Specifically, the activation methods compute the activation degrees of the rules and the activation order of the rules.
+
+* Seven activation methods available: General, First, Last, Highest, Lowest, Proportional and Threshold.
+
+* If no activation method is supplied, an instance of General will be automatically set.
+
+* New class `General` activates every rule following the insertion order in the rule block.
+
+* New classes `First` and `Last` activate the first and last $n$ rules (following insertion order) whose activation degrees are greater than or equal to a given threshold.
+
+* New classes `Highest` and `Lowest` activate the first and last $n$ rules sorted (descending or ascending) by activation degree.
+
+* New class `Proportional` activates every rule with an activation degree proportional to the activation degrees of the other rules.
+
+* New class `Threshold` activates every rule that satisfies a given comparison operator and a given threshold.
+
+* New class `ActivationFactory` provides a factory of activation methods.
+
+
+
+Defuzzifier
+-----------
+* Overall performance improvements
+* The new default resolution of integral defuzzifiers is 100 (from 200 in previous version)
+* Importantly simplified `WeightedAverage` and `WeightedSum` by not using the implication and aggregation operators.
+* New experimental classes `WeightedAverageCustom` and `WeightedSumCustom` which use the implication and aggregation operators to compute the weighted averages and weighted sums, respectively.
+
+
+Factory
+-------
+* New class `ActivationFactory` to register activation methods.
+* New method `FactoryManager::activation()` to get the activation factory.
+* Inlined methods in [CloningFactory|ConstructionFactory].h
+* Fixed bug in `CloningFactory::deregisterObject()`. Bug: Object was deleted before removing it from the map, leaving an invalid object in the map which would cause a segmentation fault. Solution: Remove the object from the map before deleting it.
+* New `abs` function in `FunctionFactory` to compute the absolute value of a number.
+* New `UnboundedSum` S-Norm in `SNormFactory`.
+
+Hedge
+-----
+* Added `FL_IOVERRIDE` identifiers to hedge Extremely
+* Added `FL_IFINAL` final identifiers to `Hedge` classes (except `Any`).
+
+
+
+Importer and Exporter
+---------------------
+* New `RScriptExporter` generates an R script that uses the `ggplot2` library to produce the surfaces of an engine for each pair of input variables on each output variable.
+
+* Updated `Fll[Importer|Exporter]` to import and export the newly named properties `implication` and `aggregation` (previously known as `activation` and `accumulation`). However, the `FllImporter` has backward compatibility with the previous property names.
+
+* In `Fll[Importer|Exporter]`, added `lock-range` property of input variables, `activation` property for activation methods in rule blocks, and `description` property to `[Input|Output]Variable` and `RuleBlock`.
+
+* Added default option to generate C++ and Java code using the actual names of the input variables, output variables, and rule blocks, instead of the generic `[input|output]Variable` and `ruleBlock` names.
+
+* Updated [Cpp|Java][Import|Export] to generate code using the `description` of an engine if available, the `implication` instead of the `activation`, and the `aggregation` instead of the `accumulation`.
+
+* Removed compatibility between `[Fcl|Fis]Exporter` and `fuzzylite`. In previous versions, these exporters produced additional tags that were only relevant to `fuzzylite`, so that an engine written in these languages could also support the features in `fuzzylite`. However, in doing so, Matlab, Octave and JFuzzyLogic would fail to import the engines written in their own languages because they would not recognize the `fuzzylite` features. Hence, in order to generate code compatible with Matlab, Octave, and JFuzzyLogic, the `fuzzylite` features are removed from the code.
+
+* Refactored methods [Cpp|Java|Fll|Fis|Fcl]Exporter::toString([S|T]Norm*) to take `::toString(Norm*)`.
+
+* Renamed methods FisImporter::extract[SNorm|TNorm|Defuzzifier]() to FisImporter::translate[SNorm|TNorm|Defuzzifier]()
+
+* Fixed bug causing segmentation fault when malformed term in FuzzyLite Language
+
+
+
+Norms
+-----
+* New class `UnboundedSum` to compute sum between any two values and hence reflect Matlab's and Octave's `sum` aggregation operator.
+* New classes `SNormFunction` and `TNormFunction` to create custom functions on any two values using the `Function` class.
+* Fixed bug computing the `NormalizedSum` S-Norm.
+
+
+Rule
+----
+* Added properties `fl::scalar activationDegree`, `bool triggered` and `bool enabled` to a `Rule`. The `activationDegree` property stores the activation degree of the rule in order to avoid recomputing it when requesting it. The `triggered` property indicates whether the rule was triggered (i.e., whether the antecedent modified the consequent). The `enabled` property determines whether the rule can be triggered (by default, a rule is always enabled unless programmatically indicated otherwise).
+
+* Decoupled computing the activation degree and triggering the rule. Previously, the activation degree of a rule was computed and triggered at the same time using `Rule::activate(TNorm* conjunction, SNorm* disjunction, TNorm* implication)`. Currently, there are two methods: `fl::scalar activateWith(TNorm* conjunction, SNorm* disjunction)`, which computes, stores and returns the activation degree of the rule; and `trigger(TNorm* implication)`, which, if the rule is enabled and the activation degree is greater than zero, then the rule is triggered to modify the consequent.
+
+* Renamed `RuleBlock::activation` operator to `RuleBlock::implication` operator, and so its respective getters and setters.
+* Added `RuleBlock::activation` method and respective getters and setters.
+* In `RuleBlock::activate()`, if there is no activation method, the `General` activation method is automatically set in order to have backward compatibility.
+
+* Fixed bug in `RuleBlock` to reset and clone the implication operator. Bug: implication operator is not copied and reset. Fix: copy and reset implication operator when cloning the `RuleBlock`.
+
+* Added identifier `FL_IFINAL` to classes `Proposition` and `Operator`.
+
+Term
+----
+* Performance improvements.
+* `Discrete` term uses binary search instead of linear search, hence significantly improving performance.
+* `Discrete` term can create a `Discrete` term from any other term.
+* New `Binary` edge term.
+* Added method `bool Term::isMonotonic()` to determine whether the term is monotonic (returns true only for `Concave`, `Ramp`, `Sigmoid`, `SShape`, and `ZShape`).
+* Refactored static method `WeightedDefuzzifier::tsukamoto()` into non-static method `Term::tsukamoto()`, which is overriden by each of the terms that can be used for `tsukamoto` controllers.
+* Privatized `Term::name` and the properties of each subclass of `Term`.
+* Inlined generic methods in `[Linear|Discrete].h`
+* Renamed `Activated::activation` operator to `Activated::implication` and its respective getters and setters.
+* Renamed `Accumulated` term to `Aggregated` term, and its `accumulation` operator to `aggregation` operator including getters and setters.
+* For performance improvements, terms of `Aggregated` term are copies of objects in stack memory rather than pointers to objects in heap memory.
+* Refactored static `Term::updateReference()` to non-static being overrided by `Linear`, `Function`.
+* Added enum `[Ramp|Sigmoid]::Direction` to specify the direction of the term.
+* Added `Term::clone()` method to create a copy of any term.
+
+* Fixed bug in `Function` term. Bug: given a formula = "tan(y)" and a map["y"] = 1.0, and executing `Function::load(formula)`, then the map of variables is reset because `load()` calls `unload()` first, causing the deregistration of variable `y`. Solution: Removed method `unload()` from `load()`, thereby causing future `load()` not to reset variables.
+* Fixed bug in `Function` when enclosing variable in double parenthesis.
+
+
+
+Variable
+--------
+* Refactored `[Input|Output]Variable::[get|set][Input|Output]Value()` to a single value in `Variable::[get|set]Value()`.
+* Refactored `OutputVariable::[is|set]LockedOutputValueInRange()` to its parent `Variable::[is|set]LockValueInRange()`.
+* Added option to lock value in range to input variables by refactoring `OutputVariable::lockValueInRange` to `Variable::lockValueInRange`.
+* Renamed `OutputVariable::[is|set]LockedPreviousValue()` to `OutputVariable::[is|set]LockPreviousValue()`.
+* Added wrapping method `OutputVariable::[get|set]Aggregation()`.
+* For performance improvements, added enum `Variable::Type` and methods `Variable::type()` to indicate whether the variable is of `Type::InputVariable` or `Type::OutputVariable`. Thus, it is no longer necessary to `dynamic_cast` variables to find out whether they are input or output variables.
+
+
+
+Benchmark
+---------
+* Benchmark the time it takes your engine to perform a given number of evaluations (available only when building using C++11) over a given number of independent runs.
+* Measure the accuracy of the engine using the mean squared error between the obtained values and the expected values.
+* Export the benchmark results to text.
+
+Complexity
+----------
+* New complexity methods in the components involved in the operation of an engine.
+* Complexity methods are completely decoupled from the operation of an engine, so they do not affect the performance of the engines.
+
+Console
+-------
+* Benchmark engines from the FuzzyLite Console
+* Hybrid example in Console
+
+Engine
+------
+* Description string for Engine
+* Changed signature of `::configure(TNorm* conjunction, SNorm* disjunction, TNorm* activation, SNorm* accumulation, int resolution)` to `::configure(TNorm* conjunction, SNorm* SNorm* disjunction, TNorm* implication, SNorm* aggregation, Activation* activation)`, where `implication` and `aggregation` are better names for activation and accumulation (respectively), and the `activation` refers to an activation method (see Activation Methods)
+
+Exception.h
+-----------
+* Definition FL_BACKTRACE_OFF in Exception.cpp renamed to FL_BACKTRACE, hence functionality is changed.
+
+fuzzylite.h
+-----------
+* Removed definitions FL_VERSION, FL_DATE from fuzzylite.h
+* Renamed fuzzylite::debug() to fuzzylite::isDebugging()
+* Renamed fuzzylite::logging() to fuzzylite::isLogging()
+* Inlined methods of fuzzylite.h
+* Removed definition `FL_CPP11` and replaced it for `FL_CPP98`. By default, `FL_CPP98` is not defined, hence building using `C++11`.
+
+
+Examples
+--------
+* New example of hybrid engines.
+* New example on obstacle avoidance for Mamdani, Takagi-Sugeno, and Hybrid engines.
+* New R scripts for each example and its respective surfaces in `pdf` formats.
+* Updated examples to use the new properties `InputVariable::lock-range`, `Engine::description`, `[Input|Output]Variable::description`, `RuleBlock::description`, `RuleBlock::implication`, `RuleBlock::activation`, and `OutputVariable::aggregation`.
+* Updated C++ and Java examples to reflect variable names instead of generic names.
+
+
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a0453
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,621 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..99a11d1
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+FROM ubuntu:latest
+MAINTAINER Juan Rada-Vilela <jcrada@fuzzylite.com>
+
+ARG CXX_COMPILER=g++
+ENV CXX_COMPILER ${CXX_COMPILER}
+
+
+#install software-properties-common to use add-apt to add repository for g++-6
+RUN apt-get update && apt-get -y install software-properties-common && \
+ add-apt-repository ppa:ubuntu-toolchain-r/test && \
+ apt-get update && apt-get -y install \
+ ${CXX_COMPILER} \
+ make \
+ cmake \
+ doxygen \
+ graphviz
+
+#Create and copy Docker's context into /build
+RUN mkdir /build
+ADD . /build
+WORKDIR /build/fuzzylite
+ENTRYPOINT [ "/build/fuzzylite/build.sh" ] \ No newline at end of file
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..84978af
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2397 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "fuzzylite"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = 6.0
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "A Fuzzy Logic Control Library in C++"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO = fuzzylite.svg
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = documentation/
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = YES
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = fuzzylite/fl README.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd,
+# *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = examples/mamdani examples/takagi-sugeno examples/tsukamoto
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *.fll *.fld *.cpp *.java *.fis *.fcl *.R
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH = documentation/ui/figure/ documentation/ui/image
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = documentation/ui/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = documentation/ui/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = documentation/ui/stylesheet.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+
+HTML_EXTRA_FILES = README.md \
+ documentation/ui/image/browserconfig.xml \
+ documentation/ui/image/manifest.json \
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "FuzzyLite Documentation"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = com.fuzzylite
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = com.fuzzylite.documentation
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = FuzzyLite Limited
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =fuzzylite-6.0.chm
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE = fuzzylite.qch
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = com.fuzzylite
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = com.fuzzylite.documentation
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 14
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = YES
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest/
+# The path should be set to ./MathJax, but there is no way to use it in Doxygen
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES ={amsmath}
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+#@TODO: YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+#@TODO: YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+#@TODO: YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+#@TODO: YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = YES
+#@TODO: YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 15
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = YES
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+#@TODO: YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+#@TODO: YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+#@TODO: YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+#@TODO: YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 500
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..856303e
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,32 @@
+INSTALL
+=======
+
+(1) Make sure you uninstall previous versions of fuzzylite from your computer.
+
+(2) The following building script is available in folder `fuzzylite/fuzzylite/`:
+```
+#In Windows,
+> build.bat help
+Usage: build.bat [options]
+where [options] can be any of the following:
+ all builds fuzzylite in debug and release mode (default)
+ debug builds fuzzylite in debug mode
+ release builds fuzzylite in release mode
+ clean erases previous builds
+ help shows this information
+
+#In Unix, from fuzzylite/fuzzylite
+$ ./build.sh help
+Usage: [bash] ./build.sh [options]
+where [options] can be any of the following:
+ all builds fuzzylite in debug and release mode (default)
+ debug builds fuzzylite in debug mode
+ release builds fuzzylite in release mode
+ clean erases previous builds
+ help shows this information
+```
+
+(3) After executing the script, the binaries will be built and stored in sub-folders `release/bin` and `debug/bin`
+
+
+For more advanced building options, please check the contents of `fuzzylite/fuzzylite/build.[bat|sh]` and the contents of `fuzzylite/fuzzylite/CMakeLists.txt`.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/LICENSE.FuzzyLite b/LICENSE.FuzzyLite
new file mode 100644
index 0000000..9477af6
--- /dev/null
+++ b/LICENSE.FuzzyLite
@@ -0,0 +1,634 @@
+FuzzyLite License
+Version 1.0, March 2017
+http://www.fuzzylite.com/license
+
+GENERAL
+=======
+The FuzzyLite Libraries, namely fuzzylite and jfuzzylite, both in version 6.0, are licensed under the GNU General Public License version 3.
+
+GNU General Public License
+--------------------------
+
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..a339cce
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,52 @@
+Version 6.0
+===========
+
+Overview
+--------
+* The FuzzyLite Libraries, namely fuzzylite and jfuzzylite, both in version 6.0, are licensed under the GNU General Public License version 3.
+
+* By default, fuzzylite builds using C++11 instead of C++98.
+
+* Important performance improvements.
+
+* Refactored the following names for the operation of engines: from activation operator to implication operator, from accumulation operator to aggregation operator.
+
+* Renamed the term `Accumulated` to `Aggregated`.
+
+* New activation methods decouple the activation of rules from the rule block and provide different methods for activating rules (see Activation Methods).
+
+* New class `ActivationFactory` provides a factory of activation methods.
+
+* New class `Benchmark` to evaluate the performance and accuracy of engines.
+
+* New class `Complexity` to estimate the computational complexity of an engine.
+
+* New class `RScriptExporter` to export the surfaces of an engine using the `ggplot2` library.
+
+* New class `BinaryTerm` for binary edges.
+
+* New `UnboundedSum` S-Norm in `SNormFactory`.
+
+* New classes `SNormFunction` and `TNormFunction` to create custom functions on any two values using the `Function` class.
+
+* Added description strings to `Engine`, `Variable` and `RuleBlock`
+
+* Privatized previously protected members of classes and subclasses of `Term`, `Variable`, `Rule`, `Defuzzifier`, `[Cloning|Construction]Factory`, `Importer`, `Exporter`, amongst others.
+
+* Improved portability by replacing `int` for `std::size_t` where necessary, thereby additionally removing warnings in Windows 64bit
+
+* Deleted `Operation.cpp` and inlined its methods into `Operation.h`
+
+* Updated `.travis.yml` to use Docker, and build using g++ (versions 6, 5, 4.9, 4.8, 4.7) and clang (versions 3.8, 3.7, 3.6, and 3.5).
+
+* Added `appveyor.yml` to use continuous integration in Windows under Visual Studio 2013 and 2015.
+
+* Added some unit tests and support for future unit tests.
+
+* Bug fixes.
+
+* New example of hybrid engines.
+
+* New example on obstacle avoidance for Mamdani, Takagi-Sugeno, and Hybrid engines.
+
+* New R scripts for each example and its respective surfaces in `pdf` formats. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0453b8a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,457 @@
+fuzzylite 6.0 &reg;
+=================
+<img src="https://raw.githubusercontent.com/fuzzylite/fuzzylite/release/fuzzylite.png" align="right" alt="fuzzylite">
+
+
+A Fuzzy Logic Control Library in C++
+------------------------------------
+
+By: [Juan Rada-Vilela](http://www.fuzzylite.com/jcrada), Ph.D.
+
+Released: 20/March/2017
+
+[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0)
+[![Build Status](https://travis-ci.org/fuzzylite/fuzzylite.svg?branch=release)](https://travis-ci.org/fuzzylite/fuzzylite)
+[![Build status](https://ci.appveyor.com/api/projects/status/065g596yxdhkt2se/branch/release)](https://ci.appveyor.com/project/jcrada/fuzzylite/branch/release)
+[![Coverity Status](https://scan.coverity.com/projects/5759/badge.svg)](https://scan.coverity.com/projects/5759)
+
+
+***
+
+
+### Table of Contents
+[License](#license) <br/>
+[Introduction](#introduction)<br/>
+[Features](#features)<br/>
+[Example](#example) <br/>
+[Compile, Link, and Execute](#compile-build-execute)<br/>
+[Bulding from Source](#building)<br/>
+[Binaries](#binaries) <br/>
+[What's new](#whatsnew)<br/>
+[What's next](#whatsnext) <br/>
+
+
+
+
+***
+
+### <a name="license">License</a>
+`fuzzylite 6.0` is licensed under the [**GNU General Public License (GPL) 3.0**](https://www.gnu.org/licenses/gpl.html). You are **strongly** encouraged to support the development of the FuzzyLite Libraries by purchasing a license of [`QtFuzzyLite 6`](http://www.fuzzylite.com/downloads).
+
+[`QtFuzzyLite 6`](http://www.fuzzylite.com/downloads/) is the new and (very likely) the best graphical user interface available to easily design and directly operate fuzzy logic controllers in real time. Available for Windows, Mac, and Linux, its goal is to significantly **speed up** the design of your fuzzy logic controllers, while providing a very **useful**, **functional** and **beautiful** user interface.
+Please, download it and check it out for free at [www.fuzzylite.com/downloads/](http://www.fuzzylite.com/downloads/).
+
+***
+
+
+### <a name="introduction">Introduction</a>
+
+
+`fuzzylite` is a free and open-source fuzzy logic control library programmed in C++ for multiple platforms (e.g., Windows, Linux, Mac, iOS). [`jfuzzylite`](https://github.com/fuzzylite/jfuzzylite/) is the equivalent library for Java and Android platforms. Together, they are the FuzzyLite Libraries for Fuzzy Logic Control.
+
+<center>
+```
+The goal of the FuzzyLite Libraries is to easily design and efficiently operate fuzzy logic controllers following an object-oriented programming model without relying on external libraries.
+```
+</center>
+
+#### Reference
+If you are using the FuzzyLite Libraries, please cite the following reference in your article:
+
+Juan Rada-Vilela. fuzzylite: a fuzzy logic control library, 2017. URL http://www.fuzzylite.com/.
+
+```bibtex
+ @misc{fl::fuzzylite,
+ author={Juan Rada-Vilela},
+ title={fuzzylite: a fuzzy logic control library},
+ url={http://www.fuzzylite.com/},
+ year={2017}}
+```
+
+#### Documentation
+The documentation for the `fuzzylite` library is available at: [www.fuzzylite.com/documentation/](http://www.fuzzylite.com/documentation/).
+
+***
+
+### <a name="features">Features</a>
+
+**(6) Controllers**: Mamdani, Takagi-Sugeno, Larsen, Tsukamoto, Inverse Tsukamoto, Hybrids
+
+**(21) Linguistic terms**: (4) *Basic*: triangle, trapezoid, rectangle, discrete.
+(9) *Extended*: bell, cosine, gaussian, gaussian product, pi-shape, sigmoid difference, sigmoid product, spike.
+(5) *Edges*: binary, concave, ramp, sigmoid, s-shape, z-shape.
+(3) *Functions*: constant, linear, function.
+
+**(7) Activation methods**: general, proportional, threshold, first, last, lowest, highest.
+
+**(8) Conjunction and Implication (T-Norms)**: minimum, algebraic product, bounded difference, drastic product, einstein product, hamacher product, nilpotent minimum, function.
+
+**(10) Disjunction and Aggregation (S-Norms)**: maximum, algebraic sum, bounded sum, drastic sum, einstein sum, hamacher sum, nilpotent maximum, normalized sum, unbounded sum, function.
+
+**(7) Defuzzifiers**: (5) *Integral*: centroid, bisector, smallest of maximum, largest of maximum, mean of maximum.
+(2) *Weighted*: weighted average, weighted sum.
+
+**(7) Hedges**: any, not, extremely, seldom, somewhat, very, function.
+
+**(3) Importers**: FuzzyLite Language `fll`, Fuzzy Inference System `fis`, Fuzzy Control Language `fcl`.
+
+**(7) Exporters**: `C++`, `Java`, FuzzyLite Language `fll`, FuzzyLite Dataset `fld`, `R` script, Fuzzy Inference System `fis`, Fuzzy Control Language `fcl`.
+
+**(30+) Examples** of Mamdani, Takagi-Sugeno, Tsukamoto, and Hybrid controllers from `fuzzylite`, Octave, and Matlab, each included in the following formats: `C++`, `Java`, `fll`, `fld`, `R`, `fis`, and `fcl`.
+
+
+
+
+***
+
+### <a name="example">Example</a>
+#### FuzzyLite Language
+```yaml
+#File: ObstacleAvoidance.fll
+Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: mSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+RuleBlock: mamdani
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: AlgebraicProduct
+ activation: General
+ rule: if obstacle is left then mSteer is right
+ rule: if obstacle is right then mSteer is left
+```
+```cpp
+//File: ObstacleAvoidance.cpp
+#include "fl/Headers.h"
+
+int main(int argc, char* argv[]){
+ using namespace fl;
+ Engine* engine = FllImporter().fromFile("ObstacleAvoidance.fll");
+
+ std::string status;
+ if (not engine->isReady(&status))
+ throw Exception("[engine error] engine is not ready:\n" + status, FL_AT);
+
+ InputVariable* obstacle = engine->getInputVariable("obstacle");
+ OutputVariable* steer = engine->getOutputVariable("mSteer");
+
+ for (int i = 0; i <= 50; ++i){
+ scalar location = obstacle->getMinimum() + i * (obstacle->range() / 50);
+ obstacle->setValue(location);
+ engine->process();
+ FL_LOG("obstacle.input = " << Op::str(location) <<
+ " => " << "steer.output = " << Op::str(steer->getValue()));
+ }
+}
+```
+
+#### C++
+```cpp
+//File: ObstacleAvoidance.cpp
+#include "fl/Headers.h"
+
+int main(int argc, char* argv[]){
+ using namespace fl;
+ //Code automatically generated with fuzzylite 6.0.
+
+ using namespace fl;
+
+ Engine* engine = new Engine;
+ engine->setName("ObstacleAvoidance");
+ engine->setDescription("");
+
+ InputVariable* obstacle = new InputVariable;
+ obstacle->setName("obstacle");
+ obstacle->setDescription("");
+ obstacle->setEnabled(true);
+ obstacle->setRange(0.000, 1.000);
+ obstacle->setLockValueInRange(false);
+ obstacle->addTerm(new Ramp("left", 1.000, 0.000));
+ obstacle->addTerm(new Ramp("right", 0.000, 1.000));
+ engine->addInputVariable(obstacle);
+
+ OutputVariable* mSteer = new OutputVariable;
+ mSteer->setName("mSteer");
+ mSteer->setDescription("");
+ mSteer->setEnabled(true);
+ mSteer->setRange(0.000, 1.000);
+ mSteer->setLockValueInRange(false);
+ mSteer->setAggregation(new Maximum);
+ mSteer->setDefuzzifier(new Centroid(100));
+ mSteer->setDefaultValue(fl::nan);
+ mSteer->setLockPreviousValue(false);
+ mSteer->addTerm(new Ramp("left", 1.000, 0.000));
+ mSteer->addTerm(new Ramp("right", 0.000, 1.000));
+ engine->addOutputVariable(mSteer);
+
+ RuleBlock* mamdani = new RuleBlock;
+ mamdani->setName("mamdani");
+ mamdani->setDescription("");
+ mamdani->setEnabled(true);
+ mamdani->setConjunction(fl::null);
+ mamdani->setDisjunction(fl::null);
+ mamdani->setImplication(new AlgebraicProduct);
+ mamdani->setActivation(new General);
+ mamdani->addRule(Rule::parse("if obstacle is left then mSteer is right", engine));
+ mamdani->addRule(Rule::parse("if obstacle is right then mSteer is left", engine));
+ engine->addRuleBlock(mamdani);
+
+ std::string status;
+ if (not engine->isReady(&status))
+ throw Exception("[engine error] engine is not ready:\n" + status, FL_AT);
+
+ for (int i = 0; i <= 50; ++i){
+ scalar location = obstacle->getMinimum() + i * (obstacle->range() / 50);
+ obstacle->setValue(location);
+ engine->process();
+ FL_LOG("obstacle.input = " << Op::str(location) <<
+ " => " << "steer.output = " << Op::str(steer->getValue()));
+ }
+}
+```
+
+### <a name="compile-build-execute">Compile, Link, and Execute</a>
+
+Once you have an engine written in C++, you can compile it to create an executable file which links to the `fuzzylite` library. The linking can be either static or dynamic. Basically, the differences between static and dynamic linking are the following. **Static linking** includes the `fuzzylite` library into your executable file, hence increasing its size, but the executable no longer needs to have access to the `fuzzylite` library files. **Dynamic linking** does not include the `fuzzylite` library into your executable file, hence reducing its size, but the executable needs to have access to the `fuzzylite` shared library file. When using dynamic linking, make sure that the shared library files are either in the same directory as the executable, or are reachable via environmental variables:
+
+```posh
+rem Windows:
+set PATH="\path\to\fuzzylite\release\bin;%PATH%"
+```
+```bash
+#Unix:
+export LD_LIBRARY_PATH="/path/to/fuzzylite/release/bin/:$LD_LIBRARY_PATH"
+```
+
+#### Windows
+The commands to compile your engine in Windows are the following:
+
+C++11 (default)
+```posh
+rem static linking:
+cl.exe ObstacleAvoidance.cpp fuzzylite-static.lib /Ipath/to/fuzzylite /EHsc /MD
+```
+```posh
+rem dynamic linking:
+cl.exe ObstacleAvoidance.cpp fuzzylite.lib /Ipath/to/fuzzylite /DFL_IMPORT_LIBRARY /EHsc /MD
+```
+
+C++98
+```posh
+rem static linking:
+cl.exe ObstacleAvoidance.cpp fuzzylite-static.lib /Ipath/to/fuzzylite /DFL_CPP98=ON /EHsc /MD
+```
+```posh
+rem dynamic linking:
+cl.exe ObstacleAvoidance.cpp fuzzylite.lib /Ipath/to/fuzzylite /DFL_IMPORT_LIBRARY /DFL_CPP98=ON /EHsc /MD
+```
+
+#### Unix
+The commands to compile your engine in Unix are the following:
+
+C++11 (default)
+```bash
+#static linking
+g++ ObstacleAvoidance.cpp -o ObstacleAvoidance -I/path/to/fuzzylite -L/path/to/fuzzylite/release/bin -lfuzzylite-static --std=c++11
+```
+```bash
+#dynamic linking
+g++ ObstacleAvoidance.cpp -o ObstacleAvoidance -I/path/to/fuzzylite -L/path/to/fuzzylite/release/bin -lfuzzylite -Wno-non-literal-null-conversion
+```
+
+C++98
+```bash
+#static linking
+g++ ObstacleAvoidance.cpp -o ObstacleAvoidance -I/path/to/fuzzylite -L/path/to/fuzzylite/release/bin -lfuzzylite-static -DFL_CPP98=ON
+```
+```bash
+#dynamic linking
+g++ ObstacleAvoidance.cpp -o ObstacleAvoidance -I/path/to/fuzzylite -L/path/to/fuzzylite/release/bin -lfuzzylite -DFL_CPP98=ON -Wno-non-literal-null-conversion
+```
+
+#### CMake
+Alternatively, you can use CMake to build your project linking to `fuzzylite`. Please, refer to the example application available at [examples/application]([/examples/application]).
+
+
+
+***
+
+
+### <a name="building">Building from Source</a>
+You can build the `fuzzylite` library from source using `CMake` [(cmake.org)](https://cmake.org/).
+
+The files [`fuzzylite/build.bat`](/fuzzylite/build.bat) and [`fuzzylite/build.sh`](/fuzzylite/build.sh) are build scripts for the Windows and Unix platforms, respectively.
+After building from source, the resulting binaries will be located in the sub-folders `fuzzylite/release/bin` and `fuzzylite/debug/bin`. The usage of these scripts is presented as follows.
+
+#### Windows
+```bash
+> build.bat help
+Usage: build.bat [options]
+where [options] can be any of the following:
+ all builds fuzzylite in debug and release mode (default)
+ debug builds fuzzylite in debug mode
+ release builds fuzzylite in release mode
+ clean erases previous builds
+ help shows this information
+```
+
+#### Unix
+```bash
+$ ./build.sh help
+Usage: [bash] ./build.sh [options]
+where [options] can be any of the following:
+ all builds fuzzylite in debug and release mode (default)
+ debug builds fuzzylite in debug mode
+ release builds fuzzylite in release mode
+ clean erases previous builds
+ help shows this information
+```
+
+
+
+#### Building Options
+For advanced building options, please check the contents of [`fuzzylite/build.bat`](/fuzzylite/build.bat) or [`fuzzylite/build.sh`](/fuzzylite/build.sh), and the contents of [`fuzzylite/CMakeLists.txt`](/fuzzylite/CMakeLists.txt).
+
+The following building options available:
+
+* `-DFL_USE_FLOAT=ON` builds the binaries utilizing the `fl::scalar` data type as a `float` represented in 4 bytes. By default, the binaries are built utilizing `-DFL_USE_FLOAT=OFF` to utilize `fl::scalar` as a `double` represented in 8 bytes and hence providing better accuracy. If `fuzzylite` is built with `-DFL_USE_FLOAT=ON`, then the applications linking to `fuzzylite` also need to specify this compilation flag.
+
+
+* `-DFL_CPP98=ON` builds binaries utilizing `C++98` features. By default, `fuzzylite` is built with `-DFL_CPP98=OFF` to utilize `C++11` features. If compiling for `C++98`, be aware that you will not be able to benchmark the performance of your engine using the `Benchmark` class.
+
+
+* `-DFL_BACKTRACE=OFF` disables the backtrace information in case of errors (default is ON). In Windows, the backtrace information requires the external library `dbghelp`, which is generally available in your system.
+
+* `-DCMAKE_BUILD_TYPE=[Debug|Release]` sets the mode of your build. You can only build one mode at a time with a single CMake script.
+
+
+#### Documentation
+The source code of `fuzzylite` is very well documented using [`doxygen`](www.doxygen.org/) formatting, and the documentation is available at [fuzzylite.com/documentation](http://fuzzylite.com/documentation). If you want to generate the documentation locally, you can produce the `html` documentation from the file [Doxyfile](/Doxyfile) using the command line: `doxygen Doxyfile`. The documentation will be created in the [`documentation`](/documentation) folder.
+
+
+
+***
+
+### <a name="binaries">Binaries</a>
+
+After building from source, the following are the relevant binaries that will be created in `Release` mode. In `Debug` mode, the file names end with `-debug` (e.g., `fuzzylite-debug.exe`).
+
+#### Windows
+
+- console application: `fuzzylite.exe`
+- shared library: `fuzzylite.dll`, `fuzzylite.lib`
+- static library: `fuzzylite-static.lib`
+
+#### Linux
+
+- console application: `fuzzylite`
+- shared library: `libfuzzylite.so`
+- static library: `libfuzzylite-static.a`
+
+#### Mac
+
+- console application: `fuzzylite`
+- shared library: `libfuzzylite.dylib`
+- static library: `libfuzzylite-static.a`
+
+
+#### Console
+The console application of `fuzzylite` allows you to import and export your engines. Its usage can be obtained executing the console binary. In addition, the console can be set in interactive mode. The `FuzzyLite Interactive Console` allows you to evaluate a given controller by manually providing the input values. The interactive console is triggered by specifying an input file and an output format. For example, to interact with the `ObstacleAvoidance` controller, the interactive console is launched as follows:
+
+```bash
+fuzzylite -i ObstacleAvoidance.fll -of fld
+```
+
+
+
+***
+
+### <a name="whatsnew">What's New?</a>
+* The FuzzyLite Libraries, namely fuzzylite and jfuzzylite, both in version 6.0, are dual licensed under the GNU General Public License version 3 and the Apache License version 2.
+
+* By default, fuzzylite builds using C++11 instead of C++98.
+
+* Important performance improvements.
+
+* Refactored the following names for the operation of engines: from activation operator to implication operator, from accumulation operator to aggregation operator.
+
+* Renamed the term `Accumulated` to `Aggregated`.
+
+* New activation methods decouple the activation of rules from the rule block and provide different methods for activating rules (see Activation Methods).
+
+* New class `ActivationFactory` provides a factory of activation methods.
+
+* New class `Benchmark` to evaluate the performance and accuracy of engines.
+
+* New class `Complexity` to estimate the computational complexity of an engine.
+
+* New class `RScriptExporter` to export the surfaces of an engine using the `ggplot2` library.
+
+* New class `Binary` term for binary edges.
+
+* New `UnboundedSum` S-Norm in `SNormFactory`.
+
+* New classes `SNormFunction` and `TNormFunction` to create custom functions on any two values using the `Function` class.
+
+* Added description strings to `Engine`, `Variable` and `RuleBlock`
+
+* Privatized previously protected members of classes and subclasses of `Term`, `Variable`, `Rule`, `Defuzzifier`, `[Cloning|Construction]Factory`, `Importer`, `Exporter`, amongst others.
+
+* Improved portability by replacing `int` for `std::size_t` where necessary, thereby additionally removing warnings in Windows 64bit
+
+* Deleted `Operation.cpp` and inlined its methods into `Operation.h`
+
+* Updated `.travis.yml` to use Docker, and build using g++ (versions 6, 5, 4.9, 4.8, 4.7) and clang (versions 3.8, 3.7, 3.6, and 3.5).
+
+* Added `appveyor.yml` to use continuous integration in Windows under Visual Studio 2013 and 2015.
+
+* Added some unit tests and support for future unit tests.
+
+* Bug fixes.
+
+* New example of hybrid engines.
+
+* New example on obstacle avoidance for Mamdani, Takagi-Sugeno, and Hybrid engines.
+
+* New R scripts for each example and its respective surfaces in `pdf` formats.
+
+#### Bug fixes
+* Fixed bug in `CloningFactory::deregisterObject()`. Bug: Object was deleted before removing it from the map, leaving an invalid object in the map which would cause a segmentation fault. Solution: Remove the object from the map before deleting it.
+* Fixed bug causing segmentation fault when malformed term in FuzzyLite Language
+* Fixed bug computing the `NormalizedSum` S-Norm.
+* Fixed bug in `RuleBlock` to reset and clone the implication operator. Bug: implication operator is not copied and reset. Fix: copy and reset implication operator when cloning the `RuleBlock`.
+* Fixed bug in `Function` term. Bug: given a formula = "tan(y)" and a map["y"] = 1.0, and executing `Function::load(formula)`, then the map of variables is reset because `load()` calls `unload()` first, causing the deregistration of variable `y`. Solution: Removed method `unload()` from `load()`, thereby causing future `load()` not to reset variables.
+* Fixed bug in `Function` when enclosing variable in double parenthesis.
+
+
+***
+
+### <a name="whatsnext">What's Next?</a>
+
++ Optimization of Fuzzy Logic Controllers
++ Type-2 Fuzzy Logic Controllers
++ Adaptive Neuro-Fuzzy Inference System (ANFIS)
++ Fuzzy C-means data clustering
+
+***
+
+fuzzylite&reg; is a registered trademark of FuzzyLite Limited.<br>
+jfuzzylite&trade; is a trademark of FuzzyLite Limited.<br>
+QtFuzzyLite&trade; is a trademark of FuzzyLite Limited.<br>
+
+
+Copyright &#xa9; 2010-2017 FuzzyLite Limited. All rights reserved.
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..df56bb0
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,22 @@
+Acknowledgements
+================
+
+Thank you to the community around fuzzylite, whose feedback and support has been of great importance towards improving the libraries.
+
+Thank you to all the users who made generous contributions buying licenses of QtFuzzyLite and making donations.
+
+Thank you to the European Centre for Soft Computing, the Foundation for the Advancement of Soft Computing, Sergio Guadarrama and Luis Magdalena for their support creating the first version of fuzzylite.
+
+Thank you to Dean Morrissey for his feedback on testing the operation of fuzzylite and validating its results; Adrien Cabarbaye for his feedback on discrete terms and feature requests on output variables; Massimo Canonico for his feedback on his experience and usage of fuzzylite in its early stages; Eva Millan for her feedback, ideas, and suggestions on rule chaining; Johannes Schauer for his work making fuzzylite directly available from Debian repositories; and Leonela Gazzano for her suggestions on activation methods.
+
+Thank you to Pablo Cingolani (JFuzzyLogic), Linda Markowsky (Octave Fuzzy Logic Toolkit), Roger Jang (Matlab Fuzzy Logic Toolbox), Edward S. Sazonov (FuzzyEngine), and their respective collaborators for open sourcing their great libraries.
+
+Special thanks to Mengjie Zhang and Mark Johnston (Victoria University of Wellington, New Zealand); Oscar Cordón (European Centre for Soft Computing, Spain); Maritza Bracho, Carlos Lameda, Belkys Lameda, and Rubén Parma (Universidad Centroccidental Lisandro Alvarado, Venezuela); and Yelitza Oviedo, Jorge Rodríguez, Edecio Freitez, Luis Alvarado, Jesús Contreras, and Oswaldo Hernández (Universidad Fermín Toro, Venezuela).
+
+Thank you all very much.
+
+Yours,
+
+Juan Rada-Vilela, Ph.D.
+jcrada@fuzzylite.com
+http://www.fuzzylite.com/jcrada \ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..b052265
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,40 @@
+version: '{branch}.{build}'
+branches:
+ only:
+ - master
+ - release
+os:
+- Visual Studio 2015
+- Visual Studio 2013
+configuration:
+- Release
+- Debug
+platform:
+- x64
+- x86
+clone_depth: 1
+clone_folder: C:\projects\fuzzylite
+before_build:
+- cmd: >-
+ cd c:\projects\fuzzylite\fuzzylite
+
+ mkdir build
+
+ cd build
+
+ cmake ..
+
+ echo %cd%
+
+ dir
+build:
+ project: c:\projects\fuzzylite\fuzzylite\build\INSTALL.vcxproj
+ parallel: true
+ verbosity: normal
+notifications:
+- provider: Email
+ to:
+ - jcrada@fuzzylite.com
+ on_build_success: true
+ on_build_failure: true
+ on_build_status_changed: true \ No newline at end of file
diff --git a/documentation/ui/figure.R b/documentation/ui/figure.R
new file mode 100644
index 0000000..88cef79
--- /dev/null
+++ b/documentation/ui/figure.R
@@ -0,0 +1,491 @@
+library('cowplot')
+library('ggplot2')
+
+theme_set(theme_gray())
+
+
+isEq = function(a,b,error=1e-5){
+ abs(a - b) <= error
+}
+
+isLt = function(a,b,error=1e-5){
+ !isEq(a,b,error) & a < b
+}
+
+isGt = function(a,b,error=1e-5){
+ !isEq(a,b,error) & a > b
+}
+
+isLE = function(a,b,error=1e-5){
+ isEq(a,b,error) | a < b
+}
+
+isGE = function(a,b,error=1e-5){
+ isEq(a,b,error) | a > b
+}
+
+#Scale: Scales a number to a different scale
+Scale = function(value, toMin, toMax, fromMin=min(value), fromMax=max(value)){
+ (toMax - toMin) / (fromMax - fromMin) * (value - fromMin) + toMin
+}
+
+#Basic
+
+term.triangle = function(x, a, b, c){
+ if (isLt(x,a) | isGt(x,c))
+ 0.0
+ else if (isEq(x,b))
+ 1.0
+ else if (isLt(x,b))
+ (x - a) / (b - a)
+ else
+ result = (c - x) / (c - b)
+}
+
+term.trapezoid = function(x,a,b,c,d){
+ if (isLt(x, a) | isGt(x, d))
+ 0.0
+ else if (isLE(x, b))
+ min(1.0, (x - a) / (b - a))
+ else if (isLE(x, c))
+ 1.0
+ else if (isLE(x, d))
+ (d - x) / (d - c)
+}
+
+term.rectangle = function(x,a,b){
+ if (isLt(x, a) | isGt(x,b))
+ 0.0
+ else 1.0
+}
+
+term.discrete = function(x, a, b){
+ diff = b-a
+ if (isLt(x,a) | isGt(x,b))
+ 0.0
+ else if (isLt(x,.25 * diff))
+ Scale(x, 0, 1, a, a + diff*.25)
+ else if (isLt(x, .5*diff))
+ Scale(x,1,0.5, a + diff*.25, a + diff*.5)
+ else if (isLt(x, .75*diff))
+ Scale(x,0.5,1,a+diff*.5, a+diff*.75)
+ else if (isLt(x, diff))
+ Scale(x, 1, 0, a+diff*.75, a+diff)
+ else {0.0}
+# else if (isLt(x, a*.5)
+}
+
+
+term.bell = function(x, center, width, slope){
+ 1.0 / (1.0 + abs((x - center) / width)**(2 * slope));
+}
+
+#EXTENDED
+
+term.cosine = function(x, center, width){
+ if (isLt(x, center-width/2.0) || isGt(x, center+width/2.0)){
+ 0.0
+ }else{
+ 0.5 * (1.0 + cos(2.0 / width * pi * (x - center)))
+ }
+}
+
+term.gaussian = function(x, mean, sd){
+ exp((-(x - mean) * (x - mean)) / (2 * sd * sd));
+}
+
+term.gaussianProduct = function(x, meanA, sdA, meanB, sdB){
+ xLEa = isLE(x, meanA)
+ a = exp((-(x - meanA) * (x - meanA)) / (2 * sdA * sdA)) * xLEa + (1 - xLEa)
+ xGEb = isGE(x, meanB)
+ b = exp((-(x - meanB) * (x - meanB)) / (2 * sdB * sdB)) * xGEb + (1 - xGEb)
+ a * b
+}
+
+term.bell = function(x, center, width, slope){
+ 1.0 / (1.0 + abs((x - center) / width)** (2 * slope))
+}
+
+term.piShape = function(x, bottomLeft, topLeft, topRight, bottomRight){
+ a_b_ave = (bottomLeft + topLeft) / 2.0
+ b_minus_a = topLeft - bottomLeft
+ c_d_ave = (topRight + bottomRight) / 2.0
+ d_minus_c = bottomRight - topRight
+
+ if (isLE(x, bottomLeft)) 0.0
+
+ else if (isLE(x, a_b_ave))
+ 2.0 * ((x - bottomLeft) / b_minus_a) ** 2
+
+ else if (isLt(x, topLeft))
+ 1.0 - 2.0 * ((x - topLeft) / b_minus_a)** 2
+
+ else if (isLE(x, topRight))
+ 1.0
+
+ else if (isLE(x, c_d_ave))
+ 1 - 2 * ((x - topRight) / d_minus_c)**2
+
+ else if (isLt(x, bottomRight))
+ 2 * ((x - bottomRight) / d_minus_c)** 2
+
+ else 0.0
+}
+
+term.sigmoidDifference = function(x, left, rising, falling, right){
+ a = 1.0 / (1 + exp(-rising * (x - left)))
+ b = 1.0 / (1 + exp(-falling * (x - right)))
+ abs(a - b)
+}
+
+term.sigmoidProduct = function(x, left, rising, falling, right){
+ a = 1.0 / (1 + exp(-rising * (x - left)))
+ b = 1.0 / (1 + exp(-falling * (x - right)))
+ abs(a * b)
+}
+
+term.spike = function(x, center, width){
+ exp(-abs( 10 / width * (x-center)))
+}
+
+#EDGES
+
+term.binary = function(x, threshold, direction){
+ if (isGE(direction,0.0) && isGE(x, threshold)){
+ 1.0
+ }else if (isLt(direction, 0.0) && isLE(x, threshold)){
+ 1.0
+ }else{
+ 0.0
+ }
+}
+
+term.concave = function(x, inflection, end){
+ if (isLE(inflection, end)){ #Concave increasing
+ if (isLt(x, end)){
+ (end - inflection) / (2 * end - inflection - x)
+ }else{ 1.0 }
+ } else{ #Concave decreasing
+ if (isGt(x, end)){
+ (inflection - end) / (inflection -2 * end + x)
+ }else{ 1.0 }
+ }
+}
+
+
+term.ramp = function(x, start, end){
+ if (isEq(start, end)) 0.0
+
+ else if (isLt(start, end)) {
+ if (isLE(x, start)) 0.0
+ else if (isGE(x, end)) 1.0
+ else (x - start) / (end - start)
+ } else {
+ if (isGE(x, start)) 0.0
+ else if (isLE(x, end)) 1.0
+ else (start - x) / ( start - end)
+ }
+}
+
+term.sigmoid = function(x, inflection, slope){
+ 1.0 / (1.0 + exp(-slope * (x - inflection)))
+}
+
+term.sShape = function(x, start, end){
+ average = (start + end) / 2
+ difference = end - start
+
+ if (isLE(x, start)) 0.0
+
+ else if (isLE(x, average))
+ 2 * ((x - start) / difference) ** 2
+
+ else if (isLt(x, end))
+ 1.0 - 2.0 * ((x - end) / difference) ** 2
+ else 1.0
+}
+
+term.zShape = function(x, start, end){
+ average = (start + end) / 2
+ difference = end - start
+
+ if (isLE(x, start)) 1.0
+
+ else if (isLE(x, average))
+ 1.0 - 2.0 * ((x - start) / difference) ** 2
+
+ else if (isLt(x, end))
+ 2.0 * ((x - end) / difference)** 2
+
+ else 0.0
+}
+
+
+
+
+
+
+
+x = seq(0,1,length=500)
+average = (max(x) + min(x))/2
+diff = (max(x) - min(x))
+
+
+
+
+
+dir.create('figure',showWarnings=F)
+
+
+##################BASIC
+
+triangle.df = data.frame(x, y=sapply(x, term.triangle, min(x), average, max(x)))
+triangle.plot = ggplot(triangle.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/triangle.svg', triangle.plot, width=3, height=3)
+
+
+trapezoid.df = data.frame(x, y=sapply(x, term.trapezoid, min(x), min(x) + .25 * diff, min(x) + .75*diff, max(x)))
+trapezoid.plot = ggplot(trapezoid.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/trapezoid.svg', trapezoid.plot, width=3, height=3)
+
+
+rectangle.df = data.frame(x, y=sapply(x, term.rectangle, min(x) + .25*diff, min(x) + .75*diff))
+rectangle.plot = ggplot(rectangle.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/rectangle.svg', rectangle.plot, width=3, height=3)
+
+
+discrete.x = x[c(1, seq(10, 495, 10), 500)]
+discrete.df = data.frame(x=discrete.x, y=sapply(discrete.x, term.discrete, min(x), max(x)))
+discrete.plot = ggplot(discrete.df, aes(x,y, size=2, lineend='round')) + geom_point() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/discrete.svg', discrete.plot, width=3, height=3)
+
+
+
+#################EXTENDED
+
+cosine.df = data.frame(x, y=sapply(x, term.cosine, average, diff))
+cosine.plot = ggplot(cosine.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/cosine.svg', cosine.plot, width=3, height=3)
+
+
+gaussian.df = data.frame(x, y=sapply(x, term.gaussian, average, .2*diff))
+gaussian.plot = ggplot(gaussian.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/gaussian.svg', gaussian.plot, width=3, height=3)
+
+
+gaussianProduct.df = data.frame(x, y=sapply(x, term.gaussianProduct, average+.1, .2*diff, average-.1, .2*diff))
+gaussianProduct.plot = ggplot(gaussianProduct.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/gaussianProduct.svg', gaussianProduct.plot, width=3, height=3)
+
+
+bell.df = data.frame(x, y=sapply(x, term.bell, average, .25*diff, 3.0))
+bell.plot = ggplot(bell.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/bell.svg', bell.plot, width=3, height=3)
+
+
+piShape.df = data.frame(x, y=sapply(x, term.piShape, min(x), average, average, max(x)))
+piShape.plot = ggplot(piShape.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/piShape.svg', piShape.plot, width=3, height=3)
+
+
+sigmoidDifference.df = data.frame(x, y=sapply(x, term.sigmoidDifference, min(x) + .25*diff, 20/diff, 20/diff, min(x)+.75*diff))
+sigmoidDifference.plot = ggplot(sigmoidDifference.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/sigmoidDifference.svg', sigmoidDifference.plot, width=3, height=3)
+
+
+sigmoidProduct.df = data.frame(x, y=sapply(x, term.sigmoidProduct, min(x) + .25*diff, 10/diff, -10/diff, min(x)+.75*diff))
+sigmoidProduct.plot = ggplot(sigmoidProduct.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/sigmoidProduct.svg', sigmoidProduct.plot, width=3, height=3)
+
+
+spike.df = data.frame(x, y=sapply(x, term.spike, average, diff))
+spike.plot = ggplot(spike.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/spike.svg', spike.plot, width=3, height=3)
+
+
+
+###############EDGE
+
+#Binary
+binary.dfa = data.frame(x, y=sapply(x, term.binary, min(x) + .25*diff, -1))
+binary.dfb = data.frame(x, y=sapply(x, term.binary, min(x) + .75*diff, 1))
+binary.plot = ggplot(binary.dfa, aes(x,y, size=2, lineend='round')) +
+ geom_line(data=binary.dfb, aes(x,y, size=2, lineend='round')) +
+ geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/binary.svg', binary.plot, width=3, height=3)
+
+#Concave
+concave.dfa = data.frame(x, y=sapply(x, term.concave, average, max(x)-.2))
+concave.dfb = data.frame(x, y=sapply(x, term.concave, average, 1-(max(x)-.2)))
+concave.plot = ggplot(concave.dfa, aes(x,y, size=2, lineend='round')) +
+ geom_line(data=concave.dfb, aes(x,y, size=2, lineend='round')) +
+ geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/concave.svg', concave.plot, width=3, height=3)
+
+#RAMP
+ramp.dfa = data.frame(x, y=sapply(x, term.ramp, max(x)-.2, min(x)+.2))
+ramp.dfb = data.frame(x, y=sapply(x, term.ramp, min(x)+.2, max(x)-.2))
+ramp.plot = ggplot(ramp.dfa, aes(x,y, size=2, lineend='round')) +
+ geom_line(data=ramp.dfb, aes(x,y, size=2, lineend='round')) +
+ geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/ramp.svg', ramp.plot, width=3, height=3)
+
+
+sigmoid.dfa = data.frame(x, y=sapply(x, term.sigmoid, average, 20/diff))
+sigmoid.dfb = data.frame(x, y=sapply(x, term.sigmoid, average, -20/diff))
+sigmoid.plot = ggplot(sigmoid.dfa, aes(x,y, size=2, lineend='round')) +
+ geom_line(data=sigmoid.dfb, aes(x,y, size=2, lineend='round')) +
+ geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/sigmoid.svg', sigmoid.plot, width=3, height=3)
+
+
+sShape.df = data.frame(x, y=sapply(x, term.sShape, min(x), max(x)))
+sShape.plot = ggplot(sShape.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/sShape.svg', sShape.plot, width=3, height=3)
+
+
+zShape.df = data.frame(x, y=sapply(x, term.zShape, min(x), max(x)))
+zShape.plot = ggplot(zShape.df, aes(x,y, size=2, lineend='round')) + geom_line() + ylab(expression(mu(x))) + theme(legend.position='none')
+ggsave('figure/zShape.svg', zShape.plot, width=3, height=3)
+
+
+##############Terms
+
+ constant.plot =
+ ggplot(data=data.frame(x=0,y=0)) +
+ geom_point(aes(x=0,y=0), size=0) +
+ ylab(expression(f(x))) + xlab('x') +
+ coord_cartesian(ylim = c(-0.05, 1.05), xlim=c(-0.05,1.05)) +
+ annotate('text', x = .5, y = .5, label = "f(x)==k", parse = T,size=10)
+
+ linear.plot =
+ ggplot(data=data.frame(x=0,y=0)) +
+ geom_point(aes(x=0,y=0), size=0) +
+ ylab(expression(f(x))) + xlab('x') +
+ coord_cartesian(ylim = c(-0.05, 1.05), xlim=c(-0.05,1.05)) +
+ annotate('text', x = .5, y = .5, angle=45, label = "f(x)==sum(paste(c[i],v[i]), i)+k", parse = T,size=10)
+
+ function.plot =
+ ggplot(data=data.frame(x=0,y=0)) +
+ geom_point(aes(x=0,y=0), size=0) +
+ ylab(expression(f(x))) + xlab('x') +
+ coord_cartesian(ylim = c(-0.05, 1.05), xlim=c(-0.05,1.05)) +
+ annotate('text', x = .5, y = .5, label = "f:x %->% f(x)", parse = T,size=10)
+
+
+########## Vertical layout
+ terms.grid = plot_grid(
+
+triangle.plot, bell.plot, piShape.plot,
+trapezoid.plot, cosine.plot, sigmoidDifference.plot,
+rectangle.plot, gaussian.plot, sigmoidProduct.plot,
+discrete.plot, gaussianProduct.plot, spike.plot,
+binary.plot, ramp.plot, sShape.plot,
+concave.plot, sigmoid.plot, zShape.plot,
+function.plot, linear.plot, constant.plot,
+
+ ncol=3, nrow=7, scale=1, label_size=12, vjust=1.25, align='v',
+ #hjust=.5, # align='hv',
+
+ labels=c(
+'Triangle', 'Bell', 'PiShape',
+'Trapezoid', 'Cosine', 'SigmoidDifference',
+'Rectangle', 'Gaussian', 'SigmoidProduct',
+'Discrete', 'GaussianProduct', 'Spike',
+'Binary', 'Ramp', 'SShape',
+'Concave', 'Sigmoid', 'ZShape',
+'Function', 'Linear', 'Constant'
+ )
+ )
+
+ save_plot('figure/terms.svg', terms.grid, ncol=3, nrow=7, scale=.75)
+
+ stop('Script successfully executed')
+
+
+##########Horizontal layout
+ terms.grid = plot_grid(
+
+ triangle.plot, trapezoid.plot, rectangle.plot, discrete.plot, function.plot, binary.plot , concave.plot,
+
+ bell.plot, cosine.plot, gaussian.plot, gaussianProduct.plot, linear.plot, ramp.plot, sigmoid.plot,
+
+ piShape.plot, sigmoidDifference.plot, sigmoidProduct.plot, spike.plot, constant.plot, sShape.plot, zShape.plot,
+
+ ncol=7, nrow=3, scale=1, label_size=12, vjust=1.25, align='v',
+ #hjust=.5, # align='hv',
+
+labels=c(
+'Triangle', 'Trapezoid', 'Rectangle', 'Discrete', 'Function', 'Binary', 'Concave',
+'Bell', 'Cosine', 'Gaussian', 'GaussianProduct', 'Linear', 'Ramp', 'Sigmoid',
+'PiShape', 'SigmoidDifference', 'SigmoidProduct','Spike', 'Constant', 'SShape', 'ZShape')
+)
+
+save_plot('figure/terms.svg', terms.grid, ncol=7, nrow=3, scale=.75)
+
+stop('Script successfully executed')
+
+
+
+
+
+
+
+
+
+
+
+
+# X1234X
+# 123456
+# 7 8
+# 123456
+
+constant.plot =
+ ggplot(data=data.frame(x=0,y=0)) +
+ geom_point(aes(x=0,y=0), size=0) +
+ ylab(expression(mu(x))) + xlab('x') +
+ coord_cartesian(ylim = c(-0.05, 1.05), xlim=c(-0.05,1.05)) +
+ annotate('text', x = .5, y = .5, label = "mu(x)==k", parse = T,size=10)
+
+linear.plot =
+ ggplot(data=data.frame(x=0,y=0)) +
+ geom_point(aes(x=0,y=0), size=0) +
+ ylab(expression(mu(x))) + xlab('x') +
+ coord_cartesian(ylim = c(-0.05, 1.05), xlim=c(-0.05,1.05)) +
+ annotate('text', x = .5, y = .5, angle=45, label = "mu(x)==sum(c[i] %.% x[i], i)+k", parse = T,size=5)
+
+function.plot =
+ ggplot(data=data.frame(x=0,y=0)) +
+ geom_point(aes(x=0,y=0), size=0) +
+ ylab(expression(mu(x))) + xlab('x') +
+ coord_cartesian(ylim = c(-0.05, 1.05), xlim=c(-0.05,1.05)) +
+ annotate('text', x = .5, y = .5, label = "f:x %->% mu(x)", parse = T,size=5)
+
+
+terms.grid = plot_grid(
+
+NULL, triangle.plot, trapezoid.plot, rectangle.plot, discrete.plot, NULL,
+
+bell.plot, cosine.plot, gaussian.plot, gaussianProduct.plot, piShape.plot, sigmoidDifference.plot,
+
+sigmoidProduct.plot, spike.plot, NULL, constant.plot, linear.plot, function.plot,
+
+binary.plot, concave.plot, ramp.plot, sigmoid.plot, sShape.plot, zShape.plot,
+
+nrow=4, ncol=6, scale=1, label_size=12, vjust=1.25,
+#hjust=.5, # align='hv',
+
+labels=c(
+'', 'Triangle', 'Trapezoid', 'Rectangle', 'Discrete', '',
+'Bell', 'Cosine', 'Gaussian', 'GaussianProduct', 'PiShape', 'SigmoidDifference',
+'SigmoidProduct','Spike', '', 'Constant', 'Linear', 'Function',
+'Binary', 'Concave', 'Ramp', 'Sigmoid', 'SShape', 'ZShape')
+)
+
+save_plot('figure/terms.svg', terms.grid,
+ ncol=6, nrow=4, scale=.5)
+
+
+
+
diff --git a/documentation/ui/figure/bell.svg b/documentation/ui/figure/bell.svg
new file mode 100644
index 0000000..9709cf5
--- /dev/null
+++ b/documentation/ui/figure/bell.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 154 L 202 154 L 202 156 L 54.019531 156 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 116 L 202 116 L 202 118 L 54.019531 118 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 78 L 202 78 L 202 80 L 54.019531 80 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 42 L 54.019531 42 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 173 L 202.601562 173 L 202.601562 175 L 54.019531 175 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 135 L 202.601562 135 L 202.601562 137 L 54.019531 137 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 97 L 202.601562 97 L 202.601562 99 L 54.019531 99 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 59 L 202.601562 59 L 202.601562 61 L 54.019531 61 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface216">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 154.882812 L 201.601562 154.882812 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 116.882812 L 201.601562 116.882812 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.882812 L 201.601562 78.882812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.882812 L 201.601562 40.882812 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 173.882812 L 201.601562 173.882812 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 135.882812 L 201.601562 135.882812 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 97.882812 L 201.601562 97.882812 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.882812 L 201.601562 59.882812 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 60.996094 171.488281 L 61.265625 171.433594 L 61.53125 171.371094 L 61.800781 171.3125 L 62.070312 171.25 L 62.878906 171.050781 L 63.144531 170.980469 L 63.953125 170.757812 L 64.222656 170.679688 L 64.492188 170.597656 L 64.757812 170.515625 L 65.296875 170.34375 L 66.105469 170.0625 L 66.371094 169.964844 L 66.640625 169.863281 L 66.910156 169.757812 L 67.449219 169.539062 L 67.71875 169.421875 L 67.984375 169.304688 L 68.253906 169.183594 L 68.523438 169.058594 L 68.792969 168.929688 L 69.0625 168.796875 L 69.332031 168.660156 L 69.597656 168.515625 L 69.867188 168.371094 L 70.136719 168.222656 L 70.40625 168.066406 L 70.675781 167.90625 L 70.945312 167.742188 L 71.210938 167.574219 L 71.480469 167.398438 L 72.019531 167.03125 L 72.289062 166.839844 L 72.558594 166.640625 L 72.824219 166.433594 L 73.09375 166.222656 L 73.363281 166.007812 L 73.632812 165.78125 L 73.902344 165.550781 L 74.167969 165.308594 L 74.4375 165.0625 L 74.707031 164.808594 L 74.976562 164.542969 L 75.246094 164.273438 L 75.515625 163.992188 L 75.78125 163.699219 L 76.050781 163.402344 L 76.320312 163.09375 L 76.589844 162.773438 L 76.859375 162.445312 L 77.128906 162.101562 L 77.394531 161.75 L 77.664062 161.386719 L 77.933594 161.011719 L 78.203125 160.625 L 78.472656 160.226562 L 78.742188 159.8125 L 79.007812 159.386719 L 79.277344 158.945312 L 79.546875 158.492188 L 79.816406 158.019531 L 80.085938 157.535156 L 80.355469 157.035156 L 80.621094 156.515625 L 80.890625 155.984375 L 81.160156 155.429688 L 81.429688 154.859375 L 81.699219 154.273438 L 81.96875 153.664062 L 82.234375 153.039062 L 82.503906 152.390625 L 82.773438 151.722656 L 83.042969 151.035156 L 83.3125 150.324219 L 83.582031 149.59375 L 83.847656 148.835938 L 84.117188 148.054688 L 84.386719 147.253906 L 84.65625 146.425781 L 84.925781 145.570312 L 85.195312 144.691406 L 85.460938 143.785156 L 85.730469 142.851562 L 86 141.890625 L 86.269531 140.902344 L 86.539062 139.882812 L 86.808594 138.839844 L 87.074219 137.761719 L 87.34375 136.65625 L 87.613281 135.519531 L 87.882812 134.355469 L 88.152344 133.15625 L 88.417969 131.929688 L 88.6875 130.667969 L 88.957031 129.378906 L 89.226562 128.054688 L 89.496094 126.699219 L 89.765625 125.316406 L 90.03125 123.898438 L 90.300781 122.449219 L 90.570312 120.972656 L 90.839844 119.460938 L 91.109375 117.921875 L 91.378906 116.351562 L 91.644531 114.753906 L 91.914062 113.128906 L 92.183594 111.476562 L 92.453125 109.800781 L 92.722656 108.097656 L 92.992188 106.367188 L 93.257812 104.617188 L 93.527344 102.847656 L 93.796875 101.058594 L 94.066406 99.25 L 94.335938 97.425781 L 94.605469 95.589844 L 94.871094 93.738281 L 95.140625 91.878906 L 95.410156 90.007812 L 95.949219 86.257812 L 96.21875 84.378906 L 96.484375 82.5 L 96.753906 80.625 L 97.023438 78.753906 L 97.292969 76.894531 L 97.5625 75.046875 L 97.832031 73.207031 L 98.097656 71.386719 L 98.367188 69.585938 L 98.636719 67.800781 L 98.90625 66.039062 L 99.175781 64.304688 L 99.445312 62.59375 L 99.710938 60.914062 L 99.980469 59.265625 L 100.25 57.648438 L 100.519531 56.0625 L 100.789062 54.515625 L 101.058594 53.003906 L 101.324219 51.53125 L 101.59375 50.097656 L 101.863281 48.703125 L 102.132812 47.351562 L 102.402344 46.039062 L 102.667969 44.769531 L 102.9375 43.542969 L 103.207031 42.359375 L 103.476562 41.21875 L 103.746094 40.125 L 104.015625 39.070312 L 104.28125 38.054688 L 104.550781 37.085938 L 104.820312 36.15625 L 105.089844 35.269531 L 105.359375 34.425781 L 105.628906 33.617188 L 105.894531 32.847656 L 106.164062 32.117188 L 106.433594 31.425781 L 106.703125 30.769531 L 106.972656 30.144531 L 107.242188 29.558594 L 107.507812 29.003906 L 107.777344 28.480469 L 108.046875 27.984375 L 108.316406 27.523438 L 108.585938 27.085938 L 108.855469 26.679688 L 109.121094 26.296875 L 109.390625 25.9375 L 109.660156 25.605469 L 109.929688 25.292969 L 110.199219 25.003906 L 110.46875 24.734375 L 110.734375 24.480469 L 111.003906 24.25 L 111.273438 24.035156 L 111.542969 23.835938 L 111.8125 23.652344 L 112.082031 23.484375 L 112.347656 23.328125 L 112.617188 23.183594 L 112.886719 23.050781 L 113.15625 22.933594 L 113.425781 22.824219 L 113.695312 22.722656 L 113.960938 22.632812 L 114.230469 22.550781 L 114.5 22.472656 L 114.769531 22.40625 L 115.039062 22.34375 L 115.308594 22.289062 L 115.574219 22.238281 L 115.84375 22.195312 L 116.113281 22.15625 L 116.382812 22.121094 L 116.652344 22.089844 L 116.921875 22.0625 L 117.1875 22.035156 L 117.996094 21.976562 L 118.265625 21.964844 L 118.53125 21.949219 L 118.800781 21.941406 L 119.070312 21.929688 L 119.609375 21.914062 L 119.878906 21.910156 L 120.144531 21.90625 L 121.222656 21.890625 L 121.492188 21.890625 L 121.757812 21.886719 L 122.566406 21.886719 L 122.835938 21.882812 L 132.78125 21.882812 L 133.050781 21.886719 L 133.859375 21.886719 L 134.128906 21.890625 L 134.394531 21.890625 L 135.742188 21.910156 L 136.007812 21.914062 L 136.546875 21.929688 L 136.816406 21.941406 L 137.085938 21.949219 L 137.355469 21.964844 L 137.621094 21.976562 L 138.429688 22.035156 L 138.96875 22.089844 L 139.234375 22.121094 L 139.503906 22.15625 L 139.773438 22.195312 L 140.042969 22.238281 L 140.3125 22.289062 L 140.582031 22.34375 L 140.847656 22.40625 L 141.117188 22.472656 L 141.386719 22.550781 L 141.65625 22.632812 L 141.925781 22.722656 L 142.195312 22.824219 L 142.460938 22.933594 L 142.730469 23.050781 L 143 23.183594 L 143.269531 23.328125 L 143.539062 23.484375 L 143.808594 23.652344 L 144.074219 23.835938 L 144.34375 24.035156 L 144.613281 24.25 L 144.882812 24.480469 L 145.152344 24.734375 L 145.421875 25.003906 L 145.6875 25.292969 L 145.957031 25.605469 L 146.226562 25.9375 L 146.496094 26.296875 L 146.765625 26.679688 L 147.03125 27.085938 L 147.300781 27.523438 L 147.570312 27.984375 L 147.839844 28.480469 L 148.109375 29.003906 L 148.378906 29.558594 L 148.644531 30.144531 L 148.914062 30.769531 L 149.183594 31.425781 L 149.453125 32.117188 L 149.722656 32.847656 L 149.992188 33.617188 L 150.257812 34.425781 L 150.527344 35.269531 L 150.796875 36.15625 L 151.066406 37.085938 L 151.335938 38.054688 L 151.605469 39.070312 L 151.871094 40.125 L 152.140625 41.21875 L 152.410156 42.359375 L 152.679688 43.542969 L 152.949219 44.769531 L 153.21875 46.039062 L 153.484375 47.351562 L 153.753906 48.703125 L 154.023438 50.097656 L 154.292969 51.53125 L 154.5625 53.003906 L 154.832031 54.515625 L 155.097656 56.0625 L 155.367188 57.648438 L 155.636719 59.265625 L 155.90625 60.914062 L 156.175781 62.59375 L 156.445312 64.304688 L 156.710938 66.039062 L 156.980469 67.800781 L 157.25 69.585938 L 157.519531 71.386719 L 157.789062 73.207031 L 158.058594 75.046875 L 158.324219 76.894531 L 158.59375 78.753906 L 158.863281 80.625 L 159.132812 82.5 L 159.671875 86.257812 L 159.9375 88.132812 L 160.207031 90.007812 L 160.476562 91.878906 L 160.746094 93.738281 L 161.015625 95.589844 L 161.28125 97.425781 L 161.550781 99.25 L 161.820312 101.058594 L 162.089844 102.847656 L 162.359375 104.617188 L 162.628906 106.367188 L 162.894531 108.097656 L 163.164062 109.800781 L 163.433594 111.476562 L 163.703125 113.128906 L 163.972656 114.753906 L 164.242188 116.351562 L 164.507812 117.921875 L 164.777344 119.460938 L 165.046875 120.972656 L 165.316406 122.449219 L 165.585938 123.898438 L 165.855469 125.316406 L 166.121094 126.699219 L 166.390625 128.054688 L 166.660156 129.378906 L 166.929688 130.667969 L 167.199219 131.929688 L 167.46875 133.15625 L 167.734375 134.355469 L 168.003906 135.519531 L 168.273438 136.65625 L 168.542969 137.761719 L 168.8125 138.839844 L 169.082031 139.882812 L 169.347656 140.902344 L 169.617188 141.890625 L 169.886719 142.851562 L 170.15625 143.785156 L 170.425781 144.691406 L 170.695312 145.570312 L 170.960938 146.425781 L 171.230469 147.253906 L 171.5 148.054688 L 171.769531 148.835938 L 172.039062 149.59375 L 172.308594 150.324219 L 172.574219 151.035156 L 172.84375 151.722656 L 173.113281 152.390625 L 173.382812 153.039062 L 173.652344 153.664062 L 173.921875 154.273438 L 174.1875 154.859375 L 174.457031 155.429688 L 174.726562 155.984375 L 174.996094 156.515625 L 175.265625 157.035156 L 175.535156 157.535156 L 175.800781 158.019531 L 176.070312 158.492188 L 176.339844 158.945312 L 176.609375 159.386719 L 176.878906 159.8125 L 177.144531 160.226562 L 177.414062 160.625 L 177.683594 161.011719 L 177.953125 161.386719 L 178.222656 161.75 L 178.492188 162.101562 L 178.757812 162.445312 L 179.027344 162.773438 L 179.296875 163.09375 L 179.566406 163.402344 L 179.835938 163.699219 L 180.105469 163.992188 L 180.371094 164.273438 L 180.640625 164.542969 L 180.910156 164.808594 L 181.179688 165.0625 L 181.449219 165.308594 L 181.71875 165.550781 L 181.984375 165.78125 L 182.253906 166.007812 L 182.523438 166.222656 L 182.792969 166.433594 L 183.0625 166.640625 L 183.332031 166.839844 L 183.597656 167.03125 L 184.136719 167.398438 L 184.40625 167.574219 L 184.675781 167.742188 L 184.945312 167.90625 L 185.210938 168.066406 L 185.480469 168.222656 L 185.75 168.371094 L 186.289062 168.660156 L 186.558594 168.796875 L 186.824219 168.929688 L 187.09375 169.058594 L 187.363281 169.183594 L 187.632812 169.304688 L 188.171875 169.539062 L 188.4375 169.648438 L 188.707031 169.757812 L 188.976562 169.863281 L 189.246094 169.964844 L 189.515625 170.0625 L 189.785156 170.15625 L 190.050781 170.25 L 190.320312 170.34375 L 190.859375 170.515625 L 191.128906 170.597656 L 191.394531 170.679688 L 191.664062 170.757812 L 192.472656 170.980469 L 192.742188 171.050781 L 193.007812 171.117188 L 193.546875 171.25 L 193.816406 171.3125 L 194.085938 171.371094 L 194.355469 171.433594 L 194.621094 171.488281 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="177.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="177.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="177.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="177.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="139.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="139.320312"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="139.320312"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="139.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="101.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="101.320312"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="101.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="101.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="63.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="63.320312"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="63.320312"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="63.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 173.882812 L 54.019531 173.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 135.882812 L 54.019531 135.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 97.882812 L 54.019531 97.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.882812 L 54.019531 59.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/binary.svg b/documentation/ui/figure/binary.svg
new file mode 100644
index 0000000..c6b8575
--- /dev/null
+++ b/documentation/ui/figure/binary.svg
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface241">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.839844 L 201.601562 152.839844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 161.28125 171.546875 L 161.550781 21.882812 L 194.890625 21.882812 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 21.882812 L 94.066406 21.882812 L 94.335938 171.546875 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/concave.svg b/documentation/ui/figure/concave.svg
new file mode 100644
index 0000000..37ef129
--- /dev/null
+++ b/documentation/ui/figure/concave.svg
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 3.171875 -2.375 L 3.171875 -5.421875 L 1.015625 -2.375 Z M 3.1875 0 L 3.1875 -1.640625 L 0.25 -1.640625 L 0.25 -2.46875 L 3.3125 -6.734375 L 4.03125 -6.734375 L 4.03125 -2.375 L 5.015625 -2.375 L 5.015625 -1.640625 L 4.03125 -1.640625 L 4.03125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 2.8125 -6.734375 C 3.5625 -6.734375 4.082031 -6.535156 4.375 -6.140625 C 4.664062 -5.753906 4.8125 -5.359375 4.8125 -4.953125 L 3.984375 -4.953125 C 3.929688 -5.210938 3.851562 -5.421875 3.75 -5.578125 C 3.539062 -5.859375 3.226562 -6 2.8125 -6 C 2.34375 -6 1.96875 -5.78125 1.6875 -5.34375 C 1.414062 -4.90625 1.265625 -4.28125 1.234375 -3.46875 C 1.421875 -3.75 1.664062 -3.960938 1.96875 -4.109375 C 2.226562 -4.234375 2.523438 -4.296875 2.859375 -4.296875 C 3.421875 -4.296875 3.910156 -4.113281 4.328125 -3.75 C 4.742188 -3.394531 4.953125 -2.863281 4.953125 -2.15625 C 4.953125 -1.539062 4.753906 -1 4.359375 -0.53125 C 3.960938 -0.0625 3.398438 0.171875 2.671875 0.171875 C 2.046875 0.171875 1.503906 -0.0625 1.046875 -0.53125 C 0.585938 -1.007812 0.359375 -1.816406 0.359375 -2.953125 C 0.359375 -3.785156 0.460938 -4.488281 0.671875 -5.0625 C 1.054688 -6.175781 1.769531 -6.734375 2.8125 -6.734375 Z M 2.75 -0.578125 C 3.1875 -0.578125 3.515625 -0.722656 3.734375 -1.015625 C 3.960938 -1.316406 4.078125 -1.671875 4.078125 -2.078125 C 4.078125 -2.421875 3.976562 -2.75 3.78125 -3.0625 C 3.582031 -3.375 3.222656 -3.53125 2.703125 -3.53125 C 2.335938 -3.53125 2.019531 -3.410156 1.75 -3.171875 C 1.476562 -2.929688 1.34375 -2.566406 1.34375 -2.078125 C 1.34375 -1.648438 1.460938 -1.289062 1.703125 -1 C 1.953125 -0.71875 2.300781 -0.578125 2.75 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 2.609375 -3.890625 C 2.984375 -3.890625 3.273438 -3.992188 3.484375 -4.203125 C 3.691406 -4.410156 3.796875 -4.660156 3.796875 -4.953125 C 3.796875 -5.203125 3.691406 -5.429688 3.484375 -5.640625 C 3.285156 -5.847656 2.984375 -5.953125 2.578125 -5.953125 C 2.171875 -5.953125 1.875 -5.847656 1.6875 -5.640625 C 1.507812 -5.429688 1.421875 -5.1875 1.421875 -4.90625 C 1.421875 -4.59375 1.535156 -4.34375 1.765625 -4.15625 C 2.003906 -3.976562 2.285156 -3.890625 2.609375 -3.890625 Z M 2.65625 -0.578125 C 3.050781 -0.578125 3.375 -0.679688 3.625 -0.890625 C 3.882812 -1.097656 4.015625 -1.414062 4.015625 -1.84375 C 4.015625 -2.269531 3.878906 -2.59375 3.609375 -2.8125 C 3.347656 -3.039062 3.007812 -3.15625 2.59375 -3.15625 C 2.195312 -3.15625 1.867188 -3.039062 1.609375 -2.8125 C 1.359375 -2.582031 1.234375 -2.265625 1.234375 -1.859375 C 1.234375 -1.515625 1.347656 -1.210938 1.578125 -0.953125 C 1.816406 -0.703125 2.175781 -0.578125 2.65625 -0.578125 Z M 1.46875 -3.578125 C 1.226562 -3.671875 1.039062 -3.785156 0.90625 -3.921875 C 0.664062 -4.171875 0.546875 -4.5 0.546875 -4.90625 C 0.546875 -5.40625 0.722656 -5.832031 1.078125 -6.1875 C 1.441406 -6.550781 1.957031 -6.734375 2.625 -6.734375 C 3.269531 -6.734375 3.773438 -6.5625 4.140625 -6.21875 C 4.503906 -5.875 4.6875 -5.476562 4.6875 -5.03125 C 4.6875 -4.613281 4.582031 -4.273438 4.375 -4.015625 C 4.25 -3.867188 4.0625 -3.722656 3.8125 -3.578125 C 4.09375 -3.453125 4.3125 -3.304688 4.46875 -3.140625 C 4.769531 -2.828125 4.921875 -2.421875 4.921875 -1.921875 C 4.921875 -1.335938 4.722656 -0.835938 4.328125 -0.421875 C 3.929688 -0.015625 3.367188 0.1875 2.640625 0.1875 C 1.984375 0.1875 1.429688 0.0078125 0.984375 -0.34375 C 0.535156 -0.695312 0.3125 -1.210938 0.3125 -1.890625 C 0.3125 -2.285156 0.40625 -2.625 0.59375 -2.90625 C 0.789062 -3.195312 1.082031 -3.421875 1.46875 -3.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-9">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 48.683594 14.398438 L 202 14.398438 L 202 180 L 48.683594 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 48.683594 165 L 202 165 L 202 167 L 48.683594 167 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 48.683594 124 L 202 124 L 202 126 L 48.683594 126 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 48.683594 83 L 202 83 L 202 84 L 48.683594 84 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 48.683594 42 L 202 42 L 202 43 L 48.683594 43 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 72 14.398438 L 74 14.398438 L 74 180 L 72 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 107 14.398438 L 109 14.398438 L 109 180 L 107 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 142 14.398438 L 143 14.398438 L 143 180 L 142 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 178 14.398438 L 178 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 48.683594 144 L 202.601562 144 L 202.601562 146 L 48.683594 146 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 48.683594 103 L 202.601562 103 L 202.601562 105 L 48.683594 105 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 48.683594 62 L 202.601562 62 L 202.601562 64 L 48.683594 64 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 48.683594 21 L 202.601562 21 L 202.601562 23 L 48.683594 23 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 55 14.398438 L 57 14.398438 L 57 180 L 55 180 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 89 14.398438 L 91 14.398438 L 91 180 L 89 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 124 14.398438 L 126 14.398438 L 126 180 L 124 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 159 14.398438 L 161 14.398438 L 161 180 L 159 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface246">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 48.683594 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 48.683594 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 165.933594 L 201.601562 165.933594 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 124.777344 L 201.601562 124.777344 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 83.617188 L 201.601562 83.617188 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 42.460938 L 201.601562 42.460938 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 73.011719 179.027344 L 73.011719 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 107.765625 179.027344 L 107.765625 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 142.519531 179.027344 L 142.519531 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 177.273438 179.027344 L 177.273438 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 145.355469 L 201.601562 145.355469 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 104.199219 L 201.601562 104.199219 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 63.039062 L 201.601562 63.039062 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.632812 179.027344 L 55.632812 14.398438 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 90.386719 179.027344 L 90.386719 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 125.140625 179.027344 L 125.140625 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 159.894531 179.027344 L 159.894531 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.648438 179.027344 L 194.648438 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 55.632812 21.882812 L 83.214844 21.882812 L 83.492188 22.15625 L 83.769531 23.519531 L 84.050781 24.863281 L 84.328125 26.191406 L 84.605469 27.5 L 84.886719 28.792969 L 85.164062 30.066406 L 85.441406 31.328125 L 85.722656 32.570312 L 86 33.796875 L 86.277344 35.011719 L 86.558594 36.207031 L 86.835938 37.390625 L 87.113281 38.558594 L 87.390625 39.710938 L 87.671875 40.851562 L 87.949219 41.976562 L 88.226562 43.089844 L 88.507812 44.191406 L 88.785156 45.277344 L 89.0625 46.351562 L 89.34375 47.410156 L 89.621094 48.460938 L 89.898438 49.496094 L 90.179688 50.519531 L 90.457031 51.535156 L 90.734375 52.535156 L 91.015625 53.523438 L 91.292969 54.503906 L 91.570312 55.472656 L 91.851562 56.429688 L 92.128906 57.375 L 92.40625 58.3125 L 92.6875 59.238281 L 92.964844 60.152344 L 93.242188 61.058594 L 93.519531 61.957031 L 93.800781 62.84375 L 94.078125 63.71875 L 94.355469 64.585938 L 94.636719 65.445312 L 94.914062 66.296875 L 95.191406 67.136719 L 95.472656 67.96875 L 95.75 68.792969 L 96.027344 69.609375 L 96.308594 70.414062 L 96.585938 71.214844 L 96.863281 72.003906 L 97.144531 72.785156 L 97.421875 73.5625 L 97.699219 74.328125 L 97.980469 75.089844 L 98.257812 75.839844 L 98.535156 76.585938 L 98.816406 77.320312 L 99.09375 78.050781 L 99.371094 78.773438 L 99.652344 79.492188 L 99.929688 80.199219 L 100.207031 80.902344 L 100.484375 81.597656 L 100.765625 82.289062 L 101.042969 82.972656 L 101.320312 83.648438 L 101.601562 84.316406 L 101.878906 84.980469 L 102.15625 85.640625 L 102.4375 86.292969 L 102.714844 86.9375 L 102.992188 87.578125 L 103.273438 88.210938 L 103.550781 88.839844 L 103.828125 89.464844 L 104.109375 90.082031 L 104.386719 90.691406 L 104.664062 91.296875 L 104.945312 91.898438 L 105.222656 92.496094 L 105.5 93.085938 L 105.78125 93.671875 L 106.335938 94.828125 L 106.613281 95.398438 L 106.894531 95.960938 L 107.171875 96.523438 L 107.449219 97.078125 L 107.730469 97.628906 L 108.007812 98.175781 L 108.285156 98.71875 L 108.566406 99.257812 L 109.121094 100.320312 L 109.402344 100.84375 L 109.679688 101.363281 L 109.957031 101.878906 L 110.238281 102.390625 L 110.515625 102.898438 L 110.792969 103.402344 L 111.074219 103.898438 L 111.351562 104.394531 L 111.628906 104.886719 L 111.910156 105.375 L 112.1875 105.859375 L 112.742188 106.8125 L 113.023438 107.285156 L 113.300781 107.753906 L 113.578125 108.21875 L 113.859375 108.679688 L 114.414062 109.59375 L 114.695312 110.042969 L 114.972656 110.492188 L 115.25 110.933594 L 115.53125 111.375 L 115.808594 111.8125 L 116.085938 112.246094 L 116.367188 112.679688 L 116.921875 113.53125 L 117.203125 113.953125 L 117.480469 114.371094 L 117.757812 114.785156 L 118.039062 115.195312 L 118.316406 115.605469 L 118.59375 116.011719 L 118.875 116.414062 L 119.152344 116.816406 L 119.429688 117.214844 L 119.707031 117.609375 L 119.988281 118 L 120.265625 118.390625 L 120.542969 118.773438 L 120.824219 119.160156 L 121.378906 119.917969 L 121.660156 120.292969 L 121.9375 120.667969 L 122.214844 121.035156 L 122.496094 121.40625 L 123.050781 122.132812 L 123.332031 122.492188 L 123.609375 122.851562 L 123.886719 123.207031 L 124.167969 123.558594 L 124.445312 123.910156 L 124.722656 124.257812 L 125.003906 124.605469 L 125.28125 124.949219 L 125.835938 125.628906 L 126.117188 125.964844 L 126.394531 126.300781 L 126.671875 126.632812 L 126.953125 126.960938 L 127.507812 127.617188 L 127.789062 127.941406 L 128.34375 128.582031 L 128.625 128.898438 L 128.902344 129.214844 L 129.179688 129.527344 L 129.460938 129.839844 L 129.738281 130.152344 L 130.015625 130.457031 L 130.296875 130.765625 L 130.574219 131.066406 L 130.851562 131.371094 L 131.132812 131.671875 L 131.6875 132.265625 L 131.964844 132.558594 L 132.246094 132.851562 L 132.523438 133.144531 L 132.800781 133.433594 L 133.082031 133.71875 L 133.636719 134.289062 L 133.917969 134.570312 L 134.195312 134.851562 L 134.472656 135.128906 L 134.753906 135.40625 L 135.03125 135.683594 L 135.308594 135.957031 L 135.589844 136.230469 L 136.144531 136.769531 L 136.425781 137.035156 L 136.980469 137.566406 L 137.261719 137.828125 L 137.816406 138.351562 L 138.09375 138.609375 L 138.375 138.863281 L 138.652344 139.121094 L 138.929688 139.375 L 139.210938 139.625 L 139.488281 139.878906 L 139.765625 140.125 L 140.046875 140.375 L 140.601562 140.867188 L 140.882812 141.109375 L 141.4375 141.59375 L 141.71875 141.835938 L 141.996094 142.074219 L 142.273438 142.308594 L 142.554688 142.546875 L 143.109375 143.015625 L 143.390625 143.246094 L 143.945312 143.707031 L 144.226562 143.933594 L 145.058594 144.613281 L 145.339844 144.835938 L 145.617188 145.058594 L 145.894531 145.277344 L 146.175781 145.496094 L 146.730469 145.933594 L 147.011719 146.148438 L 147.566406 146.578125 L 147.847656 146.792969 L 148.402344 147.214844 L 148.683594 147.425781 L 149.238281 147.839844 L 149.519531 148.046875 L 149.796875 148.25 L 150.074219 148.457031 L 150.355469 148.660156 L 150.632812 148.859375 L 150.910156 149.0625 L 151.1875 149.261719 L 151.46875 149.460938 L 151.746094 149.660156 L 152.023438 149.855469 L 152.304688 150.050781 L 152.859375 150.441406 L 153.140625 150.632812 L 153.417969 150.828125 L 153.695312 151.019531 L 153.976562 151.207031 L 154.253906 151.398438 L 154.53125 151.585938 L 154.8125 151.773438 L 155.089844 151.960938 L 155.367188 152.144531 L 155.648438 152.332031 L 155.925781 152.515625 L 156.203125 152.695312 L 156.484375 152.878906 L 156.761719 153.058594 L 157.039062 153.242188 L 157.316406 153.417969 L 157.597656 153.597656 L 157.875 153.777344 L 158.152344 153.953125 L 158.433594 154.128906 L 158.710938 154.304688 L 158.988281 154.476562 L 159.269531 154.652344 L 159.824219 154.996094 L 160.105469 155.167969 L 160.382812 155.335938 L 160.660156 155.507812 L 160.941406 155.675781 L 161.496094 156.011719 L 161.777344 156.175781 L 162.054688 156.34375 L 162.332031 156.507812 L 162.613281 156.671875 L 162.890625 156.835938 L 163.167969 156.996094 L 163.445312 157.160156 L 163.726562 157.320312 L 164.28125 157.640625 L 164.5625 157.796875 L 164.839844 157.957031 L 165.117188 158.113281 L 165.398438 158.269531 L 165.953125 158.582031 L 166.234375 158.734375 L 166.511719 158.890625 L 166.789062 159.042969 L 167.070312 159.195312 L 167.625 159.5 L 167.90625 159.648438 L 168.183594 159.800781 L 168.460938 159.949219 L 168.742188 160.097656 L 169.019531 160.246094 L 169.296875 160.390625 L 169.578125 160.539062 L 169.855469 160.683594 L 170.132812 160.832031 L 170.410156 160.976562 L 170.691406 161.117188 L 171.246094 161.40625 L 171.527344 161.546875 L 171.804688 161.6875 L 172.082031 161.832031 L 172.363281 161.96875 L 172.917969 162.25 L 173.199219 162.386719 L 173.476562 162.527344 L 173.753906 162.664062 L 174.035156 162.800781 L 174.589844 163.074219 L 174.871094 163.207031 L 175.148438 163.34375 L 175.425781 163.476562 L 175.707031 163.609375 L 176.539062 164.007812 L 176.820312 164.136719 L 177.097656 164.269531 L 177.375 164.398438 L 177.65625 164.527344 L 178.210938 164.785156 L 178.492188 164.914062 L 178.769531 165.042969 L 179.046875 165.167969 L 179.328125 165.296875 L 179.882812 165.546875 L 180.164062 165.671875 L 180.71875 165.921875 L 181 166.042969 L 181.277344 166.167969 L 181.554688 166.289062 L 181.835938 166.414062 L 182.667969 166.777344 L 182.949219 166.894531 L 183.226562 167.015625 L 183.503906 167.132812 L 183.785156 167.253906 L 184.339844 167.488281 L 184.621094 167.605469 L 185.175781 167.839844 L 185.457031 167.957031 L 185.734375 168.070312 L 186.011719 168.1875 L 186.292969 168.300781 L 186.847656 168.527344 L 187.128906 168.640625 L 187.683594 168.867188 L 187.964844 168.980469 L 188.242188 169.089844 L 188.519531 169.203125 L 188.800781 169.3125 L 189.078125 169.421875 L 189.355469 169.535156 L 189.632812 169.644531 L 189.914062 169.753906 L 190.191406 169.859375 L 190.46875 169.96875 L 190.75 170.078125 L 191.027344 170.183594 L 191.304688 170.292969 L 191.585938 170.398438 L 192.140625 170.609375 L 192.421875 170.714844 L 192.976562 170.925781 L 193.257812 171.03125 L 193.535156 171.132812 L 193.8125 171.238281 L 194.09375 171.339844 L 194.371094 171.445312 L 194.648438 171.546875 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 55.632812 171.546875 L 55.910156 171.445312 L 56.191406 171.339844 L 56.46875 171.238281 L 56.746094 171.132812 L 57.027344 171.03125 L 57.582031 170.820312 L 57.863281 170.714844 L 58.417969 170.503906 L 58.699219 170.398438 L 58.976562 170.292969 L 59.253906 170.183594 L 59.535156 170.078125 L 60.089844 169.859375 L 60.371094 169.753906 L 60.925781 169.535156 L 61.207031 169.421875 L 61.761719 169.203125 L 62.039062 169.089844 L 62.320312 168.980469 L 62.875 168.753906 L 63.15625 168.640625 L 63.710938 168.414062 L 63.992188 168.300781 L 64.269531 168.1875 L 64.546875 168.070312 L 64.828125 167.957031 L 65.382812 167.722656 L 65.664062 167.605469 L 66.21875 167.371094 L 66.5 167.253906 L 66.777344 167.132812 L 67.054688 167.015625 L 67.335938 166.894531 L 67.613281 166.777344 L 68.167969 166.535156 L 68.449219 166.414062 L 68.726562 166.289062 L 69.003906 166.167969 L 69.285156 166.042969 L 69.5625 165.921875 L 69.839844 165.796875 L 70.121094 165.671875 L 70.675781 165.421875 L 70.957031 165.296875 L 71.234375 165.167969 L 71.511719 165.042969 L 71.792969 164.914062 L 72.347656 164.65625 L 72.628906 164.527344 L 73.183594 164.269531 L 73.464844 164.136719 L 73.742188 164.007812 L 74.019531 163.875 L 74.300781 163.742188 L 75.132812 163.34375 L 75.414062 163.207031 L 75.691406 163.074219 L 75.96875 162.9375 L 76.25 162.800781 L 76.804688 162.527344 L 77.085938 162.386719 L 77.363281 162.25 L 77.640625 162.109375 L 77.921875 161.96875 L 78.199219 161.832031 L 78.476562 161.6875 L 78.757812 161.546875 L 79.035156 161.40625 L 79.3125 161.261719 L 79.59375 161.117188 L 79.871094 160.976562 L 80.148438 160.832031 L 80.429688 160.683594 L 80.707031 160.539062 L 80.984375 160.390625 L 81.261719 160.246094 L 81.542969 160.097656 L 82.097656 159.800781 L 82.378906 159.648438 L 82.65625 159.5 L 82.933594 159.347656 L 83.214844 159.195312 L 83.769531 158.890625 L 84.050781 158.734375 L 84.328125 158.582031 L 84.605469 158.425781 L 84.886719 158.269531 L 85.441406 157.957031 L 85.722656 157.796875 L 86 157.640625 L 86.277344 157.480469 L 86.558594 157.320312 L 86.835938 157.160156 L 87.113281 156.996094 L 87.390625 156.835938 L 87.671875 156.671875 L 88.226562 156.34375 L 88.507812 156.175781 L 88.785156 156.011719 L 89.0625 155.84375 L 89.34375 155.675781 L 89.621094 155.507812 L 89.898438 155.335938 L 90.179688 155.167969 L 90.734375 154.824219 L 91.015625 154.652344 L 91.292969 154.476562 L 91.570312 154.304688 L 91.851562 154.128906 L 92.40625 153.777344 L 92.6875 153.597656 L 92.964844 153.417969 L 93.242188 153.242188 L 93.519531 153.058594 L 93.800781 152.878906 L 94.078125 152.695312 L 94.355469 152.515625 L 94.636719 152.332031 L 94.914062 152.144531 L 95.191406 151.960938 L 95.472656 151.773438 L 96.027344 151.398438 L 96.308594 151.207031 L 96.585938 151.019531 L 96.863281 150.828125 L 97.144531 150.632812 L 97.421875 150.441406 L 97.699219 150.246094 L 97.980469 150.050781 L 98.535156 149.660156 L 98.816406 149.460938 L 99.371094 149.0625 L 99.652344 148.859375 L 99.929688 148.660156 L 100.207031 148.457031 L 100.484375 148.25 L 100.765625 148.046875 L 101.320312 147.632812 L 101.601562 147.425781 L 102.15625 147.003906 L 102.4375 146.792969 L 102.992188 146.363281 L 103.273438 146.148438 L 103.550781 145.933594 L 103.828125 145.714844 L 104.109375 145.496094 L 104.664062 145.058594 L 104.945312 144.835938 L 105.222656 144.613281 L 105.5 144.386719 L 105.78125 144.160156 L 106.335938 143.707031 L 106.613281 143.476562 L 106.894531 143.246094 L 107.171875 143.015625 L 107.449219 142.78125 L 107.730469 142.546875 L 108.007812 142.308594 L 108.285156 142.074219 L 108.566406 141.835938 L 109.121094 141.351562 L 109.402344 141.109375 L 109.679688 140.867188 L 109.957031 140.621094 L 110.238281 140.375 L 110.515625 140.125 L 110.792969 139.878906 L 111.074219 139.625 L 111.351562 139.375 L 111.628906 139.121094 L 111.910156 138.863281 L 112.1875 138.609375 L 112.464844 138.351562 L 112.742188 138.089844 L 113.023438 137.828125 L 113.300781 137.566406 L 113.578125 137.300781 L 113.859375 137.035156 L 114.136719 136.769531 L 114.414062 136.5 L 114.695312 136.230469 L 115.25 135.683594 L 115.53125 135.40625 L 116.367188 134.570312 L 116.644531 134.289062 L 116.921875 134.003906 L 117.203125 133.71875 L 117.480469 133.433594 L 117.757812 133.144531 L 118.039062 132.851562 L 118.59375 132.265625 L 118.875 131.96875 L 119.152344 131.671875 L 119.429688 131.371094 L 119.707031 131.066406 L 119.988281 130.765625 L 120.265625 130.457031 L 120.542969 130.152344 L 120.824219 129.839844 L 121.378906 129.214844 L 121.660156 128.898438 L 121.9375 128.582031 L 122.214844 128.261719 L 122.496094 127.941406 L 122.773438 127.617188 L 123.050781 127.289062 L 123.332031 126.960938 L 123.609375 126.632812 L 123.886719 126.300781 L 124.167969 125.964844 L 124.445312 125.628906 L 124.722656 125.289062 L 125.003906 124.949219 L 125.28125 124.605469 L 125.835938 123.910156 L 126.117188 123.558594 L 126.394531 123.207031 L 126.671875 122.851562 L 126.953125 122.492188 L 127.230469 122.132812 L 127.507812 121.769531 L 127.789062 121.40625 L 128.066406 121.035156 L 128.34375 120.667969 L 128.625 120.292969 L 128.902344 119.917969 L 129.179688 119.539062 L 129.460938 119.160156 L 129.738281 118.773438 L 130.015625 118.390625 L 130.296875 118 L 130.574219 117.609375 L 130.851562 117.214844 L 131.132812 116.816406 L 131.6875 116.011719 L 131.964844 115.605469 L 132.246094 115.195312 L 132.523438 114.785156 L 132.800781 114.371094 L 133.082031 113.953125 L 133.359375 113.53125 L 133.636719 113.105469 L 133.917969 112.679688 L 134.472656 111.8125 L 134.753906 111.375 L 135.308594 110.492188 L 135.589844 110.042969 L 135.867188 109.59375 L 136.144531 109.136719 L 136.425781 108.679688 L 136.703125 108.21875 L 136.980469 107.753906 L 137.261719 107.285156 L 137.539062 106.8125 L 138.09375 105.859375 L 138.375 105.375 L 138.652344 104.886719 L 138.929688 104.394531 L 139.210938 103.898438 L 139.488281 103.402344 L 139.765625 102.898438 L 140.046875 102.390625 L 140.324219 101.878906 L 140.601562 101.363281 L 140.882812 100.84375 L 141.160156 100.320312 L 141.4375 99.789062 L 141.71875 99.257812 L 141.996094 98.71875 L 142.273438 98.175781 L 142.554688 97.628906 L 142.832031 97.078125 L 143.390625 95.960938 L 143.667969 95.398438 L 143.945312 94.828125 L 144.226562 94.25 L 144.503906 93.671875 L 144.78125 93.085938 L 145.058594 92.496094 L 145.339844 91.898438 L 145.617188 91.296875 L 145.894531 90.691406 L 146.175781 90.082031 L 146.453125 89.464844 L 146.730469 88.839844 L 147.011719 88.210938 L 147.289062 87.578125 L 147.566406 86.9375 L 147.847656 86.292969 L 148.125 85.640625 L 148.402344 84.980469 L 148.683594 84.316406 L 148.960938 83.648438 L 149.238281 82.972656 L 149.519531 82.289062 L 149.796875 81.597656 L 150.074219 80.902344 L 150.355469 80.199219 L 150.632812 79.492188 L 150.910156 78.773438 L 151.1875 78.050781 L 151.46875 77.320312 L 151.746094 76.585938 L 152.023438 75.839844 L 152.304688 75.089844 L 152.582031 74.328125 L 152.859375 73.5625 L 153.140625 72.785156 L 153.417969 72.003906 L 153.695312 71.214844 L 153.976562 70.414062 L 154.253906 69.609375 L 154.53125 68.792969 L 154.8125 67.96875 L 155.089844 67.136719 L 155.367188 66.296875 L 155.648438 65.445312 L 155.925781 64.585938 L 156.203125 63.71875 L 156.484375 62.84375 L 156.761719 61.957031 L 157.039062 61.058594 L 157.316406 60.152344 L 157.597656 59.238281 L 157.875 58.3125 L 158.152344 57.375 L 158.433594 56.429688 L 158.710938 55.472656 L 158.988281 54.503906 L 159.269531 53.523438 L 159.546875 52.535156 L 159.824219 51.535156 L 160.105469 50.519531 L 160.382812 49.496094 L 160.660156 48.460938 L 160.941406 47.410156 L 161.21875 46.351562 L 161.496094 45.277344 L 161.777344 44.191406 L 162.054688 43.089844 L 162.332031 41.976562 L 162.613281 40.851562 L 162.890625 39.710938 L 163.167969 38.558594 L 163.445312 37.390625 L 163.726562 36.207031 L 164.003906 35.011719 L 164.28125 33.796875 L 164.5625 32.570312 L 164.839844 31.328125 L 165.117188 30.066406 L 165.398438 28.792969 L 165.675781 27.5 L 165.953125 26.191406 L 166.234375 24.863281 L 166.511719 23.519531 L 166.789062 22.15625 L 167.070312 21.882812 L 194.648438 21.882812 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="148.792969"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="148.792969"/>
+ <use xlink:href="#glyph0-3" x="36.262756" y="148.792969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="107.636719"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="107.636719"/>
+ <use xlink:href="#glyph0-4" x="36.262756" y="107.636719"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="66.476562"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="66.476562"/>
+ <use xlink:href="#glyph0-5" x="36.262756" y="66.476562"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.261719" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.262756" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 145.355469 L 48.683594 145.355469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 104.199219 L 48.683594 104.199219 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 63.039062 L 48.683594 63.039062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 21.882812 L 48.683594 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.632812 183.28125 L 55.632812 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 90.386719 183.28125 L 90.386719 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 125.140625 183.28125 L 125.140625 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 159.894531 183.28125 L 159.894531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.648438 183.28125 L 194.648438 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="46.296875" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="51.632462" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="54.297913" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.633499" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="81.050781" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="86.386368" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="89.051819" y="192.992188"/>
+ <use xlink:href="#glyph0-8" x="94.387405" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="115.804688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="121.140274" y="192.992188"/>
+ <use xlink:href="#glyph0-8" x="123.805725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="129.141312" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="150.558594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="155.89418" y="192.992188"/>
+ <use xlink:href="#glyph0-9" x="158.559631" y="192.992188"/>
+ <use xlink:href="#glyph0-8" x="163.895218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.3125" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.648087" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.313538" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.649124" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="122.140625" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/cosine.svg b/documentation/ui/figure/cosine.svg
new file mode 100644
index 0000000..ab567c5
--- /dev/null
+++ b/documentation/ui/figure/cosine.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface201">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.835938 L 201.601562 152.835938 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.003906 L 201.601562 78.003906 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 60.996094 171.539062 L 61.265625 171.523438 L 61.53125 171.492188 L 61.800781 171.449219 L 62.070312 171.398438 L 62.339844 171.332031 L 62.609375 171.253906 L 62.878906 171.167969 L 63.144531 171.066406 L 63.414062 170.953125 L 63.683594 170.828125 L 63.953125 170.691406 L 64.222656 170.546875 L 64.492188 170.386719 L 64.757812 170.214844 L 65.027344 170.03125 L 65.296875 169.839844 L 65.566406 169.632812 L 65.835938 169.414062 L 66.105469 169.183594 L 66.371094 168.945312 L 66.640625 168.691406 L 66.910156 168.429688 L 67.179688 168.15625 L 67.449219 167.867188 L 67.71875 167.570312 L 67.984375 167.261719 L 68.253906 166.941406 L 68.523438 166.613281 L 68.792969 166.269531 L 69.0625 165.917969 L 69.332031 165.554688 L 69.597656 165.179688 L 69.867188 164.792969 L 70.136719 164.394531 L 70.40625 163.988281 L 70.675781 163.570312 L 70.945312 163.140625 L 71.210938 162.703125 L 71.480469 162.253906 L 71.75 161.792969 L 72.019531 161.324219 L 72.289062 160.84375 L 72.558594 160.351562 L 72.824219 159.851562 L 73.09375 159.339844 L 73.363281 158.820312 L 73.632812 158.289062 L 73.902344 157.75 L 74.167969 157.199219 L 74.4375 156.640625 L 74.707031 156.070312 L 74.976562 155.492188 L 75.246094 154.902344 L 75.515625 154.308594 L 75.78125 153.699219 L 76.050781 153.085938 L 76.320312 152.460938 L 76.589844 151.828125 L 76.859375 151.1875 L 77.128906 150.535156 L 77.394531 149.878906 L 77.664062 149.210938 L 77.933594 148.535156 L 78.203125 147.851562 L 78.472656 147.160156 L 78.742188 146.457031 L 79.007812 145.75 L 79.277344 145.035156 L 79.546875 144.3125 L 79.816406 143.582031 L 80.085938 142.84375 L 80.355469 142.097656 L 80.621094 141.34375 L 80.890625 140.585938 L 81.160156 139.816406 L 81.429688 139.042969 L 81.699219 138.265625 L 81.96875 137.476562 L 82.234375 136.683594 L 82.503906 135.882812 L 82.773438 135.078125 L 83.042969 134.265625 L 83.3125 133.449219 L 83.582031 132.625 L 83.847656 131.792969 L 84.117188 130.960938 L 84.65625 129.273438 L 84.925781 128.421875 L 85.195312 127.566406 L 85.460938 126.707031 L 85.730469 125.839844 L 86 124.96875 L 86.269531 124.09375 L 86.539062 123.214844 L 86.808594 122.332031 L 87.074219 121.445312 L 87.34375 120.554688 L 87.613281 119.660156 L 87.882812 118.761719 L 88.152344 117.859375 L 88.417969 116.953125 L 88.957031 115.132812 L 89.226562 114.21875 L 89.496094 113.300781 L 89.765625 112.378906 L 90.03125 111.457031 L 90.570312 109.605469 L 91.109375 107.746094 L 91.378906 106.8125 L 91.644531 105.878906 L 92.722656 102.128906 L 92.992188 101.1875 L 93.257812 100.246094 L 94.066406 97.421875 L 94.335938 96.476562 L 94.605469 95.535156 L 94.871094 94.59375 L 95.679688 91.769531 L 95.949219 90.832031 L 96.21875 89.890625 L 96.484375 88.953125 L 96.753906 88.019531 L 97.023438 87.082031 L 97.292969 86.148438 L 97.5625 85.21875 L 97.832031 84.285156 L 98.097656 83.359375 L 98.636719 81.507812 L 98.90625 80.585938 L 99.175781 79.667969 L 99.445312 78.753906 L 99.710938 77.839844 L 99.980469 76.929688 L 100.519531 75.117188 L 101.058594 73.320312 L 101.324219 72.425781 L 101.863281 70.652344 L 102.402344 68.894531 L 102.667969 68.023438 L 102.9375 67.15625 L 103.207031 66.292969 L 103.476562 65.433594 L 103.746094 64.578125 L 104.015625 63.730469 L 104.28125 62.886719 L 104.550781 62.050781 L 104.820312 61.21875 L 105.089844 60.390625 L 105.359375 59.570312 L 105.628906 58.753906 L 105.894531 57.945312 L 106.164062 57.144531 L 106.433594 56.347656 L 106.703125 55.554688 L 106.972656 54.773438 L 107.242188 53.996094 L 107.507812 53.226562 L 107.777344 52.460938 L 108.046875 51.707031 L 108.316406 50.957031 L 108.585938 50.214844 L 108.855469 49.480469 L 109.121094 48.753906 L 109.390625 48.035156 L 109.660156 47.320312 L 109.929688 46.617188 L 110.199219 45.921875 L 110.46875 45.234375 L 110.734375 44.554688 L 111.003906 43.882812 L 111.273438 43.21875 L 111.542969 42.566406 L 111.8125 41.917969 L 112.082031 41.28125 L 112.347656 40.652344 L 112.617188 40.035156 L 112.886719 39.421875 L 113.15625 38.820312 L 113.425781 38.230469 L 113.695312 37.644531 L 113.960938 37.070312 L 114.230469 36.507812 L 114.5 35.953125 L 114.769531 35.40625 L 115.039062 34.871094 L 115.308594 34.347656 L 115.574219 33.832031 L 115.84375 33.324219 L 116.113281 32.828125 L 116.382812 32.34375 L 116.652344 31.867188 L 116.921875 31.402344 L 117.1875 30.949219 L 117.457031 30.503906 L 117.726562 30.070312 L 117.996094 29.648438 L 118.265625 29.234375 L 118.53125 28.832031 L 118.800781 28.441406 L 119.070312 28.0625 L 119.339844 27.691406 L 119.609375 27.332031 L 119.878906 26.984375 L 120.144531 26.648438 L 120.414062 26.324219 L 120.683594 26.007812 L 120.953125 25.707031 L 121.222656 25.414062 L 121.492188 25.132812 L 121.757812 24.863281 L 122.027344 24.605469 L 122.296875 24.359375 L 122.566406 24.125 L 122.835938 23.902344 L 123.105469 23.691406 L 123.371094 23.492188 L 123.640625 23.300781 L 123.910156 23.125 L 124.179688 22.960938 L 124.449219 22.808594 L 124.71875 22.664062 L 124.984375 22.535156 L 125.253906 22.417969 L 125.523438 22.308594 L 125.792969 22.214844 L 126.0625 22.132812 L 126.332031 22.0625 L 126.597656 22 L 126.867188 21.953125 L 127.136719 21.917969 L 127.40625 21.894531 L 127.675781 21.882812 L 127.945312 21.882812 L 128.210938 21.894531 L 128.480469 21.917969 L 128.75 21.953125 L 129.019531 22 L 129.289062 22.0625 L 129.558594 22.132812 L 129.824219 22.214844 L 130.09375 22.308594 L 130.363281 22.417969 L 130.632812 22.535156 L 130.902344 22.664062 L 131.171875 22.808594 L 131.4375 22.960938 L 131.707031 23.125 L 131.976562 23.300781 L 132.246094 23.492188 L 132.515625 23.691406 L 132.78125 23.902344 L 133.050781 24.125 L 133.320312 24.359375 L 133.589844 24.605469 L 133.859375 24.863281 L 134.128906 25.132812 L 134.394531 25.414062 L 134.664062 25.707031 L 134.933594 26.007812 L 135.203125 26.324219 L 135.472656 26.648438 L 135.742188 26.984375 L 136.007812 27.332031 L 136.277344 27.691406 L 136.546875 28.0625 L 136.816406 28.441406 L 137.085938 28.832031 L 137.355469 29.234375 L 137.621094 29.648438 L 137.890625 30.070312 L 138.160156 30.503906 L 138.429688 30.949219 L 138.699219 31.402344 L 138.96875 31.867188 L 139.234375 32.34375 L 139.503906 32.828125 L 139.773438 33.324219 L 140.042969 33.832031 L 140.3125 34.347656 L 140.582031 34.871094 L 140.847656 35.40625 L 141.117188 35.953125 L 141.386719 36.507812 L 141.65625 37.070312 L 141.925781 37.644531 L 142.195312 38.230469 L 142.460938 38.820312 L 142.730469 39.421875 L 143 40.035156 L 143.269531 40.652344 L 143.539062 41.28125 L 143.808594 41.917969 L 144.074219 42.566406 L 144.34375 43.21875 L 144.613281 43.882812 L 144.882812 44.554688 L 145.152344 45.234375 L 145.421875 45.921875 L 145.6875 46.617188 L 145.957031 47.320312 L 146.226562 48.035156 L 146.496094 48.753906 L 146.765625 49.480469 L 147.03125 50.214844 L 147.300781 50.957031 L 147.570312 51.707031 L 147.839844 52.460938 L 148.109375 53.226562 L 148.378906 53.996094 L 148.644531 54.773438 L 148.914062 55.554688 L 149.183594 56.347656 L 149.453125 57.144531 L 149.722656 57.945312 L 149.992188 58.753906 L 150.257812 59.570312 L 150.527344 60.390625 L 150.796875 61.21875 L 151.066406 62.050781 L 151.335938 62.886719 L 151.605469 63.730469 L 151.871094 64.578125 L 152.140625 65.433594 L 152.410156 66.292969 L 152.679688 67.15625 L 152.949219 68.023438 L 153.21875 68.894531 L 153.484375 69.773438 L 153.753906 70.652344 L 154.292969 72.425781 L 154.5625 73.320312 L 154.832031 74.21875 L 155.097656 75.117188 L 155.636719 76.929688 L 155.90625 77.839844 L 156.445312 79.667969 L 156.710938 80.585938 L 156.980469 81.507812 L 157.789062 84.285156 L 158.058594 85.21875 L 158.324219 86.148438 L 158.59375 87.082031 L 158.863281 88.019531 L 159.132812 88.953125 L 159.402344 89.890625 L 159.671875 90.832031 L 159.9375 91.769531 L 161.015625 95.535156 L 161.28125 96.476562 L 161.550781 97.421875 L 162.628906 101.1875 L 162.894531 102.128906 L 163.972656 105.878906 L 164.242188 106.8125 L 164.507812 107.746094 L 165.046875 109.605469 L 165.585938 111.457031 L 165.855469 112.378906 L 166.121094 113.300781 L 166.390625 114.21875 L 166.660156 115.132812 L 167.199219 116.953125 L 167.46875 117.859375 L 167.734375 118.761719 L 168.003906 119.660156 L 168.273438 120.554688 L 168.542969 121.445312 L 168.8125 122.332031 L 169.082031 123.214844 L 169.347656 124.09375 L 169.617188 124.96875 L 169.886719 125.839844 L 170.15625 126.707031 L 170.425781 127.566406 L 170.695312 128.421875 L 170.960938 129.273438 L 171.5 130.960938 L 172.039062 132.625 L 172.308594 133.449219 L 172.574219 134.265625 L 172.84375 135.078125 L 173.113281 135.882812 L 173.382812 136.683594 L 173.652344 137.476562 L 173.921875 138.265625 L 174.1875 139.042969 L 174.457031 139.816406 L 174.726562 140.585938 L 174.996094 141.34375 L 175.265625 142.097656 L 175.535156 142.84375 L 175.800781 143.582031 L 176.070312 144.3125 L 176.339844 145.035156 L 176.609375 145.75 L 176.878906 146.457031 L 177.144531 147.160156 L 177.414062 147.851562 L 177.683594 148.535156 L 177.953125 149.210938 L 178.222656 149.878906 L 178.492188 150.535156 L 178.757812 151.1875 L 179.027344 151.828125 L 179.296875 152.460938 L 179.566406 153.085938 L 179.835938 153.699219 L 180.105469 154.308594 L 180.371094 154.902344 L 180.640625 155.492188 L 180.910156 156.070312 L 181.179688 156.640625 L 181.449219 157.199219 L 181.71875 157.75 L 181.984375 158.289062 L 182.253906 158.820312 L 182.523438 159.339844 L 182.792969 159.851562 L 183.0625 160.351562 L 183.332031 160.84375 L 183.597656 161.324219 L 183.867188 161.792969 L 184.136719 162.253906 L 184.40625 162.703125 L 184.675781 163.140625 L 184.945312 163.570312 L 185.210938 163.988281 L 185.480469 164.394531 L 185.75 164.792969 L 186.019531 165.179688 L 186.289062 165.554688 L 186.558594 165.917969 L 186.824219 166.269531 L 187.09375 166.613281 L 187.363281 166.941406 L 187.632812 167.261719 L 187.902344 167.570312 L 188.171875 167.867188 L 188.4375 168.15625 L 188.707031 168.429688 L 188.976562 168.691406 L 189.246094 168.945312 L 189.515625 169.183594 L 189.785156 169.414062 L 190.050781 169.632812 L 190.320312 169.839844 L 190.589844 170.03125 L 190.859375 170.214844 L 191.128906 170.386719 L 191.394531 170.546875 L 191.664062 170.691406 L 191.933594 170.828125 L 192.203125 170.953125 L 192.472656 171.066406 L 192.742188 171.167969 L 193.007812 171.253906 L 193.277344 171.332031 L 193.546875 171.398438 L 193.816406 171.449219 L 194.085938 171.492188 L 194.355469 171.523438 L 194.621094 171.539062 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/discrete.svg b/documentation/ui/figure/discrete.svg
new file mode 100644
index 0000000..bb24450
--- /dev/null
+++ b/documentation/ui/figure/discrete.svg
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 153 L 54.019531 153 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 114 L 202 114 L 202 115 L 54.019531 115 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 76 L 202 76 L 202 77 L 54.019531 77 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 38 L 202 38 L 202 39 L 54.019531 39 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 132 L 202.601562 132 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 94 L 202.601562 94 L 202.601562 96 L 54.019531 96 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 56 L 202.601562 56 L 202.601562 58 L 54.019531 58 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 18 L 202.601562 18 L 202.601562 20 L 54.019531 20 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface196">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.515625 L 201.601562 152.515625 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 114.449219 L 201.601562 114.449219 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 76.386719 L 201.601562 76.386719 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 38.320312 L 201.601562 38.320312 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 133.480469 L 201.601562 133.480469 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 95.417969 L 201.601562 95.417969 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 57.355469 L 201.601562 57.355469 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 19.289062 L 201.601562 19.289062 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 64.445312 171.546875 C 64.445312 176.507812 57.007812 176.507812 57.007812 171.546875 C 57.007812 166.585938 64.445312 166.585938 64.445312 171.546875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 66.867188 160.5625 C 66.867188 165.523438 59.425781 165.523438 59.425781 160.5625 C 59.425781 155.601562 66.867188 155.601562 66.867188 160.5625 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 69.554688 148.355469 C 69.554688 153.316406 62.113281 153.316406 62.113281 148.355469 C 62.113281 143.394531 69.554688 143.394531 69.554688 148.355469 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 72.242188 136.152344 C 72.242188 141.113281 64.804688 141.113281 64.804688 136.152344 C 64.804688 131.191406 72.242188 131.191406 72.242188 136.152344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 74.933594 123.945312 C 74.933594 128.90625 67.492188 128.90625 67.492188 123.945312 C 67.492188 118.984375 74.933594 118.984375 74.933594 123.945312 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 77.621094 111.742188 C 77.621094 116.703125 70.179688 116.703125 70.179688 111.742188 C 70.179688 106.78125 77.621094 106.78125 77.621094 111.742188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 80.308594 99.535156 C 80.308594 104.496094 72.871094 104.496094 72.871094 99.535156 C 72.871094 94.578125 80.308594 94.578125 80.308594 99.535156 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 83 87.332031 C 83 92.292969 75.558594 92.292969 75.558594 87.332031 C 75.558594 82.371094 83 82.371094 83 87.332031 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 85.6875 75.128906 C 85.6875 80.085938 78.246094 80.085938 78.246094 75.128906 C 78.246094 70.167969 85.6875 70.167969 85.6875 75.128906 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 88.375 62.921875 C 88.375 67.882812 80.933594 67.882812 80.933594 62.921875 C 80.933594 57.960938 88.375 57.960938 88.375 62.921875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 91.066406 50.71875 C 91.066406 55.679688 83.625 55.679688 83.625 50.71875 C 83.625 45.757812 91.066406 45.757812 91.066406 50.71875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 93.753906 38.511719 C 93.753906 43.472656 86.3125 43.472656 86.3125 38.511719 C 86.3125 33.550781 93.753906 33.550781 93.753906 38.511719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 96.441406 26.308594 C 96.441406 31.269531 89 31.269531 89 26.308594 C 89 21.347656 96.441406 21.347656 96.441406 26.308594 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 99.132812 21.882812 C 99.132812 26.84375 91.691406 26.84375 91.691406 21.882812 C 91.691406 16.921875 99.132812 16.921875 99.132812 21.882812 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 101.820312 27.984375 C 101.820312 32.945312 94.378906 32.945312 94.378906 27.984375 C 94.378906 23.023438 101.820312 23.023438 101.820312 27.984375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 104.507812 34.089844 C 104.507812 39.046875 97.066406 39.046875 97.066406 34.089844 C 97.066406 29.128906 104.507812 29.128906 104.507812 34.089844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 107.195312 40.191406 C 107.195312 45.152344 99.757812 45.152344 99.757812 40.191406 C 99.757812 35.230469 107.195312 35.230469 107.195312 40.191406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 109.886719 46.292969 C 109.886719 51.253906 102.445312 51.253906 102.445312 46.292969 C 102.445312 41.332031 109.886719 41.332031 109.886719 46.292969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 112.574219 52.394531 C 112.574219 57.355469 105.132812 57.355469 105.132812 52.394531 C 105.132812 47.433594 112.574219 47.433594 112.574219 52.394531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 115.261719 58.496094 C 115.261719 63.457031 107.820312 63.457031 107.820312 58.496094 C 107.820312 53.539062 115.261719 53.539062 115.261719 58.496094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 117.953125 64.601562 C 117.953125 69.5625 110.511719 69.5625 110.511719 64.601562 C 110.511719 59.640625 117.953125 59.640625 117.953125 64.601562 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 120.640625 70.703125 C 120.640625 75.664062 113.199219 75.664062 113.199219 70.703125 C 113.199219 65.742188 120.640625 65.742188 120.640625 70.703125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 123.328125 76.804688 C 123.328125 81.765625 115.886719 81.765625 115.886719 76.804688 C 115.886719 71.84375 123.328125 71.84375 123.328125 76.804688 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 126.019531 82.90625 C 126.019531 87.867188 118.578125 87.867188 118.578125 82.90625 C 118.578125 77.945312 126.019531 77.945312 126.019531 82.90625 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 128.707031 89.011719 C 128.707031 93.972656 121.265625 93.972656 121.265625 89.011719 C 121.265625 84.050781 128.707031 84.050781 128.707031 89.011719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 131.394531 95.113281 C 131.394531 100.074219 123.953125 100.074219 123.953125 95.113281 C 123.953125 90.152344 131.394531 90.152344 131.394531 95.113281 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 134.082031 89.621094 C 134.082031 94.582031 126.644531 94.582031 126.644531 89.621094 C 126.644531 84.660156 134.082031 84.660156 134.082031 89.621094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 136.773438 83.519531 C 136.773438 88.480469 129.332031 88.480469 129.332031 83.519531 C 129.332031 78.558594 136.773438 78.558594 136.773438 83.519531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 139.460938 77.414062 C 139.460938 82.375 132.019531 82.375 132.019531 77.414062 C 132.019531 72.453125 139.460938 72.453125 139.460938 77.414062 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 142.148438 71.3125 C 142.148438 76.273438 134.707031 76.273438 134.707031 71.3125 C 134.707031 66.351562 142.148438 66.351562 142.148438 71.3125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 144.839844 65.210938 C 144.839844 70.171875 137.398438 70.171875 137.398438 65.210938 C 137.398438 60.25 144.839844 60.25 144.839844 65.210938 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 147.527344 59.109375 C 147.527344 64.070312 140.085938 64.070312 140.085938 59.109375 C 140.085938 54.148438 147.527344 54.148438 147.527344 59.109375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 150.214844 53.003906 C 150.214844 57.964844 142.773438 57.964844 142.773438 53.003906 C 142.773438 48.046875 150.214844 48.046875 150.214844 53.003906 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 152.90625 46.902344 C 152.90625 51.863281 145.464844 51.863281 145.464844 46.902344 C 145.464844 41.941406 152.90625 41.941406 152.90625 46.902344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 155.59375 40.800781 C 155.59375 45.761719 148.152344 45.761719 148.152344 40.800781 C 148.152344 35.839844 155.59375 35.839844 155.59375 40.800781 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 158.28125 34.699219 C 158.28125 39.660156 150.839844 39.660156 150.839844 34.699219 C 150.839844 29.738281 158.28125 29.738281 158.28125 34.699219 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 160.96875 28.597656 C 160.96875 33.554688 153.53125 33.554688 153.53125 28.597656 C 153.53125 23.636719 160.96875 23.636719 160.96875 28.597656 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 163.660156 22.492188 C 163.660156 27.453125 156.21875 27.453125 156.21875 22.492188 C 156.21875 17.53125 163.660156 17.53125 163.660156 22.492188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 166.347656 25.085938 C 166.347656 30.046875 158.90625 30.046875 158.90625 25.085938 C 158.90625 20.125 166.347656 20.125 166.347656 25.085938 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 169.035156 37.292969 C 169.035156 42.253906 161.597656 42.253906 161.597656 37.292969 C 161.597656 32.332031 169.035156 32.332031 169.035156 37.292969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 171.726562 49.496094 C 171.726562 54.457031 164.285156 54.457031 164.285156 49.496094 C 164.285156 44.535156 171.726562 44.535156 171.726562 49.496094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 174.414062 61.703125 C 174.414062 66.664062 166.972656 66.664062 166.972656 61.703125 C 166.972656 56.742188 174.414062 56.742188 174.414062 61.703125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 177.101562 73.90625 C 177.101562 78.867188 169.660156 78.867188 169.660156 73.90625 C 169.660156 68.945312 177.101562 68.945312 177.101562 73.90625 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 179.792969 86.113281 C 179.792969 91.070312 172.351562 91.070312 172.351562 86.113281 C 172.351562 81.152344 179.792969 81.152344 179.792969 86.113281 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 182.480469 98.316406 C 182.480469 103.277344 175.039062 103.277344 175.039062 98.316406 C 175.039062 93.355469 182.480469 93.355469 182.480469 98.316406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 185.167969 110.519531 C 185.167969 115.480469 177.726562 115.480469 177.726562 110.519531 C 177.726562 105.5625 185.167969 105.5625 185.167969 110.519531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 187.859375 122.726562 C 187.859375 127.6875 180.417969 127.6875 180.417969 122.726562 C 180.417969 117.765625 187.859375 117.765625 187.859375 122.726562 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 190.546875 134.929688 C 190.546875 139.890625 183.105469 139.890625 183.105469 134.929688 C 183.105469 129.96875 190.546875 129.96875 190.546875 134.929688 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 193.234375 147.136719 C 193.234375 152.097656 185.792969 152.097656 185.792969 147.136719 C 185.792969 142.175781 193.234375 142.175781 193.234375 147.136719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 195.921875 159.339844 C 195.921875 164.300781 188.484375 164.300781 188.484375 159.339844 C 188.484375 154.378906 195.921875 154.378906 195.921875 159.339844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 198.613281 171.546875 C 198.613281 176.507812 191.171875 176.507812 191.171875 171.546875 C 191.171875 166.585938 198.613281 166.585938 198.613281 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="136.917969"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="136.917969"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="136.917969"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="136.917969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="98.855469"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="98.855469"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="98.855469"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="98.855469"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="60.792969"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="60.792969"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="60.792969"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="60.792969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="22.726562"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="22.726562"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="22.726562"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="22.726562"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 133.480469 L 54.019531 133.480469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 95.417969 L 54.019531 95.417969 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 57.355469 L 54.019531 57.355469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 19.289062 L 54.019531 19.289062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/gaussian.svg b/documentation/ui/figure/gaussian.svg
new file mode 100644
index 0000000..3eddc70
--- /dev/null
+++ b/documentation/ui/figure/gaussian.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 158 L 202 158 L 202 160 L 54.019531 160 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 119 L 202 119 L 202 120 L 54.019531 120 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 80 L 202 80 L 202 81 L 54.019531 81 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 41 L 202 41 L 202 42 L 54.019531 42 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 177 L 202.601562 177 L 202.601562 179 L 54.019531 179 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 138 L 202.601562 138 L 202.601562 140 L 54.019531 140 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 99 L 202.601562 99 L 202.601562 101 L 54.019531 101 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 60 L 202.601562 60 L 202.601562 62 L 54.019531 62 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface206">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 158.855469 L 201.601562 158.855469 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 119.71875 L 201.601562 119.71875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 80.585938 L 201.601562 80.585938 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 41.449219 L 201.601562 41.449219 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 178.425781 L 201.601562 178.425781 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 139.289062 L 201.601562 139.289062 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 100.152344 L 201.601562 100.152344 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 61.015625 L 201.601562 61.015625 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 61.265625 171.195312 L 61.53125 171.011719 L 61.800781 170.828125 L 62.339844 170.445312 L 62.878906 170.046875 L 63.144531 169.839844 L 63.414062 169.632812 L 63.683594 169.417969 L 64.222656 168.980469 L 64.492188 168.753906 L 64.757812 168.519531 L 65.027344 168.285156 L 65.296875 168.046875 L 65.566406 167.800781 L 65.835938 167.550781 L 66.105469 167.296875 L 66.371094 167.039062 L 66.640625 166.777344 L 66.910156 166.507812 L 67.179688 166.234375 L 67.449219 165.957031 L 67.71875 165.671875 L 67.984375 165.382812 L 68.253906 165.089844 L 68.523438 164.789062 L 68.792969 164.484375 L 69.0625 164.175781 L 69.332031 163.859375 L 69.597656 163.539062 L 69.867188 163.214844 L 70.136719 162.882812 L 70.40625 162.542969 L 70.675781 162.199219 L 70.945312 161.851562 L 71.210938 161.496094 L 71.480469 161.136719 L 71.75 160.769531 L 72.019531 160.398438 L 72.289062 160.019531 L 72.558594 159.632812 L 72.824219 159.242188 L 73.09375 158.847656 L 73.632812 158.035156 L 73.902344 157.617188 L 74.167969 157.195312 L 74.4375 156.765625 L 74.707031 156.332031 L 74.976562 155.890625 L 75.246094 155.441406 L 75.515625 154.988281 L 75.78125 154.527344 L 76.050781 154.058594 L 76.320312 153.585938 L 76.589844 153.105469 L 76.859375 152.617188 L 77.128906 152.125 L 77.394531 151.621094 L 77.664062 151.113281 L 77.933594 150.597656 L 78.203125 150.078125 L 78.472656 149.550781 L 78.742188 149.015625 L 79.007812 148.472656 L 79.277344 147.921875 L 79.546875 147.367188 L 79.816406 146.804688 L 80.085938 146.234375 L 80.355469 145.65625 L 80.621094 145.070312 L 80.890625 144.480469 L 81.160156 143.882812 L 81.429688 143.277344 L 81.699219 142.664062 L 81.96875 142.046875 L 82.234375 141.417969 L 82.503906 140.785156 L 82.773438 140.144531 L 83.042969 139.5 L 83.3125 138.84375 L 83.582031 138.183594 L 83.847656 137.515625 L 84.117188 136.839844 L 84.386719 136.15625 L 84.65625 135.46875 L 84.925781 134.773438 L 85.195312 134.070312 L 85.460938 133.363281 L 85.730469 132.644531 L 86 131.921875 L 86.269531 131.195312 L 86.539062 130.457031 L 86.808594 129.714844 L 87.074219 128.964844 L 87.34375 128.210938 L 87.613281 127.449219 L 87.882812 126.679688 L 88.152344 125.90625 L 88.417969 125.125 L 88.6875 124.339844 L 88.957031 123.546875 L 89.226562 122.746094 L 89.496094 121.941406 L 89.765625 121.128906 L 90.03125 120.3125 L 90.300781 119.488281 L 90.570312 118.660156 L 90.839844 117.828125 L 91.109375 116.988281 L 91.378906 116.144531 L 91.644531 115.292969 L 91.914062 114.4375 L 92.183594 113.578125 L 92.453125 112.714844 L 92.722656 111.84375 L 92.992188 110.96875 L 93.257812 110.089844 L 93.527344 109.207031 L 94.066406 107.425781 L 94.605469 105.628906 L 94.871094 104.722656 L 95.140625 103.816406 L 95.679688 101.988281 L 95.949219 101.070312 L 96.21875 100.148438 L 96.484375 99.222656 L 97.023438 97.363281 L 97.5625 95.496094 L 97.832031 94.558594 L 98.097656 93.617188 L 98.636719 91.734375 L 98.90625 90.789062 L 99.175781 89.839844 L 99.445312 88.894531 L 99.710938 87.945312 L 99.980469 86.996094 L 100.25 86.042969 L 100.519531 85.09375 L 100.789062 84.140625 L 101.058594 83.191406 L 101.324219 82.238281 L 101.59375 81.289062 L 101.863281 80.335938 L 102.402344 78.4375 L 102.667969 77.492188 L 102.9375 76.542969 L 103.476562 74.652344 L 103.746094 73.710938 L 104.015625 72.773438 L 104.28125 71.835938 L 104.550781 70.898438 L 105.359375 68.109375 L 105.628906 67.1875 L 105.894531 66.269531 L 106.164062 65.351562 L 106.433594 64.441406 L 106.972656 62.628906 L 107.242188 61.730469 L 107.507812 60.835938 L 107.777344 59.949219 L 108.046875 59.066406 L 108.316406 58.1875 L 108.585938 57.316406 L 108.855469 56.449219 L 109.121094 55.589844 L 109.390625 54.734375 L 109.660156 53.886719 L 109.929688 53.046875 L 110.199219 52.210938 L 110.46875 51.386719 L 110.734375 50.566406 L 111.003906 49.757812 L 111.273438 48.953125 L 111.542969 48.15625 L 111.8125 47.371094 L 112.082031 46.589844 L 112.347656 45.820312 L 112.617188 45.0625 L 112.886719 44.308594 L 113.15625 43.566406 L 113.425781 42.832031 L 113.695312 42.109375 L 113.960938 41.394531 L 114.230469 40.691406 L 114.5 40 L 114.769531 39.316406 L 115.039062 38.644531 L 115.308594 37.984375 L 115.574219 37.332031 L 115.84375 36.695312 L 116.113281 36.066406 L 116.382812 35.449219 L 116.652344 34.847656 L 116.921875 34.253906 L 117.1875 33.675781 L 117.457031 33.105469 L 117.726562 32.550781 L 117.996094 32.007812 L 118.265625 31.476562 L 118.53125 30.960938 L 118.800781 30.457031 L 119.070312 29.964844 L 119.339844 29.488281 L 119.609375 29.023438 L 119.878906 28.574219 L 120.144531 28.136719 L 120.414062 27.710938 L 120.683594 27.304688 L 120.953125 26.910156 L 121.222656 26.527344 L 121.492188 26.160156 L 121.757812 25.808594 L 122.027344 25.472656 L 122.296875 25.148438 L 122.566406 24.839844 L 122.835938 24.546875 L 123.105469 24.269531 L 123.371094 24.007812 L 123.640625 23.757812 L 123.910156 23.523438 L 124.179688 23.308594 L 124.449219 23.105469 L 124.71875 22.917969 L 124.984375 22.746094 L 125.253906 22.589844 L 125.523438 22.449219 L 125.792969 22.324219 L 126.0625 22.210938 L 126.332031 22.117188 L 126.597656 22.039062 L 126.867188 21.976562 L 127.136719 21.929688 L 127.40625 21.898438 L 127.675781 21.882812 L 127.945312 21.882812 L 128.210938 21.898438 L 128.480469 21.929688 L 128.75 21.976562 L 129.019531 22.039062 L 129.289062 22.117188 L 129.558594 22.210938 L 129.824219 22.324219 L 130.09375 22.449219 L 130.363281 22.589844 L 130.632812 22.746094 L 130.902344 22.917969 L 131.171875 23.105469 L 131.4375 23.308594 L 131.707031 23.523438 L 131.976562 23.757812 L 132.246094 24.007812 L 132.515625 24.269531 L 132.78125 24.546875 L 133.050781 24.839844 L 133.320312 25.148438 L 133.589844 25.472656 L 133.859375 25.808594 L 134.128906 26.160156 L 134.394531 26.527344 L 134.664062 26.910156 L 134.933594 27.304688 L 135.203125 27.710938 L 135.472656 28.136719 L 135.742188 28.574219 L 136.007812 29.023438 L 136.277344 29.488281 L 136.546875 29.964844 L 136.816406 30.457031 L 137.085938 30.960938 L 137.355469 31.476562 L 137.621094 32.007812 L 137.890625 32.550781 L 138.160156 33.105469 L 138.429688 33.675781 L 138.699219 34.253906 L 138.96875 34.847656 L 139.234375 35.449219 L 139.503906 36.066406 L 139.773438 36.695312 L 140.042969 37.332031 L 140.3125 37.984375 L 140.582031 38.644531 L 140.847656 39.316406 L 141.117188 40 L 141.386719 40.691406 L 141.65625 41.394531 L 141.925781 42.109375 L 142.195312 42.832031 L 142.460938 43.566406 L 142.730469 44.308594 L 143 45.0625 L 143.269531 45.820312 L 143.539062 46.589844 L 143.808594 47.371094 L 144.074219 48.15625 L 144.34375 48.953125 L 144.613281 49.757812 L 144.882812 50.566406 L 145.152344 51.386719 L 145.421875 52.210938 L 145.6875 53.046875 L 145.957031 53.886719 L 146.226562 54.734375 L 146.496094 55.589844 L 146.765625 56.449219 L 147.03125 57.316406 L 147.300781 58.1875 L 147.570312 59.066406 L 147.839844 59.949219 L 148.109375 60.835938 L 148.378906 61.730469 L 148.644531 62.628906 L 149.183594 64.441406 L 149.453125 65.351562 L 149.992188 67.1875 L 150.257812 68.109375 L 151.066406 70.898438 L 151.605469 72.773438 L 151.871094 73.710938 L 152.140625 74.652344 L 152.679688 76.542969 L 152.949219 77.492188 L 153.21875 78.4375 L 153.484375 79.386719 L 153.753906 80.335938 L 154.023438 81.289062 L 154.292969 82.238281 L 154.5625 83.191406 L 154.832031 84.140625 L 155.097656 85.09375 L 155.367188 86.042969 L 155.636719 86.996094 L 156.175781 88.894531 L 156.445312 89.839844 L 156.710938 90.789062 L 156.980469 91.734375 L 157.789062 94.558594 L 158.058594 95.496094 L 158.324219 96.429688 L 158.59375 97.363281 L 159.132812 99.222656 L 159.402344 100.148438 L 159.671875 101.070312 L 159.9375 101.988281 L 160.476562 103.816406 L 161.015625 105.628906 L 161.28125 106.527344 L 161.550781 107.425781 L 162.089844 109.207031 L 162.359375 110.089844 L 162.628906 110.96875 L 162.894531 111.84375 L 163.164062 112.714844 L 163.433594 113.578125 L 163.703125 114.4375 L 163.972656 115.292969 L 164.242188 116.144531 L 164.507812 116.988281 L 164.777344 117.828125 L 165.046875 118.660156 L 165.316406 119.488281 L 165.585938 120.3125 L 165.855469 121.128906 L 166.121094 121.941406 L 166.390625 122.746094 L 166.660156 123.546875 L 166.929688 124.339844 L 167.199219 125.125 L 167.46875 125.90625 L 167.734375 126.679688 L 168.003906 127.449219 L 168.273438 128.210938 L 168.542969 128.964844 L 168.8125 129.714844 L 169.082031 130.457031 L 169.347656 131.195312 L 169.617188 131.921875 L 169.886719 132.644531 L 170.15625 133.363281 L 170.425781 134.070312 L 170.695312 134.773438 L 170.960938 135.46875 L 171.230469 136.15625 L 171.5 136.839844 L 171.769531 137.515625 L 172.039062 138.183594 L 172.308594 138.84375 L 172.574219 139.5 L 172.84375 140.144531 L 173.113281 140.785156 L 173.382812 141.417969 L 173.652344 142.046875 L 173.921875 142.664062 L 174.1875 143.277344 L 174.457031 143.882812 L 174.726562 144.480469 L 174.996094 145.070312 L 175.265625 145.65625 L 175.535156 146.234375 L 175.800781 146.804688 L 176.070312 147.367188 L 176.339844 147.921875 L 176.609375 148.472656 L 176.878906 149.015625 L 177.144531 149.550781 L 177.414062 150.078125 L 177.683594 150.597656 L 177.953125 151.113281 L 178.222656 151.621094 L 178.492188 152.125 L 178.757812 152.617188 L 179.027344 153.105469 L 179.296875 153.585938 L 179.566406 154.058594 L 179.835938 154.527344 L 180.105469 154.988281 L 180.371094 155.441406 L 180.640625 155.890625 L 180.910156 156.332031 L 181.179688 156.765625 L 181.449219 157.195312 L 181.71875 157.617188 L 181.984375 158.035156 L 182.523438 158.847656 L 182.792969 159.242188 L 183.0625 159.632812 L 183.332031 160.019531 L 183.597656 160.398438 L 183.867188 160.769531 L 184.136719 161.136719 L 184.40625 161.496094 L 184.675781 161.851562 L 184.945312 162.199219 L 185.210938 162.542969 L 185.480469 162.882812 L 185.75 163.214844 L 186.019531 163.539062 L 186.289062 163.859375 L 186.558594 164.175781 L 186.824219 164.484375 L 187.09375 164.789062 L 187.363281 165.089844 L 187.632812 165.382812 L 187.902344 165.671875 L 188.171875 165.957031 L 188.4375 166.234375 L 188.707031 166.507812 L 188.976562 166.777344 L 189.246094 167.039062 L 189.515625 167.296875 L 189.785156 167.550781 L 190.050781 167.800781 L 190.320312 168.046875 L 190.589844 168.285156 L 191.128906 168.753906 L 191.394531 168.980469 L 191.933594 169.417969 L 192.203125 169.632812 L 192.742188 170.046875 L 193.007812 170.246094 L 193.277344 170.445312 L 193.816406 170.828125 L 194.355469 171.195312 L 194.621094 171.371094 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="181.863281"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="181.863281"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="181.863281"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="181.863281"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="142.726562"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="142.726562"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="142.726562"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="142.726562"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="103.589844"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="103.589844"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="103.589844"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="103.589844"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="64.453125"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="64.453125"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="64.453125"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="64.453125"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 178.425781 L 54.019531 178.425781 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 139.289062 L 54.019531 139.289062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 100.152344 L 54.019531 100.152344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 61.015625 L 54.019531 61.015625 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/gaussianProduct.svg b/documentation/ui/figure/gaussianProduct.svg
new file mode 100644
index 0000000..0643bbd
--- /dev/null
+++ b/documentation/ui/figure/gaussianProduct.svg
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 3.171875 -2.375 L 3.171875 -5.421875 L 1.015625 -2.375 Z M 3.1875 0 L 3.1875 -1.640625 L 0.25 -1.640625 L 0.25 -2.46875 L 3.3125 -6.734375 L 4.03125 -6.734375 L 4.03125 -2.375 L 5.015625 -2.375 L 5.015625 -1.640625 L 4.03125 -1.640625 L 4.03125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 2.8125 -6.734375 C 3.5625 -6.734375 4.082031 -6.535156 4.375 -6.140625 C 4.664062 -5.753906 4.8125 -5.359375 4.8125 -4.953125 L 3.984375 -4.953125 C 3.929688 -5.210938 3.851562 -5.421875 3.75 -5.578125 C 3.539062 -5.859375 3.226562 -6 2.8125 -6 C 2.34375 -6 1.96875 -5.78125 1.6875 -5.34375 C 1.414062 -4.90625 1.265625 -4.28125 1.234375 -3.46875 C 1.421875 -3.75 1.664062 -3.960938 1.96875 -4.109375 C 2.226562 -4.234375 2.523438 -4.296875 2.859375 -4.296875 C 3.421875 -4.296875 3.910156 -4.113281 4.328125 -3.75 C 4.742188 -3.394531 4.953125 -2.863281 4.953125 -2.15625 C 4.953125 -1.539062 4.753906 -1 4.359375 -0.53125 C 3.960938 -0.0625 3.398438 0.171875 2.671875 0.171875 C 2.046875 0.171875 1.503906 -0.0625 1.046875 -0.53125 C 0.585938 -1.007812 0.359375 -1.816406 0.359375 -2.953125 C 0.359375 -3.785156 0.460938 -4.488281 0.671875 -5.0625 C 1.054688 -6.175781 1.769531 -6.734375 2.8125 -6.734375 Z M 2.75 -0.578125 C 3.1875 -0.578125 3.515625 -0.722656 3.734375 -1.015625 C 3.960938 -1.316406 4.078125 -1.671875 4.078125 -2.078125 C 4.078125 -2.421875 3.976562 -2.75 3.78125 -3.0625 C 3.582031 -3.375 3.222656 -3.53125 2.703125 -3.53125 C 2.335938 -3.53125 2.019531 -3.410156 1.75 -3.171875 C 1.476562 -2.929688 1.34375 -2.566406 1.34375 -2.078125 C 1.34375 -1.648438 1.460938 -1.289062 1.703125 -1 C 1.953125 -0.71875 2.300781 -0.578125 2.75 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 2.609375 -3.890625 C 2.984375 -3.890625 3.273438 -3.992188 3.484375 -4.203125 C 3.691406 -4.410156 3.796875 -4.660156 3.796875 -4.953125 C 3.796875 -5.203125 3.691406 -5.429688 3.484375 -5.640625 C 3.285156 -5.847656 2.984375 -5.953125 2.578125 -5.953125 C 2.171875 -5.953125 1.875 -5.847656 1.6875 -5.640625 C 1.507812 -5.429688 1.421875 -5.1875 1.421875 -4.90625 C 1.421875 -4.59375 1.535156 -4.34375 1.765625 -4.15625 C 2.003906 -3.976562 2.285156 -3.890625 2.609375 -3.890625 Z M 2.65625 -0.578125 C 3.050781 -0.578125 3.375 -0.679688 3.625 -0.890625 C 3.882812 -1.097656 4.015625 -1.414062 4.015625 -1.84375 C 4.015625 -2.269531 3.878906 -2.59375 3.609375 -2.8125 C 3.347656 -3.039062 3.007812 -3.15625 2.59375 -3.15625 C 2.195312 -3.15625 1.867188 -3.039062 1.609375 -2.8125 C 1.359375 -2.582031 1.234375 -2.265625 1.234375 -1.859375 C 1.234375 -1.515625 1.347656 -1.210938 1.578125 -0.953125 C 1.816406 -0.703125 2.175781 -0.578125 2.65625 -0.578125 Z M 1.46875 -3.578125 C 1.226562 -3.671875 1.039062 -3.785156 0.90625 -3.921875 C 0.664062 -4.171875 0.546875 -4.5 0.546875 -4.90625 C 0.546875 -5.40625 0.722656 -5.832031 1.078125 -6.1875 C 1.441406 -6.550781 1.957031 -6.734375 2.625 -6.734375 C 3.269531 -6.734375 3.773438 -6.5625 4.140625 -6.21875 C 4.503906 -5.875 4.6875 -5.476562 4.6875 -5.03125 C 4.6875 -4.613281 4.582031 -4.273438 4.375 -4.015625 C 4.25 -3.867188 4.0625 -3.722656 3.8125 -3.578125 C 4.09375 -3.453125 4.3125 -3.304688 4.46875 -3.140625 C 4.769531 -2.828125 4.921875 -2.421875 4.921875 -1.921875 C 4.921875 -1.335938 4.722656 -0.835938 4.328125 -0.421875 C 3.929688 -0.015625 3.367188 0.1875 2.640625 0.1875 C 1.984375 0.1875 1.429688 0.0078125 0.984375 -0.34375 C 0.535156 -0.695312 0.3125 -1.210938 0.3125 -1.890625 C 0.3125 -2.285156 0.40625 -2.625 0.59375 -2.90625 C 0.789062 -3.195312 1.082031 -3.421875 1.46875 -3.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-9">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 48.683594 14.398438 L 202 14.398438 L 202 180 L 48.683594 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 48.683594 153 L 202 153 L 202 155 L 48.683594 155 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 48.683594 114 L 202 114 L 202 116 L 48.683594 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 48.683594 75 L 202 75 L 202 77 L 48.683594 77 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 48.683594 36 L 202 36 L 202 38 L 48.683594 38 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 72 14.398438 L 74 14.398438 L 74 180 L 72 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 107 14.398438 L 109 14.398438 L 109 180 L 107 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 142 14.398438 L 143 14.398438 L 143 180 L 142 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 178 14.398438 L 178 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 48.683594 173 L 202.601562 173 L 202.601562 175 L 48.683594 175 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 48.683594 134 L 202.601562 134 L 202.601562 136 L 48.683594 136 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 48.683594 95 L 202.601562 95 L 202.601562 97 L 48.683594 97 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 48.683594 56 L 202.601562 56 L 202.601562 58 L 48.683594 58 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 48.683594 17 L 202.601562 17 L 202.601562 19 L 48.683594 19 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 55 14.398438 L 57 14.398438 L 57 180 L 55 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 89 14.398438 L 91 14.398438 L 91 180 L 89 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 124 14.398438 L 126 14.398438 L 126 180 L 124 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 159 14.398438 L 161 14.398438 L 161 180 L 159 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface211">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 48.683594 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 48.683594 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 154.214844 L 201.601562 154.214844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 115.226562 L 201.601562 115.226562 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 76.234375 L 201.601562 76.234375 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 37.242188 L 201.601562 37.242188 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 73.011719 179.027344 L 73.011719 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 107.765625 179.027344 L 107.765625 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 142.519531 179.027344 L 142.519531 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 177.273438 179.027344 L 177.273438 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 173.710938 L 201.601562 173.710938 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 134.71875 L 201.601562 134.71875 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 95.730469 L 201.601562 95.730469 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 56.738281 L 201.601562 56.738281 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 17.746094 L 201.601562 17.746094 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.632812 179.027344 L 55.632812 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 90.386719 179.027344 L 90.386719 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 125.140625 179.027344 L 125.140625 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 159.894531 179.027344 L 159.894531 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.648438 179.027344 L 194.648438 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 55.632812 171.546875 L 55.910156 171.480469 L 56.191406 171.414062 L 56.46875 171.34375 L 56.746094 171.269531 L 57.027344 171.199219 L 57.304688 171.121094 L 57.582031 171.046875 L 57.863281 170.964844 L 58.417969 170.800781 L 58.699219 170.714844 L 58.976562 170.628906 L 59.253906 170.539062 L 59.535156 170.445312 L 59.8125 170.351562 L 60.089844 170.253906 L 60.371094 170.152344 L 60.648438 170.050781 L 60.925781 169.945312 L 61.207031 169.839844 L 61.484375 169.730469 L 61.761719 169.617188 L 62.039062 169.5 L 62.320312 169.382812 L 62.597656 169.261719 L 62.875 169.136719 L 63.15625 169.011719 L 63.710938 168.746094 L 63.992188 168.609375 L 64.269531 168.472656 L 64.546875 168.328125 L 64.828125 168.183594 L 65.382812 167.878906 L 65.664062 167.722656 L 65.941406 167.5625 L 66.21875 167.398438 L 66.5 167.230469 L 67.054688 166.886719 L 67.335938 166.707031 L 67.613281 166.523438 L 67.890625 166.335938 L 68.167969 166.144531 L 68.449219 165.949219 L 68.726562 165.75 L 69.003906 165.546875 L 69.285156 165.335938 L 69.5625 165.125 L 69.839844 164.90625 L 70.121094 164.683594 L 70.398438 164.457031 L 70.675781 164.226562 L 70.957031 163.992188 L 71.234375 163.75 L 71.511719 163.503906 L 71.792969 163.253906 L 72.070312 162.996094 L 72.347656 162.734375 L 72.628906 162.46875 L 72.90625 162.199219 L 73.183594 161.921875 L 73.464844 161.636719 L 73.742188 161.351562 L 74.019531 161.054688 L 74.300781 160.757812 L 74.578125 160.453125 L 74.855469 160.140625 L 75.132812 159.824219 L 75.414062 159.5 L 75.691406 159.171875 L 75.96875 158.835938 L 76.25 158.496094 L 76.527344 158.148438 L 76.804688 157.792969 L 77.085938 157.433594 L 77.363281 157.066406 L 77.640625 156.695312 L 77.921875 156.316406 L 78.199219 155.929688 L 78.476562 155.535156 L 78.757812 155.132812 L 79.035156 154.726562 L 79.3125 154.3125 L 79.59375 153.890625 L 79.871094 153.464844 L 80.148438 153.027344 L 80.429688 152.585938 L 80.707031 152.136719 L 80.984375 151.679688 L 81.261719 151.214844 L 81.542969 150.742188 L 81.820312 150.261719 L 82.097656 149.773438 L 82.378906 149.28125 L 82.65625 148.777344 L 82.933594 148.265625 L 83.214844 147.746094 L 83.492188 147.222656 L 83.769531 146.6875 L 84.050781 146.144531 L 84.328125 145.59375 L 84.605469 145.035156 L 84.886719 144.46875 L 85.164062 143.894531 L 85.441406 143.3125 L 85.722656 142.71875 L 86 142.121094 L 86.277344 141.511719 L 86.558594 140.894531 L 86.835938 140.269531 L 87.113281 139.636719 L 87.390625 138.996094 L 87.671875 138.34375 L 87.949219 137.683594 L 88.226562 137.019531 L 88.507812 136.339844 L 88.785156 135.65625 L 89.0625 134.960938 L 89.34375 134.261719 L 89.621094 133.550781 L 89.898438 132.828125 L 90.179688 132.101562 L 90.457031 131.363281 L 90.734375 130.617188 L 91.015625 129.863281 L 91.292969 129.101562 L 91.570312 128.328125 L 91.851562 127.546875 L 92.128906 126.757812 L 92.40625 125.960938 L 92.6875 125.152344 L 92.964844 124.335938 L 93.242188 123.511719 L 93.519531 122.679688 L 93.800781 121.839844 L 94.078125 120.988281 L 94.355469 120.128906 L 94.636719 119.261719 L 94.914062 118.386719 L 95.191406 117.503906 L 95.472656 116.609375 L 95.75 115.710938 L 96.027344 114.800781 L 96.308594 113.882812 L 96.585938 112.957031 L 96.863281 112.023438 L 97.144531 111.082031 L 97.421875 110.132812 L 97.699219 109.175781 L 97.980469 108.210938 L 98.257812 107.238281 L 98.535156 106.253906 L 98.816406 105.265625 L 99.09375 104.269531 L 99.371094 103.265625 L 99.652344 102.257812 L 99.929688 101.238281 L 100.207031 100.214844 L 100.484375 99.179688 L 100.765625 98.140625 L 101.042969 97.097656 L 101.320312 96.042969 L 101.601562 94.984375 L 101.878906 93.917969 L 102.15625 92.847656 L 102.4375 91.769531 L 102.714844 90.683594 L 102.992188 89.59375 L 103.273438 88.5 L 103.550781 87.398438 L 103.828125 86.292969 L 104.109375 85.179688 L 104.386719 84.0625 L 104.664062 82.941406 L 104.945312 81.8125 L 105.5 79.546875 L 105.78125 78.40625 L 106.058594 77.261719 L 106.335938 76.113281 L 106.613281 74.960938 L 106.894531 73.804688 L 107.171875 72.644531 L 107.449219 71.480469 L 107.730469 70.316406 L 108.007812 69.148438 L 108.285156 67.976562 L 108.566406 66.804688 L 109.121094 64.453125 L 109.402344 63.273438 L 109.679688 62.09375 L 109.957031 60.910156 L 110.238281 59.726562 L 110.792969 57.359375 L 111.074219 56.175781 L 111.351562 54.992188 L 111.628906 53.816406 L 111.910156 52.65625 L 112.1875 51.507812 L 112.464844 50.375 L 112.742188 49.253906 L 113.023438 48.152344 L 113.300781 47.0625 L 113.578125 45.988281 L 113.859375 44.933594 L 114.136719 43.894531 L 114.414062 42.875 L 114.695312 41.871094 L 114.972656 40.886719 L 115.25 39.925781 L 115.53125 38.980469 L 115.808594 38.058594 L 116.085938 37.15625 L 116.367188 36.277344 L 116.644531 35.417969 L 116.921875 34.582031 L 117.203125 33.769531 L 117.480469 32.980469 L 117.757812 32.214844 L 118.039062 31.476562 L 118.316406 30.757812 L 118.59375 30.070312 L 118.875 29.402344 L 119.152344 28.765625 L 119.429688 28.152344 L 119.707031 27.566406 L 119.988281 27.007812 L 120.265625 26.476562 L 120.542969 25.972656 L 120.824219 25.496094 L 121.101562 25.050781 L 121.378906 24.632812 L 121.660156 24.242188 L 121.9375 23.882812 L 122.214844 23.550781 L 122.496094 23.25 L 122.773438 22.976562 L 123.050781 22.734375 L 123.332031 22.523438 L 123.609375 22.339844 L 123.886719 22.1875 L 124.167969 22.066406 L 124.445312 21.972656 L 124.722656 21.914062 L 125.003906 21.882812 L 125.28125 21.882812 L 125.558594 21.914062 L 125.835938 21.972656 L 126.117188 22.066406 L 126.394531 22.1875 L 126.671875 22.339844 L 126.953125 22.523438 L 127.230469 22.734375 L 127.507812 22.976562 L 127.789062 23.25 L 128.066406 23.550781 L 128.34375 23.882812 L 128.625 24.242188 L 128.902344 24.632812 L 129.179688 25.050781 L 129.460938 25.496094 L 129.738281 25.972656 L 130.015625 26.476562 L 130.296875 27.007812 L 130.574219 27.566406 L 130.851562 28.152344 L 131.132812 28.765625 L 131.410156 29.402344 L 131.6875 30.070312 L 131.964844 30.757812 L 132.246094 31.476562 L 132.523438 32.214844 L 132.800781 32.980469 L 133.082031 33.769531 L 133.359375 34.582031 L 133.636719 35.417969 L 133.917969 36.277344 L 134.195312 37.15625 L 134.472656 38.058594 L 134.753906 38.980469 L 135.03125 39.925781 L 135.308594 40.886719 L 135.589844 41.871094 L 135.867188 42.875 L 136.144531 43.894531 L 136.425781 44.933594 L 136.703125 45.988281 L 136.980469 47.0625 L 137.261719 48.152344 L 137.539062 49.253906 L 137.816406 50.375 L 138.09375 51.507812 L 138.375 52.65625 L 138.652344 53.816406 L 138.929688 54.992188 L 139.210938 56.175781 L 139.765625 58.542969 L 140.046875 59.726562 L 140.601562 62.09375 L 140.882812 63.273438 L 141.160156 64.453125 L 141.4375 65.628906 L 141.71875 66.804688 L 142.273438 69.148438 L 142.554688 70.316406 L 143.109375 72.644531 L 143.390625 73.804688 L 143.667969 74.960938 L 143.945312 76.113281 L 144.226562 77.261719 L 144.503906 78.40625 L 144.78125 79.546875 L 145.058594 80.679688 L 145.339844 81.8125 L 145.617188 82.941406 L 145.894531 84.0625 L 146.175781 85.179688 L 146.453125 86.292969 L 146.730469 87.398438 L 147.011719 88.5 L 147.289062 89.59375 L 147.566406 90.683594 L 147.847656 91.769531 L 148.125 92.847656 L 148.402344 93.917969 L 148.683594 94.984375 L 148.960938 96.042969 L 149.238281 97.097656 L 149.519531 98.140625 L 149.796875 99.179688 L 150.074219 100.214844 L 150.355469 101.238281 L 150.632812 102.257812 L 150.910156 103.265625 L 151.1875 104.269531 L 151.46875 105.265625 L 151.746094 106.253906 L 152.023438 107.238281 L 152.304688 108.210938 L 152.582031 109.175781 L 152.859375 110.132812 L 153.140625 111.082031 L 153.417969 112.023438 L 153.695312 112.957031 L 153.976562 113.882812 L 154.253906 114.800781 L 154.53125 115.710938 L 154.8125 116.609375 L 155.089844 117.503906 L 155.367188 118.386719 L 155.648438 119.261719 L 155.925781 120.128906 L 156.203125 120.988281 L 156.484375 121.839844 L 156.761719 122.679688 L 157.039062 123.511719 L 157.316406 124.335938 L 157.597656 125.152344 L 157.875 125.960938 L 158.152344 126.757812 L 158.433594 127.546875 L 158.710938 128.328125 L 158.988281 129.101562 L 159.269531 129.863281 L 159.546875 130.617188 L 159.824219 131.363281 L 160.105469 132.101562 L 160.382812 132.828125 L 160.660156 133.550781 L 160.941406 134.261719 L 161.21875 134.960938 L 161.496094 135.65625 L 161.777344 136.339844 L 162.054688 137.019531 L 162.332031 137.683594 L 162.613281 138.34375 L 162.890625 138.996094 L 163.167969 139.636719 L 163.445312 140.269531 L 163.726562 140.894531 L 164.003906 141.511719 L 164.28125 142.121094 L 164.5625 142.71875 L 164.839844 143.3125 L 165.117188 143.894531 L 165.398438 144.46875 L 165.675781 145.035156 L 165.953125 145.59375 L 166.234375 146.144531 L 166.511719 146.6875 L 166.789062 147.222656 L 167.070312 147.746094 L 167.347656 148.265625 L 167.625 148.777344 L 167.90625 149.28125 L 168.183594 149.773438 L 168.460938 150.261719 L 168.742188 150.742188 L 169.019531 151.214844 L 169.296875 151.679688 L 169.578125 152.136719 L 169.855469 152.585938 L 170.132812 153.027344 L 170.410156 153.464844 L 170.691406 153.890625 L 170.96875 154.3125 L 171.246094 154.726562 L 171.527344 155.132812 L 171.804688 155.535156 L 172.082031 155.929688 L 172.363281 156.316406 L 172.640625 156.695312 L 172.917969 157.066406 L 173.199219 157.433594 L 173.476562 157.792969 L 173.753906 158.148438 L 174.035156 158.496094 L 174.3125 158.835938 L 174.589844 159.171875 L 174.871094 159.5 L 175.148438 159.824219 L 175.425781 160.140625 L 175.707031 160.453125 L 175.984375 160.757812 L 176.539062 161.351562 L 176.820312 161.636719 L 177.097656 161.921875 L 177.375 162.199219 L 177.65625 162.46875 L 177.933594 162.734375 L 178.210938 162.996094 L 178.492188 163.253906 L 178.769531 163.503906 L 179.046875 163.75 L 179.328125 163.992188 L 179.605469 164.226562 L 179.882812 164.457031 L 180.164062 164.683594 L 180.441406 164.90625 L 180.71875 165.125 L 181 165.335938 L 181.277344 165.546875 L 181.554688 165.75 L 181.835938 165.949219 L 182.113281 166.144531 L 182.390625 166.335938 L 182.667969 166.523438 L 182.949219 166.707031 L 183.226562 166.886719 L 183.503906 167.058594 L 183.785156 167.230469 L 184.0625 167.398438 L 184.339844 167.5625 L 184.621094 167.722656 L 184.898438 167.878906 L 185.175781 168.03125 L 185.457031 168.183594 L 186.011719 168.472656 L 186.292969 168.609375 L 186.570312 168.746094 L 186.847656 168.878906 L 187.128906 169.011719 L 187.683594 169.261719 L 187.964844 169.382812 L 188.519531 169.617188 L 188.800781 169.730469 L 189.078125 169.839844 L 189.632812 170.050781 L 189.914062 170.152344 L 190.191406 170.253906 L 190.46875 170.351562 L 190.75 170.445312 L 191.027344 170.539062 L 191.304688 170.628906 L 191.585938 170.714844 L 191.863281 170.800781 L 192.140625 170.882812 L 192.421875 170.964844 L 192.699219 171.046875 L 192.976562 171.121094 L 193.257812 171.199219 L 193.535156 171.269531 L 193.8125 171.34375 L 194.09375 171.414062 L 194.648438 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="177.148438"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="177.148438"/>
+ <use xlink:href="#glyph0-1" x="36.262756" y="177.148438"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="138.15625"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="138.15625"/>
+ <use xlink:href="#glyph0-3" x="36.262756" y="138.15625"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="99.167969"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="99.167969"/>
+ <use xlink:href="#glyph0-4" x="36.262756" y="99.167969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="60.175781"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="60.175781"/>
+ <use xlink:href="#glyph0-5" x="36.262756" y="60.175781"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="21.183594"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="21.183594"/>
+ <use xlink:href="#glyph0-6" x="36.262756" y="21.183594"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 173.710938 L 48.683594 173.710938 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 134.71875 L 48.683594 134.71875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 95.730469 L 48.683594 95.730469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 56.738281 L 48.683594 56.738281 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 17.746094 L 48.683594 17.746094 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.632812 183.28125 L 55.632812 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 90.386719 183.28125 L 90.386719 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 125.140625 183.28125 L 125.140625 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 159.894531 183.28125 L 159.894531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.648438 183.28125 L 194.648438 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="46.296875" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="51.632462" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="54.297913" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.633499" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="81.050781" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="86.386368" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="89.051819" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="94.387405" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="115.804688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="121.140274" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="123.805725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="129.141312" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="150.558594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="155.89418" y="192.992188"/>
+ <use xlink:href="#glyph0-8" x="158.559631" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="163.895218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-9" x="185.3125" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.648087" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.313538" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.649124" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="122.140625" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/piShape.svg b/documentation/ui/figure/piShape.svg
new file mode 100644
index 0000000..ecf546c
--- /dev/null
+++ b/documentation/ui/figure/piShape.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface221">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.835938 L 201.601562 152.835938 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 60.996094 171.542969 L 61.265625 171.527344 L 61.53125 171.503906 L 61.800781 171.46875 L 62.070312 171.425781 L 62.339844 171.371094 L 62.609375 171.308594 L 62.878906 171.238281 L 63.144531 171.15625 L 63.414062 171.066406 L 63.683594 170.964844 L 63.953125 170.851562 L 64.222656 170.734375 L 64.492188 170.601562 L 64.757812 170.464844 L 65.027344 170.316406 L 65.296875 170.15625 L 65.566406 169.988281 L 65.835938 169.808594 L 66.105469 169.621094 L 66.371094 169.425781 L 66.640625 169.21875 L 66.910156 169.003906 L 67.179688 168.777344 L 67.449219 168.539062 L 67.71875 168.296875 L 67.984375 168.039062 L 68.253906 167.777344 L 68.523438 167.503906 L 68.792969 167.21875 L 69.0625 166.925781 L 69.332031 166.621094 L 69.597656 166.308594 L 69.867188 165.988281 L 70.136719 165.65625 L 70.40625 165.3125 L 70.675781 164.964844 L 70.945312 164.601562 L 71.210938 164.230469 L 71.480469 163.851562 L 71.75 163.460938 L 72.019531 163.0625 L 72.289062 162.65625 L 72.558594 162.238281 L 72.824219 161.808594 L 73.09375 161.371094 L 73.363281 160.925781 L 73.632812 160.46875 L 73.902344 160 L 74.167969 159.523438 L 74.4375 159.039062 L 74.707031 158.542969 L 74.976562 158.039062 L 75.246094 157.523438 L 75.515625 157 L 75.78125 156.464844 L 76.050781 155.921875 L 76.320312 155.371094 L 76.589844 154.808594 L 76.859375 154.234375 L 77.128906 153.652344 L 77.394531 153.0625 L 77.664062 152.460938 L 77.933594 151.851562 L 78.203125 151.230469 L 78.472656 150.601562 L 78.742188 149.960938 L 79.007812 149.3125 L 79.277344 148.652344 L 79.546875 147.984375 L 79.816406 147.304688 L 80.085938 146.617188 L 80.355469 145.921875 L 80.621094 145.214844 L 80.890625 144.5 L 81.160156 143.773438 L 81.429688 143.035156 L 81.699219 142.292969 L 81.96875 141.535156 L 82.234375 140.773438 L 82.503906 139.996094 L 82.773438 139.214844 L 83.042969 138.421875 L 83.3125 137.617188 L 83.582031 136.804688 L 83.847656 135.984375 L 84.117188 135.152344 L 84.386719 134.308594 L 84.65625 133.457031 L 84.925781 132.597656 L 85.195312 131.726562 L 85.460938 130.847656 L 85.730469 129.957031 L 86 129.058594 L 86.269531 128.148438 L 86.539062 127.230469 L 86.808594 126.304688 L 87.074219 125.367188 L 87.34375 124.417969 L 87.613281 123.460938 L 87.882812 122.496094 L 88.152344 121.519531 L 88.417969 120.53125 L 88.6875 119.539062 L 88.957031 118.53125 L 89.226562 117.519531 L 89.496094 116.492188 L 89.765625 115.460938 L 90.03125 114.417969 L 90.300781 113.363281 L 90.570312 112.300781 L 90.839844 111.230469 L 91.109375 110.148438 L 91.378906 109.054688 L 91.644531 107.953125 L 91.914062 106.84375 L 92.183594 105.722656 L 92.453125 104.59375 L 92.722656 103.453125 L 92.992188 102.304688 L 93.257812 101.144531 L 93.527344 99.976562 L 93.796875 98.796875 L 94.066406 97.609375 L 94.335938 96.414062 L 94.605469 95.222656 L 94.871094 94.039062 L 95.140625 92.867188 L 95.410156 91.703125 L 95.679688 90.546875 L 95.949219 89.402344 L 96.21875 88.269531 L 96.484375 87.144531 L 96.753906 86.027344 L 97.023438 84.921875 L 97.292969 83.824219 L 97.5625 82.738281 L 97.832031 81.660156 L 98.097656 80.59375 L 98.367188 79.535156 L 98.636719 78.488281 L 98.90625 77.449219 L 99.175781 76.421875 L 99.445312 75.402344 L 99.710938 74.390625 L 99.980469 73.390625 L 100.25 72.402344 L 100.519531 71.417969 L 100.789062 70.449219 L 101.058594 69.488281 L 101.324219 68.535156 L 101.59375 67.59375 L 101.863281 66.660156 L 102.132812 65.734375 L 102.402344 64.824219 L 102.667969 63.917969 L 102.9375 63.023438 L 103.207031 62.140625 L 103.476562 61.265625 L 103.746094 60.398438 L 104.015625 59.542969 L 104.28125 58.695312 L 104.550781 57.859375 L 104.820312 57.03125 L 105.089844 56.214844 L 105.359375 55.40625 L 105.628906 54.609375 L 105.894531 53.820312 L 106.164062 53.042969 L 106.433594 52.273438 L 106.703125 51.511719 L 106.972656 50.761719 L 107.242188 50.023438 L 107.507812 49.292969 L 107.777344 48.570312 L 108.046875 47.859375 L 108.316406 47.15625 L 108.585938 46.464844 L 108.855469 45.78125 L 109.121094 45.109375 L 109.390625 44.445312 L 109.660156 43.789062 L 109.929688 43.144531 L 110.199219 42.511719 L 110.46875 41.886719 L 110.734375 41.269531 L 111.003906 40.664062 L 111.273438 40.070312 L 111.542969 39.480469 L 111.8125 38.90625 L 112.082031 38.335938 L 112.347656 37.78125 L 112.617188 37.230469 L 112.886719 36.691406 L 113.15625 36.164062 L 113.425781 35.644531 L 113.695312 35.136719 L 113.960938 34.636719 L 114.230469 34.144531 L 114.5 33.664062 L 114.769531 33.191406 L 115.039062 32.730469 L 115.308594 32.277344 L 115.574219 31.835938 L 115.84375 31.402344 L 116.113281 30.980469 L 116.382812 30.566406 L 116.652344 30.164062 L 116.921875 29.769531 L 117.1875 29.382812 L 117.457031 29.007812 L 117.726562 28.644531 L 117.996094 28.289062 L 118.265625 27.941406 L 118.53125 27.605469 L 118.800781 27.277344 L 119.070312 26.960938 L 119.339844 26.652344 L 119.609375 26.355469 L 119.878906 26.066406 L 120.144531 25.789062 L 120.414062 25.519531 L 120.683594 25.257812 L 120.953125 25.007812 L 121.222656 24.769531 L 121.492188 24.539062 L 121.757812 24.316406 L 122.027344 24.105469 L 122.296875 23.902344 L 122.566406 23.710938 L 122.835938 23.527344 L 123.105469 23.355469 L 123.371094 23.191406 L 123.640625 23.039062 L 123.910156 22.894531 L 124.179688 22.757812 L 124.449219 22.632812 L 124.71875 22.519531 L 124.984375 22.410156 L 125.253906 22.316406 L 125.523438 22.230469 L 125.792969 22.152344 L 126.0625 22.085938 L 126.332031 22.027344 L 126.597656 21.980469 L 126.867188 21.941406 L 127.136719 21.910156 L 127.40625 21.894531 L 127.675781 21.882812 L 127.945312 21.882812 L 128.210938 21.894531 L 128.480469 21.910156 L 128.75 21.941406 L 129.019531 21.980469 L 129.289062 22.027344 L 129.558594 22.085938 L 129.824219 22.152344 L 130.09375 22.230469 L 130.363281 22.316406 L 130.632812 22.410156 L 130.902344 22.519531 L 131.171875 22.632812 L 131.4375 22.757812 L 131.707031 22.894531 L 131.976562 23.039062 L 132.246094 23.191406 L 132.515625 23.355469 L 132.78125 23.527344 L 133.050781 23.710938 L 133.320312 23.902344 L 133.589844 24.105469 L 133.859375 24.316406 L 134.128906 24.539062 L 134.394531 24.769531 L 134.664062 25.007812 L 134.933594 25.257812 L 135.203125 25.519531 L 135.472656 25.789062 L 135.742188 26.066406 L 136.007812 26.355469 L 136.277344 26.652344 L 136.546875 26.960938 L 136.816406 27.277344 L 137.085938 27.605469 L 137.355469 27.941406 L 137.621094 28.289062 L 137.890625 28.644531 L 138.160156 29.007812 L 138.429688 29.382812 L 138.699219 29.769531 L 138.96875 30.164062 L 139.234375 30.566406 L 139.503906 30.980469 L 139.773438 31.402344 L 140.042969 31.835938 L 140.3125 32.277344 L 140.582031 32.730469 L 140.847656 33.191406 L 141.117188 33.664062 L 141.386719 34.144531 L 141.65625 34.636719 L 141.925781 35.136719 L 142.195312 35.644531 L 142.460938 36.164062 L 142.730469 36.691406 L 143 37.230469 L 143.269531 37.78125 L 143.539062 38.335938 L 143.808594 38.90625 L 144.074219 39.480469 L 144.34375 40.070312 L 144.613281 40.664062 L 144.882812 41.269531 L 145.152344 41.886719 L 145.421875 42.511719 L 145.6875 43.144531 L 145.957031 43.789062 L 146.226562 44.445312 L 146.496094 45.109375 L 146.765625 45.78125 L 147.03125 46.464844 L 147.300781 47.15625 L 147.570312 47.859375 L 147.839844 48.570312 L 148.109375 49.292969 L 148.378906 50.023438 L 148.644531 50.761719 L 148.914062 51.511719 L 149.183594 52.273438 L 149.453125 53.042969 L 149.722656 53.820312 L 149.992188 54.609375 L 150.527344 56.214844 L 150.796875 57.03125 L 151.066406 57.859375 L 151.335938 58.695312 L 151.605469 59.542969 L 151.871094 60.398438 L 152.140625 61.265625 L 152.410156 62.140625 L 152.679688 63.023438 L 152.949219 63.917969 L 153.21875 64.824219 L 153.484375 65.734375 L 153.753906 66.660156 L 154.023438 67.59375 L 154.292969 68.535156 L 154.5625 69.488281 L 154.832031 70.449219 L 155.097656 71.417969 L 155.367188 72.402344 L 155.636719 73.390625 L 155.90625 74.390625 L 156.175781 75.402344 L 156.445312 76.421875 L 156.710938 77.449219 L 156.980469 78.488281 L 157.25 79.535156 L 157.519531 80.59375 L 157.789062 81.660156 L 158.058594 82.738281 L 158.324219 83.824219 L 158.59375 84.921875 L 158.863281 86.027344 L 159.132812 87.144531 L 159.402344 88.269531 L 159.671875 89.402344 L 159.9375 90.546875 L 160.207031 91.703125 L 160.476562 92.867188 L 160.746094 94.039062 L 161.015625 95.222656 L 161.28125 96.414062 L 161.550781 97.609375 L 161.820312 98.796875 L 162.089844 99.976562 L 162.359375 101.144531 L 162.628906 102.304688 L 162.894531 103.453125 L 163.164062 104.59375 L 163.433594 105.722656 L 163.703125 106.84375 L 163.972656 107.953125 L 164.242188 109.054688 L 164.507812 110.148438 L 164.777344 111.230469 L 165.046875 112.300781 L 165.316406 113.363281 L 165.585938 114.417969 L 165.855469 115.460938 L 166.121094 116.492188 L 166.390625 117.519531 L 166.660156 118.53125 L 166.929688 119.539062 L 167.199219 120.53125 L 167.46875 121.519531 L 167.734375 122.496094 L 168.003906 123.460938 L 168.273438 124.417969 L 168.542969 125.367188 L 168.8125 126.304688 L 169.082031 127.230469 L 169.347656 128.148438 L 169.617188 129.058594 L 169.886719 129.957031 L 170.15625 130.847656 L 170.425781 131.726562 L 170.695312 132.597656 L 170.960938 133.457031 L 171.230469 134.308594 L 171.5 135.152344 L 171.769531 135.984375 L 172.039062 136.804688 L 172.308594 137.617188 L 172.574219 138.421875 L 172.84375 139.214844 L 173.113281 139.996094 L 173.382812 140.773438 L 173.652344 141.535156 L 173.921875 142.292969 L 174.1875 143.035156 L 174.457031 143.773438 L 174.726562 144.5 L 174.996094 145.214844 L 175.265625 145.921875 L 175.535156 146.617188 L 175.800781 147.304688 L 176.070312 147.984375 L 176.339844 148.652344 L 176.609375 149.3125 L 176.878906 149.960938 L 177.144531 150.601562 L 177.414062 151.230469 L 177.683594 151.851562 L 177.953125 152.460938 L 178.222656 153.0625 L 178.492188 153.652344 L 178.757812 154.234375 L 179.027344 154.808594 L 179.296875 155.371094 L 179.566406 155.921875 L 179.835938 156.464844 L 180.105469 157 L 180.371094 157.523438 L 180.640625 158.039062 L 180.910156 158.542969 L 181.179688 159.039062 L 181.449219 159.523438 L 181.71875 160 L 181.984375 160.46875 L 182.253906 160.925781 L 182.523438 161.371094 L 182.792969 161.808594 L 183.0625 162.238281 L 183.332031 162.65625 L 183.597656 163.0625 L 183.867188 163.460938 L 184.136719 163.851562 L 184.40625 164.230469 L 184.675781 164.601562 L 184.945312 164.964844 L 185.210938 165.3125 L 185.480469 165.65625 L 185.75 165.988281 L 186.019531 166.308594 L 186.289062 166.621094 L 186.558594 166.925781 L 186.824219 167.21875 L 187.09375 167.503906 L 187.363281 167.777344 L 187.632812 168.039062 L 187.902344 168.296875 L 188.171875 168.539062 L 188.4375 168.777344 L 188.707031 169.003906 L 188.976562 169.21875 L 189.246094 169.425781 L 189.515625 169.621094 L 189.785156 169.808594 L 190.050781 169.988281 L 190.320312 170.15625 L 190.589844 170.316406 L 190.859375 170.464844 L 191.128906 170.601562 L 191.394531 170.734375 L 191.664062 170.851562 L 191.933594 170.964844 L 192.203125 171.066406 L 192.472656 171.15625 L 192.742188 171.238281 L 193.007812 171.308594 L 193.277344 171.371094 L 193.546875 171.425781 L 193.816406 171.46875 L 194.085938 171.503906 L 194.355469 171.527344 L 194.621094 171.542969 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/power.svg b/documentation/ui/figure/power.svg
new file mode 100644
index 0000000..8bb7b3d
--- /dev/null
+++ b/documentation/ui/figure/power.svg
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.421875 0 L 0.421875 -9.46875 L 7.9375 -9.46875 L 7.9375 0 Z M 6.75 -1.1875 L 6.75 -8.28125 L 1.609375 -8.28125 L 1.609375 -1.1875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 3.578125 -9.234375 C 4.765625 -9.234375 5.625 -8.738281 6.15625 -7.75 C 6.570312 -6.988281 6.78125 -5.945312 6.78125 -4.625 C 6.78125 -3.375 6.59375 -2.335938 6.21875 -1.515625 C 5.675781 -0.335938 4.789062 0.25 3.5625 0.25 C 2.457031 0.25 1.632812 -0.226562 1.09375 -1.1875 C 0.632812 -1.988281 0.40625 -3.066406 0.40625 -4.421875 C 0.40625 -5.472656 0.539062 -6.375 0.8125 -7.125 C 1.320312 -8.53125 2.242188 -9.234375 3.578125 -9.234375 Z M 3.5625 -0.8125 C 4.164062 -0.8125 4.644531 -1.078125 5 -1.609375 C 5.351562 -2.140625 5.53125 -3.128906 5.53125 -4.578125 C 5.53125 -5.628906 5.398438 -6.492188 5.140625 -7.171875 C 4.878906 -7.847656 4.378906 -8.1875 3.640625 -8.1875 C 2.960938 -8.1875 2.460938 -7.863281 2.140625 -7.21875 C 1.828125 -6.582031 1.671875 -5.640625 1.671875 -4.390625 C 1.671875 -3.441406 1.769531 -2.679688 1.96875 -2.109375 C 2.28125 -1.242188 2.8125 -0.8125 3.5625 -0.8125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.890625 -9.46875 L 2.046875 -9.46875 L 2.046875 0 L 0.890625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 3.59375 -0.75 C 4.363281 -0.75 4.890625 -1.039062 5.171875 -1.625 C 5.460938 -2.207031 5.609375 -2.851562 5.609375 -3.5625 C 5.609375 -4.207031 5.503906 -4.734375 5.296875 -5.140625 C 4.960938 -5.773438 4.398438 -6.09375 3.609375 -6.09375 C 2.898438 -6.09375 2.382812 -5.820312 2.0625 -5.28125 C 1.738281 -4.738281 1.578125 -4.082031 1.578125 -3.3125 C 1.578125 -2.582031 1.738281 -1.972656 2.0625 -1.484375 C 2.382812 -0.992188 2.894531 -0.75 3.59375 -0.75 Z M 3.640625 -7.109375 C 4.523438 -7.109375 5.273438 -6.8125 5.890625 -6.21875 C 6.503906 -5.625 6.8125 -4.75 6.8125 -3.59375 C 6.8125 -2.476562 6.539062 -1.554688 6 -0.828125 C 5.457031 -0.109375 4.617188 0.25 3.484375 0.25 C 2.535156 0.25 1.78125 -0.0664062 1.21875 -0.703125 C 0.65625 -1.347656 0.375 -2.210938 0.375 -3.296875 C 0.375 -4.460938 0.664062 -5.390625 1.25 -6.078125 C 1.84375 -6.765625 2.640625 -7.109375 3.640625 -7.109375 Z M 3.59375 -7.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.390625 -6.90625 L 2.71875 -1.46875 L 4.0625 -6.90625 L 5.359375 -6.90625 L 6.71875 -1.5 L 8.125 -6.90625 L 9.296875 -6.90625 L 7.28125 0 L 6.078125 0 L 4.671875 -5.34375 L 3.3125 0 L 2.109375 0 L 0.109375 -6.90625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 0.84375 -9.5 L 2.015625 -9.5 L 2.015625 -5.96875 C 2.285156 -6.3125 2.53125 -6.554688 2.75 -6.703125 C 3.125 -6.953125 3.59375 -7.078125 4.15625 -7.078125 C 5.15625 -7.078125 5.832031 -6.722656 6.1875 -6.015625 C 6.382812 -5.640625 6.484375 -5.109375 6.484375 -4.421875 L 6.484375 0 L 5.28125 0 L 5.28125 -4.359375 C 5.28125 -4.859375 5.21875 -5.226562 5.09375 -5.46875 C 4.882812 -5.84375 4.488281 -6.03125 3.90625 -6.03125 C 3.425781 -6.03125 2.988281 -5.863281 2.59375 -5.53125 C 2.207031 -5.207031 2.015625 -4.582031 2.015625 -3.65625 L 2.015625 0 L 0.84375 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.84375 -6.875 L 2.03125 -6.875 L 2.03125 0 L 0.84375 0 Z M 0.84375 -9.46875 L 2.03125 -9.46875 L 2.03125 -8.15625 L 0.84375 -8.15625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d="M 3.28125 -7.03125 C 3.820312 -7.03125 4.296875 -6.894531 4.703125 -6.625 C 4.921875 -6.476562 5.144531 -6.257812 5.375 -5.96875 L 5.375 -6.84375 L 6.453125 -6.84375 L 6.453125 -0.5625 C 6.453125 0.3125 6.320312 1.003906 6.0625 1.515625 C 5.582031 2.453125 4.671875 2.921875 3.328125 2.921875 C 2.585938 2.921875 1.960938 2.753906 1.453125 2.421875 C 0.953125 2.085938 0.671875 1.566406 0.609375 0.859375 L 1.78125 0.859375 C 1.84375 1.171875 1.957031 1.410156 2.125 1.578125 C 2.382812 1.828125 2.796875 1.953125 3.359375 1.953125 C 4.242188 1.953125 4.828125 1.640625 5.109375 1.015625 C 5.265625 0.648438 5.335938 -0.00390625 5.328125 -0.953125 C 5.097656 -0.609375 4.816406 -0.347656 4.484375 -0.171875 C 4.160156 -0.00390625 3.734375 0.078125 3.203125 0.078125 C 2.453125 0.078125 1.796875 -0.1875 1.234375 -0.71875 C 0.671875 -1.25 0.390625 -2.125 0.390625 -3.34375 C 0.390625 -4.5 0.671875 -5.398438 1.234375 -6.046875 C 1.804688 -6.703125 2.488281 -7.03125 3.28125 -7.03125 Z M 5.375 -3.484375 C 5.375 -4.335938 5.195312 -4.96875 4.84375 -5.375 C 4.488281 -5.789062 4.039062 -6 3.5 -6 C 2.6875 -6 2.128906 -5.617188 1.828125 -4.859375 C 1.660156 -4.441406 1.578125 -3.90625 1.578125 -3.25 C 1.578125 -2.46875 1.734375 -1.875 2.046875 -1.46875 C 2.367188 -1.0625 2.796875 -0.859375 3.328125 -0.859375 C 4.160156 -0.859375 4.75 -1.234375 5.09375 -1.984375 C 5.28125 -2.410156 5.375 -2.910156 5.375 -3.484375 Z M 3.421875 -7.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 1.265625 -6.53125 L 1.265625 -7.421875 C 2.097656 -7.503906 2.679688 -7.640625 3.015625 -7.828125 C 3.347656 -8.023438 3.597656 -8.476562 3.765625 -9.1875 L 4.671875 -9.1875 L 4.671875 0 L 3.4375 0 L 3.4375 -6.53125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0 -0.421875 L -9.46875 -0.421875 L -9.46875 -7.9375 L 0 -7.9375 Z M -1.1875 -6.75 L -8.28125 -6.75 L -8.28125 -1.609375 L -1.1875 -1.609375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M -9.234375 -3.578125 C -9.234375 -4.765625 -8.738281 -5.625 -7.75 -6.15625 C -6.988281 -6.570312 -5.945312 -6.78125 -4.625 -6.78125 C -3.375 -6.78125 -2.335938 -6.59375 -1.515625 -6.21875 C -0.335938 -5.675781 0.25 -4.789062 0.25 -3.5625 C 0.25 -2.457031 -0.226562 -1.632812 -1.1875 -1.09375 C -1.988281 -0.632812 -3.066406 -0.40625 -4.421875 -0.40625 C -5.472656 -0.40625 -6.375 -0.539062 -7.125 -0.8125 C -8.53125 -1.320312 -9.234375 -2.242188 -9.234375 -3.578125 Z M -0.8125 -3.5625 C -0.8125 -4.164062 -1.078125 -4.644531 -1.609375 -5 C -2.140625 -5.351562 -3.128906 -5.53125 -4.578125 -5.53125 C -5.628906 -5.53125 -6.492188 -5.398438 -7.171875 -5.140625 C -7.847656 -4.878906 -8.1875 -4.378906 -8.1875 -3.640625 C -8.1875 -2.960938 -7.863281 -2.460938 -7.21875 -2.140625 C -6.582031 -1.828125 -5.640625 -1.671875 -4.390625 -1.671875 C -3.441406 -1.671875 -2.679688 -1.769531 -2.109375 -1.96875 C -1.242188 -2.28125 -0.8125 -2.8125 -0.8125 -3.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-2">
+<path style="stroke:none;" d="M -1.40625 -1.125 L -1.40625 -2.46875 L 0 -2.46875 L 0 -1.125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-3">
+<path style="stroke:none;" d="M -2.359375 -1.625 C -1.691406 -1.707031 -1.234375 -2.015625 -0.984375 -2.546875 C -0.847656 -2.828125 -0.78125 -3.144531 -0.78125 -3.5 C -0.78125 -4.1875 -1 -4.695312 -1.4375 -5.03125 C -1.882812 -5.363281 -2.375 -5.53125 -2.90625 -5.53125 C -3.550781 -5.53125 -4.046875 -5.332031 -4.390625 -4.9375 C -4.742188 -4.550781 -4.921875 -4.082031 -4.921875 -3.53125 C -4.921875 -3.125 -4.84375 -2.773438 -4.6875 -2.484375 C -4.539062 -2.203125 -4.328125 -1.960938 -4.046875 -1.765625 L -4.109375 -0.765625 L -9.078125 -1.46875 L -9.078125 -6.265625 L -7.953125 -6.265625 L -7.953125 -2.328125 L -5.390625 -1.9375 C -5.554688 -2.15625 -5.675781 -2.359375 -5.75 -2.546875 C -5.894531 -2.890625 -5.96875 -3.289062 -5.96875 -3.75 C -5.96875 -4.59375 -5.691406 -5.304688 -5.140625 -5.890625 C -4.597656 -6.484375 -3.910156 -6.78125 -3.078125 -6.78125 C -2.203125 -6.78125 -1.429688 -6.507812 -0.765625 -5.96875 C -0.0976562 -5.425781 0.234375 -4.566406 0.234375 -3.390625 C 0.234375 -2.640625 0.0234375 -1.972656 -0.390625 -1.390625 C -0.816406 -0.816406 -1.472656 -0.492188 -2.359375 -0.421875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-4">
+<path style="stroke:none;" d="M -6.53125 -1.265625 L -7.421875 -1.265625 C -7.503906 -2.097656 -7.640625 -2.679688 -7.828125 -3.015625 C -8.023438 -3.347656 -8.476562 -3.597656 -9.1875 -3.765625 L -9.1875 -4.671875 L 0 -4.671875 L 0 -3.4375 L -6.53125 -3.4375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 0.578125 0 L 0.578125 -12.90625 L 10.828125 -12.90625 L 10.828125 0 Z M 9.21875 -1.625 L 9.21875 -11.296875 L 2.203125 -11.296875 L 2.203125 -1.625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M 1.53125 -12.90625 L 7.34375 -12.90625 C 8.5 -12.90625 9.425781 -12.582031 10.125 -11.9375 C 10.832031 -11.289062 11.1875 -10.382812 11.1875 -9.21875 C 11.1875 -8.207031 10.867188 -7.328125 10.234375 -6.578125 C 9.609375 -5.828125 8.644531 -5.453125 7.34375 -5.453125 L 3.28125 -5.453125 L 3.28125 0 L 1.53125 0 Z M 9.40625 -9.203125 C 9.40625 -10.148438 9.054688 -10.796875 8.359375 -11.140625 C 7.972656 -11.316406 7.441406 -11.40625 6.765625 -11.40625 L 3.28125 -11.40625 L 3.28125 -6.9375 L 6.765625 -6.9375 C 7.554688 -6.9375 8.191406 -7.101562 8.671875 -7.4375 C 9.160156 -7.769531 9.40625 -8.359375 9.40625 -9.203125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-2">
+<path style="stroke:none;" d="M 4.890625 -1.015625 C 5.941406 -1.015625 6.660156 -1.410156 7.046875 -2.203125 C 7.441406 -3.003906 7.640625 -3.890625 7.640625 -4.859375 C 7.640625 -5.734375 7.5 -6.445312 7.21875 -7 C 6.769531 -7.875 6 -8.3125 4.90625 -8.3125 C 3.945312 -8.3125 3.242188 -7.941406 2.796875 -7.203125 C 2.359375 -6.460938 2.140625 -5.570312 2.140625 -4.53125 C 2.140625 -3.53125 2.359375 -2.691406 2.796875 -2.015625 C 3.242188 -1.347656 3.941406 -1.015625 4.890625 -1.015625 Z M 4.953125 -9.6875 C 6.171875 -9.6875 7.195312 -9.28125 8.03125 -8.46875 C 8.875 -7.664062 9.296875 -6.476562 9.296875 -4.90625 C 9.296875 -3.382812 8.925781 -2.128906 8.1875 -1.140625 C 7.445312 -0.148438 6.300781 0.34375 4.75 0.34375 C 3.445312 0.34375 2.414062 -0.09375 1.65625 -0.96875 C 0.894531 -1.84375 0.515625 -3.019531 0.515625 -4.5 C 0.515625 -6.082031 0.914062 -7.34375 1.71875 -8.28125 C 2.519531 -9.21875 3.597656 -9.6875 4.953125 -9.6875 Z M 4.90625 -9.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-3">
+<path style="stroke:none;" d="M 1.890625 -9.40625 L 3.703125 -2 L 5.53125 -9.40625 L 7.3125 -9.40625 L 9.15625 -2.046875 L 11.078125 -9.40625 L 12.671875 -9.40625 L 9.9375 0 L 8.28125 0 L 6.375 -7.28125 L 4.515625 0 L 2.875 0 L 0.15625 -9.40625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-4">
+<path style="stroke:none;" d="M 5.078125 -9.625 C 5.742188 -9.625 6.390625 -9.46875 7.015625 -9.15625 C 7.648438 -8.84375 8.128906 -8.4375 8.453125 -7.9375 C 8.773438 -7.457031 8.988281 -6.90625 9.09375 -6.28125 C 9.1875 -5.84375 9.234375 -5.148438 9.234375 -4.203125 L 2.328125 -4.203125 C 2.359375 -3.242188 2.582031 -2.472656 3 -1.890625 C 3.425781 -1.316406 4.082031 -1.03125 4.96875 -1.03125 C 5.789062 -1.03125 6.445312 -1.304688 6.9375 -1.859375 C 7.21875 -2.171875 7.421875 -2.535156 7.546875 -2.953125 L 9.09375 -2.953125 C 9.050781 -2.609375 8.914062 -2.222656 8.6875 -1.796875 C 8.457031 -1.367188 8.195312 -1.019531 7.90625 -0.75 C 7.425781 -0.28125 6.832031 0.03125 6.125 0.1875 C 5.75 0.28125 5.316406 0.328125 4.828125 0.328125 C 3.660156 0.328125 2.671875 -0.09375 1.859375 -0.9375 C 1.046875 -1.789062 0.640625 -2.988281 0.640625 -4.53125 C 0.640625 -6.039062 1.046875 -7.265625 1.859375 -8.203125 C 2.679688 -9.148438 3.753906 -9.625 5.078125 -9.625 Z M 7.609375 -5.453125 C 7.535156 -6.140625 7.382812 -6.691406 7.15625 -7.109375 C 6.71875 -7.867188 5.992188 -8.25 4.984375 -8.25 C 4.253906 -8.25 3.644531 -7.984375 3.15625 -7.453125 C 2.664062 -6.929688 2.40625 -6.265625 2.375 -5.453125 Z M 4.9375 -9.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-5">
+<path style="stroke:none;" d="M 1.203125 -9.40625 L 2.703125 -9.40625 L 2.703125 -7.78125 C 2.828125 -8.101562 3.128906 -8.488281 3.609375 -8.9375 C 4.085938 -9.394531 4.644531 -9.625 5.28125 -9.625 C 5.300781 -9.625 5.347656 -9.617188 5.421875 -9.609375 C 5.492188 -9.609375 5.613281 -9.597656 5.78125 -9.578125 L 5.78125 -7.90625 C 5.6875 -7.925781 5.597656 -7.9375 5.515625 -7.9375 C 5.441406 -7.945312 5.359375 -7.953125 5.265625 -7.953125 C 4.460938 -7.953125 3.847656 -7.695312 3.421875 -7.1875 C 2.992188 -6.675781 2.78125 -6.085938 2.78125 -5.421875 L 2.78125 0 L 1.203125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 0.484375 0 L 0.484375 -10.765625 L 9.03125 -10.765625 L 9.03125 0 Z M 7.671875 -1.34375 L 7.671875 -9.40625 L 1.828125 -9.40625 L 1.828125 -1.34375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M 5.859375 -7.84375 L 7.328125 -7.84375 C 7.140625 -7.34375 6.726562 -6.195312 6.09375 -4.40625 C 5.613281 -3.050781 5.210938 -1.953125 4.890625 -1.109375 C 4.128906 0.890625 3.59375 2.109375 3.28125 2.546875 C 2.96875 2.992188 2.425781 3.21875 1.65625 3.21875 C 1.476562 3.21875 1.335938 3.207031 1.234375 3.1875 C 1.128906 3.175781 1.003906 3.148438 0.859375 3.109375 L 0.859375 1.90625 C 1.085938 1.96875 1.253906 2.003906 1.359375 2.015625 C 1.460938 2.035156 1.554688 2.046875 1.640625 2.046875 C 1.878906 2.046875 2.054688 2.003906 2.171875 1.921875 C 2.285156 1.847656 2.382812 1.753906 2.46875 1.640625 C 2.488281 1.597656 2.570312 1.394531 2.71875 1.03125 C 2.875 0.664062 2.984375 0.398438 3.046875 0.234375 L 0.15625 -7.84375 L 1.640625 -7.84375 L 3.75 -1.453125 Z M 3.75 -8.03125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -2.296875 -2.484375 C -1.585938 -2.484375 -1.113281 -2.550781 -0.875 -2.6875 C -0.632812 -2.832031 -0.515625 -3.085938 -0.515625 -3.453125 C -0.515625 -4.023438 -0.914062 -4.5 -1.71875 -4.875 C -2.519531 -5.25 -3.539062 -5.4375 -4.78125 -5.4375 L -6.734375 -5.4375 L -6.734375 -6.828125 L -1.8125 -6.828125 C -1.363281 -6.828125 -1.035156 -6.875 -0.828125 -6.96875 C -0.617188 -7.0625 -0.515625 -7.203125 -0.515625 -7.390625 C -0.515625 -7.609375 -0.617188 -7.769531 -0.828125 -7.875 C -1.035156 -7.988281 -1.34375 -8.046875 -1.75 -8.046875 L -1.953125 -8.046875 L -1.953125 -8.359375 C -1.910156 -8.359375 -1.863281 -8.359375 -1.8125 -8.359375 C -1.769531 -8.367188 -1.707031 -8.375 -1.625 -8.375 C -1.0625 -8.375 -0.628906 -8.253906 -0.328125 -8.015625 C -0.0234375 -7.773438 0.125 -7.441406 0.125 -7.015625 C 0.125 -6.515625 -0.0859375 -6.132812 -0.515625 -5.875 C -0.941406 -5.625 -1.585938 -5.5 -2.453125 -5.5 C -1.554688 -5.269531 -0.898438 -4.960938 -0.484375 -4.578125 C -0.078125 -4.191406 0.125 -3.707031 0.125 -3.125 C 0.125 -2.6875 -0.00390625 -2.320312 -0.265625 -2.03125 C -0.523438 -1.738281 -0.90625 -1.535156 -1.40625 -1.421875 C -1.320312 -1.410156 -1.179688 -1.40625 -0.984375 -1.40625 C -0.359375 -1.40625 0.34375 -1.566406 1.125 -1.890625 C 1.90625 -2.210938 2.363281 -2.375 2.5 -2.375 C 2.695312 -2.375 2.851562 -2.316406 2.96875 -2.203125 C 3.082031 -2.085938 3.140625 -1.9375 3.140625 -1.75 C 3.140625 -1.519531 3.054688 -1.351562 2.890625 -1.25 C 2.722656 -1.144531 2.457031 -1.09375 2.09375 -1.09375 C 2 -1.09375 1.707031 -1.101562 1.21875 -1.125 C 0.726562 -1.144531 0.28125 -1.15625 -0.125 -1.15625 C -0.476562 -1.15625 -0.984375 -1.144531 -1.640625 -1.125 C -2.296875 -1.113281 -2.769531 -1.109375 -3.0625 -1.109375 L -6.734375 -1.109375 L -6.734375 -2.484375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-0">
+<path style="stroke:none;" d="M 3.3125 -0.9375 L -13.21875 -0.9375 L -13.21875 -10.3125 L 3.3125 -10.3125 Z M 2.265625 -1.984375 L 2.265625 -9.265625 L -12.171875 -9.265625 L -12.171875 -1.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-1">
+<path style="stroke:none;" d="M -13.1875 -5.359375 C -12.25 -4.328125 -11.160156 -3.585938 -9.921875 -3.140625 C -8.679688 -2.703125 -7.019531 -2.484375 -4.9375 -2.484375 C -2.84375 -2.484375 -1.179688 -2.703125 0.046875 -3.140625 C 1.273438 -3.585938 2.359375 -4.328125 3.296875 -5.359375 L 3.6875 -4.984375 C 2.738281 -3.691406 1.503906 -2.679688 -0.015625 -1.953125 C -1.535156 -1.222656 -3.175781 -0.859375 -4.9375 -0.859375 C -6.695312 -0.859375 -8.335938 -1.222656 -9.859375 -1.953125 C -11.390625 -2.691406 -12.628906 -3.703125 -13.578125 -4.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-2">
+<path style="stroke:none;" d="M -13.1875 -0.875 L -13.578125 -1.234375 C -12.628906 -2.523438 -11.390625 -3.539062 -9.859375 -4.28125 C -8.328125 -5.019531 -6.6875 -5.390625 -4.9375 -5.390625 C -3.1875 -5.390625 -1.546875 -5.019531 -0.015625 -4.28125 C 1.503906 -3.539062 2.738281 -2.523438 3.6875 -1.234375 L 3.296875 -0.875 C 2.367188 -1.914062 1.289062 -2.65625 0.0625 -3.09375 C -1.164062 -3.53125 -2.832031 -3.75 -4.9375 -3.75 C -7.03125 -3.75 -8.691406 -3.53125 -9.921875 -3.09375 C -11.160156 -2.65625 -12.25 -1.914062 -13.1875 -0.875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph6-0">
+<path style="stroke:none;" d="M 0 -0.484375 L -10.765625 -0.484375 L -10.765625 -9.03125 L 0 -9.03125 Z M -1.34375 -7.671875 L -9.40625 -7.671875 L -9.40625 -1.828125 L -1.34375 -1.828125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph6-1">
+<path style="stroke:none;" d="M -7.84375 -5.859375 L -7.84375 -7.328125 C -7.34375 -7.140625 -6.195312 -6.726562 -4.40625 -6.09375 C -3.050781 -5.613281 -1.953125 -5.210938 -1.109375 -4.890625 C 0.890625 -4.128906 2.109375 -3.59375 2.546875 -3.28125 C 2.992188 -2.96875 3.21875 -2.425781 3.21875 -1.65625 C 3.21875 -1.476562 3.207031 -1.335938 3.1875 -1.234375 C 3.175781 -1.128906 3.148438 -1.003906 3.109375 -0.859375 L 1.90625 -0.859375 C 1.96875 -1.085938 2.003906 -1.253906 2.015625 -1.359375 C 2.035156 -1.460938 2.046875 -1.554688 2.046875 -1.640625 C 2.046875 -1.878906 2.003906 -2.054688 1.921875 -2.171875 C 1.847656 -2.285156 1.753906 -2.382812 1.640625 -2.46875 C 1.597656 -2.488281 1.394531 -2.570312 1.03125 -2.71875 C 0.664062 -2.875 0.398438 -2.984375 0.234375 -3.046875 L -7.84375 -0.15625 L -7.84375 -1.640625 L -1.453125 -3.75 Z M -8.03125 -3.75 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 53 17.28125 L 55 17.28125 L 55 179.5625 L 53 179.5625 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 90 17.28125 L 93 17.28125 L 93 179.5625 L 90 179.5625 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 128 17.28125 L 130 17.28125 L 130 179.5625 L 128 179.5625 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 165 17.28125 L 167 17.28125 L 167 179.5625 L 165 179.5625 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 202 17.28125 L 205 17.28125 L 205 179.5625 L 202 179.5625 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 43.199219 172 L 215.558594 172 L 215.558594 174 L 43.199219 174 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 43.199219 134 L 215.558594 134 L 215.558594 136 L 43.199219 136 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 43.199219 97 L 215.558594 97 L 215.558594 99 L 43.199219 99 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 43.199219 60 L 215.558594 60 L 215.558594 62 L 43.199219 62 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 43.199219 22 L 215.558594 22 L 215.558594 24 L 43.199219 24 Z "/>
+</clipPath>
+</defs>
+<g id="surface81">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 43.199219 178.558594 L 214.558594 178.558594 L 214.558594 17.28125 L 43.199219 17.28125 L 43.199219 178.558594 "/>
+<path style="fill:none;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.214844 172.585938 L 54.511719 171.390625 L 54.664062 170.792969 L 54.8125 170.191406 L 55.109375 168.996094 L 55.261719 168.398438 L 55.410156 167.796875 L 55.558594 167.199219 L 55.710938 166.601562 L 56.007812 165.40625 L 56.160156 164.804688 L 56.457031 163.609375 L 56.609375 163.011719 L 56.757812 162.410156 L 57.054688 161.214844 L 57.207031 160.617188 L 57.355469 160.015625 L 57.503906 159.417969 L 57.65625 158.820312 L 57.953125 157.625 L 58.105469 157.023438 L 58.550781 155.230469 L 58.703125 154.628906 L 59 153.433594 L 59.152344 152.835938 L 59.300781 152.238281 L 59.449219 151.636719 L 59.601562 151.039062 L 59.898438 149.84375 L 60.050781 149.242188 L 60.496094 147.449219 L 60.648438 146.851562 L 60.796875 146.25 L 60.945312 145.652344 L 61.097656 145.054688 L 61.246094 144.457031 L 61.394531 143.855469 L 61.546875 143.257812 L 61.84375 142.0625 L 61.996094 141.464844 L 62.144531 140.863281 L 62.441406 139.667969 L 62.59375 139.070312 L 62.742188 138.46875 L 62.890625 137.871094 L 63.042969 137.273438 L 63.339844 136.078125 L 63.492188 135.476562 L 63.9375 133.683594 L 64.089844 133.082031 L 64.386719 131.886719 L 64.539062 131.289062 L 64.6875 130.691406 L 64.835938 130.089844 L 64.988281 129.492188 L 65.285156 128.296875 L 65.4375 127.695312 L 65.882812 125.902344 L 66.035156 125.304688 L 66.183594 124.703125 L 66.332031 124.105469 L 66.484375 123.507812 L 66.632812 122.910156 L 66.78125 122.308594 L 66.933594 121.710938 L 67.230469 120.515625 L 67.382812 119.914062 L 67.828125 118.121094 L 67.980469 117.523438 L 68.128906 116.921875 L 68.277344 116.324219 L 68.429688 115.726562 L 68.578125 115.128906 L 68.726562 114.527344 L 68.878906 113.929688 L 69.175781 112.734375 L 69.328125 112.136719 L 69.476562 111.535156 L 69.773438 110.339844 L 69.925781 109.742188 L 70.074219 109.140625 L 70.222656 108.542969 L 70.375 107.945312 L 70.671875 106.75 L 70.824219 106.148438 L 71.269531 104.355469 L 71.421875 103.753906 L 71.71875 102.558594 L 71.871094 101.960938 L 72.019531 101.363281 L 72.167969 100.761719 L 72.320312 100.164062 L 72.617188 98.96875 L 72.769531 98.367188 L 73.214844 96.574219 L 73.367188 95.976562 L 73.515625 95.375 L 73.664062 94.777344 L 73.816406 94.179688 L 73.964844 93.582031 L 74.113281 92.980469 L 74.265625 92.382812 L 74.5625 91.1875 L 74.714844 90.589844 L 74.863281 89.988281 L 75.160156 88.792969 L 75.3125 88.195312 L 75.460938 87.59375 L 75.609375 86.996094 L 75.761719 86.398438 L 76.058594 85.203125 L 76.210938 84.601562 L 76.507812 83.40625 L 76.660156 82.808594 L 76.808594 82.207031 L 77.105469 81.011719 L 77.257812 80.414062 L 77.40625 79.816406 L 77.554688 79.214844 L 77.707031 78.617188 L 78.003906 77.421875 L 78.15625 76.820312 L 78.601562 75.027344 L 78.753906 74.425781 L 79.050781 73.230469 L 79.203125 72.632812 L 79.351562 72.035156 L 79.5 71.433594 L 79.652344 70.835938 L 79.949219 69.640625 L 80.101562 69.039062 L 80.546875 67.246094 L 80.699219 66.648438 L 80.847656 66.046875 L 80.996094 65.449219 L 81.148438 64.851562 L 81.296875 64.253906 L 81.445312 63.652344 L 81.597656 63.054688 L 81.894531 61.859375 L 82.046875 61.261719 L 82.195312 60.660156 L 82.492188 59.464844 L 82.644531 58.867188 L 82.792969 58.265625 L 82.941406 57.667969 L 83.09375 57.070312 L 83.390625 55.875 L 83.542969 55.273438 L 83.988281 53.480469 L 84.140625 52.878906 L 84.4375 51.683594 L 84.589844 51.085938 L 84.738281 50.488281 L 84.886719 49.886719 L 85.039062 49.289062 L 85.335938 48.09375 L 85.488281 47.492188 L 85.933594 45.699219 L 86.085938 45.101562 L 86.234375 44.5 L 86.382812 43.902344 L 86.535156 43.304688 L 86.683594 42.707031 L 86.832031 42.105469 L 86.984375 41.507812 L 87.28125 40.3125 L 87.433594 39.714844 L 87.582031 39.113281 L 87.878906 37.917969 L 88.03125 37.320312 L 88.179688 36.71875 L 88.328125 36.121094 L 88.480469 35.523438 L 88.628906 34.925781 L 88.777344 34.324219 L 88.929688 33.726562 L 89.226562 32.53125 L 89.378906 31.933594 L 89.527344 31.332031 L 89.824219 30.136719 L 89.976562 29.539062 L 90.125 28.9375 L 90.273438 28.339844 L 90.425781 27.742188 L 90.722656 26.546875 L 90.875 25.945312 L 91.320312 24.152344 L 91.472656 23.550781 L 91.621094 23.550781 L 91.769531 24.152344 L 91.921875 24.75 L 92.21875 25.945312 L 92.371094 26.546875 L 92.667969 27.742188 L 92.820312 28.339844 L 92.96875 28.9375 L 93.117188 29.539062 L 93.265625 30.136719 L 93.417969 30.734375 L 93.566406 31.332031 L 93.714844 31.933594 L 93.867188 32.53125 L 94.164062 33.726562 L 94.316406 34.324219 L 94.464844 34.925781 L 94.613281 35.523438 L 94.765625 36.121094 L 94.914062 36.71875 L 95.0625 37.320312 L 95.210938 37.917969 L 95.363281 38.515625 L 95.511719 39.113281 L 95.660156 39.714844 L 95.8125 40.3125 L 96.109375 41.507812 L 96.261719 42.105469 L 96.410156 42.707031 L 96.558594 43.304688 L 96.710938 43.902344 L 96.859375 44.5 L 97.007812 45.101562 L 97.15625 45.699219 L 97.308594 46.296875 L 97.605469 47.492188 L 97.757812 48.09375 L 98.054688 49.289062 L 98.207031 49.886719 L 98.355469 50.488281 L 98.652344 51.683594 L 98.804688 52.28125 L 98.953125 52.878906 L 99.101562 53.480469 L 99.253906 54.078125 L 99.550781 55.273438 L 99.703125 55.875 L 100 57.070312 L 100.152344 57.667969 L 100.300781 58.265625 L 100.449219 58.867188 L 100.597656 59.464844 L 100.75 60.0625 L 100.898438 60.660156 L 101.046875 61.261719 L 101.199219 61.859375 L 101.496094 63.054688 L 101.648438 63.652344 L 101.796875 64.253906 L 101.945312 64.851562 L 102.097656 65.449219 L 102.246094 66.046875 L 102.394531 66.648438 L 102.542969 67.246094 L 102.695312 67.84375 L 102.992188 69.039062 L 103.144531 69.640625 L 103.441406 70.835938 L 103.59375 71.433594 L 103.742188 72.035156 L 104.039062 73.230469 L 104.191406 73.828125 L 104.339844 74.425781 L 104.488281 75.027344 L 104.640625 75.625 L 104.9375 76.820312 L 105.089844 77.421875 L 105.386719 78.617188 L 105.539062 79.214844 L 105.6875 79.816406 L 105.984375 81.011719 L 106.136719 81.609375 L 106.285156 82.207031 L 106.433594 82.808594 L 106.585938 83.40625 L 106.882812 84.601562 L 107.035156 85.203125 L 107.332031 86.398438 L 107.484375 86.996094 L 107.632812 87.59375 L 107.78125 88.195312 L 107.929688 88.792969 L 108.082031 89.390625 L 108.230469 89.988281 L 108.378906 90.589844 L 108.53125 91.1875 L 108.828125 92.382812 L 108.980469 92.980469 L 109.128906 93.582031 L 109.277344 94.179688 L 109.429688 94.777344 L 109.578125 95.375 L 109.726562 95.976562 L 109.875 96.574219 L 110.027344 97.171875 L 110.324219 98.367188 L 110.476562 98.96875 L 110.773438 100.164062 L 110.925781 100.761719 L 111.074219 101.363281 L 111.371094 102.558594 L 111.523438 103.15625 L 111.671875 103.753906 L 111.820312 104.355469 L 111.972656 104.953125 L 112.269531 106.148438 L 112.421875 106.75 L 112.71875 107.945312 L 112.871094 108.542969 L 113.019531 109.140625 L 113.167969 109.742188 L 113.316406 110.339844 L 113.46875 110.9375 L 113.617188 111.535156 L 113.765625 112.136719 L 113.917969 112.734375 L 114.214844 113.929688 L 114.367188 114.527344 L 114.515625 115.128906 L 114.664062 115.726562 L 114.816406 116.324219 L 114.964844 116.921875 L 115.113281 117.523438 L 115.261719 118.121094 L 115.414062 118.71875 L 115.710938 119.914062 L 115.863281 120.515625 L 116.160156 121.710938 L 116.3125 122.308594 L 116.460938 122.910156 L 116.757812 124.105469 L 116.910156 124.703125 L 117.058594 125.304688 L 117.207031 125.902344 L 117.359375 126.5 L 117.65625 127.695312 L 117.808594 128.296875 L 118.105469 129.492188 L 118.257812 130.089844 L 118.40625 130.691406 L 118.703125 131.886719 L 118.855469 132.484375 L 119.003906 133.082031 L 119.152344 133.683594 L 119.304688 134.28125 L 119.601562 135.476562 L 119.753906 136.078125 L 120.050781 137.273438 L 120.203125 137.871094 L 120.351562 138.46875 L 120.5 139.070312 L 120.648438 139.667969 L 120.800781 140.265625 L 120.949219 140.863281 L 121.097656 141.464844 L 121.25 142.0625 L 121.546875 143.257812 L 121.699219 143.855469 L 121.847656 144.457031 L 121.996094 145.054688 L 122.148438 145.652344 L 122.296875 146.25 L 122.445312 146.851562 L 122.59375 147.449219 L 122.746094 148.046875 L 123.042969 149.242188 L 123.195312 149.84375 L 123.492188 151.039062 L 123.644531 151.636719 L 123.792969 152.238281 L 124.089844 153.433594 L 124.242188 154.03125 L 124.390625 154.628906 L 124.539062 155.230469 L 124.691406 155.828125 L 124.988281 157.023438 L 125.140625 157.625 L 125.4375 158.820312 L 125.589844 159.417969 L 125.738281 160.015625 L 125.886719 160.617188 L 126.035156 161.214844 L 126.1875 161.8125 L 126.335938 162.410156 L 126.484375 163.011719 L 126.636719 163.609375 L 126.933594 164.804688 L 127.085938 165.40625 L 127.382812 166.601562 L 127.535156 167.199219 L 127.683594 167.796875 L 127.832031 168.398438 L 127.980469 168.996094 L 128.132812 169.59375 L 128.28125 170.191406 L 128.429688 170.792969 L 128.582031 171.390625 L 128.878906 172.585938 "/>
+<path style="fill:none;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 91.546875 172.585938 L 91.695312 171.988281 L 91.847656 171.390625 L 91.996094 170.792969 L 92.144531 170.191406 L 92.292969 169.59375 L 92.445312 168.996094 L 92.59375 168.398438 L 92.742188 167.796875 L 92.894531 167.199219 L 93.191406 166.003906 L 93.34375 165.40625 L 93.492188 164.804688 L 93.640625 164.207031 L 93.792969 163.609375 L 93.941406 163.011719 L 94.089844 162.410156 L 94.238281 161.8125 L 94.390625 161.214844 L 94.539062 160.617188 L 94.6875 160.015625 L 94.839844 159.417969 L 95.136719 158.222656 L 95.289062 157.625 L 95.4375 157.023438 L 95.585938 156.425781 L 95.738281 155.828125 L 95.886719 155.230469 L 96.035156 154.628906 L 96.183594 154.03125 L 96.335938 153.433594 L 96.632812 152.238281 L 96.785156 151.636719 L 97.082031 150.441406 L 97.234375 149.84375 L 97.382812 149.242188 L 97.679688 148.046875 L 97.832031 147.449219 L 97.980469 146.851562 L 98.128906 146.25 L 98.28125 145.652344 L 98.578125 144.457031 L 98.730469 143.855469 L 99.027344 142.660156 L 99.179688 142.0625 L 99.328125 141.464844 L 99.476562 140.863281 L 99.625 140.265625 L 99.777344 139.667969 L 99.925781 139.070312 L 100.074219 138.46875 L 100.226562 137.871094 L 100.523438 136.675781 L 100.675781 136.078125 L 100.824219 135.476562 L 100.972656 134.878906 L 101.125 134.28125 L 101.273438 133.683594 L 101.421875 133.082031 L 101.570312 132.484375 L 101.722656 131.886719 L 102.019531 130.691406 L 102.171875 130.089844 L 102.46875 128.894531 L 102.621094 128.296875 L 102.769531 127.695312 L 102.917969 127.097656 L 103.070312 126.5 L 103.367188 125.304688 L 103.515625 124.703125 L 103.667969 124.105469 L 103.964844 122.910156 L 104.117188 122.308594 L 104.414062 121.113281 L 104.566406 120.515625 L 104.714844 119.914062 L 105.011719 118.71875 L 105.164062 118.121094 L 105.3125 117.523438 L 105.460938 116.921875 L 105.613281 116.324219 L 105.910156 115.128906 L 106.0625 114.527344 L 106.359375 113.332031 L 106.511719 112.734375 L 106.660156 112.136719 L 106.808594 111.535156 L 106.957031 110.9375 L 107.109375 110.339844 L 107.257812 109.742188 L 107.40625 109.140625 L 107.558594 108.542969 L 107.855469 107.347656 L 108.007812 106.75 L 108.15625 106.148438 L 108.304688 105.550781 L 108.457031 104.953125 L 108.605469 104.355469 L 108.753906 103.753906 L 108.902344 103.15625 L 109.054688 102.558594 L 109.351562 101.363281 L 109.503906 100.761719 L 109.800781 99.566406 L 109.953125 98.96875 L 110.101562 98.367188 L 110.398438 97.171875 L 110.550781 96.574219 L 110.699219 95.976562 L 110.847656 95.375 L 111 94.777344 L 111.296875 93.582031 L 111.449219 92.980469 L 111.746094 91.785156 L 111.898438 91.1875 L 112.046875 90.589844 L 112.195312 89.988281 L 112.34375 89.390625 L 112.496094 88.792969 L 112.644531 88.195312 L 112.792969 87.59375 L 112.945312 86.996094 L 113.242188 85.800781 L 113.394531 85.203125 L 113.542969 84.601562 L 113.691406 84.003906 L 113.84375 83.40625 L 113.992188 82.808594 L 114.140625 82.207031 L 114.289062 81.609375 L 114.441406 81.011719 L 114.738281 79.816406 L 114.890625 79.214844 L 115.1875 78.019531 L 115.339844 77.421875 L 115.488281 76.820312 L 115.636719 76.222656 L 115.789062 75.625 L 115.9375 75.027344 L 116.085938 74.425781 L 116.234375 73.828125 L 116.386719 73.230469 L 116.683594 72.035156 L 116.835938 71.433594 L 117.132812 70.238281 L 117.285156 69.640625 L 117.433594 69.039062 L 117.730469 67.84375 L 117.882812 67.246094 L 118.03125 66.648438 L 118.179688 66.046875 L 118.332031 65.449219 L 118.628906 64.253906 L 118.78125 63.652344 L 119.078125 62.457031 L 119.230469 61.859375 L 119.378906 61.261719 L 119.527344 60.660156 L 119.675781 60.0625 L 119.828125 59.464844 L 119.976562 58.867188 L 120.125 58.265625 L 120.277344 57.667969 L 120.574219 56.472656 L 120.726562 55.875 L 120.875 55.273438 L 121.023438 54.675781 L 121.175781 54.078125 L 121.324219 53.480469 L 121.472656 52.878906 L 121.621094 52.28125 L 121.773438 51.683594 L 122.070312 50.488281 L 122.222656 49.886719 L 122.519531 48.691406 L 122.671875 48.09375 L 122.820312 47.492188 L 122.96875 46.894531 L 123.121094 46.296875 L 123.417969 45.101562 L 123.566406 44.5 L 123.71875 43.902344 L 124.015625 42.707031 L 124.167969 42.105469 L 124.464844 40.910156 L 124.617188 40.3125 L 124.765625 39.714844 L 124.914062 39.113281 L 125.0625 38.515625 L 125.214844 37.917969 L 125.363281 37.320312 L 125.511719 36.71875 L 125.664062 36.121094 L 125.960938 34.925781 L 126.113281 34.324219 L 126.410156 33.128906 L 126.5625 32.53125 L 126.710938 31.933594 L 126.859375 31.332031 L 127.007812 30.734375 L 127.160156 30.136719 L 127.308594 29.539062 L 127.457031 28.9375 L 127.609375 28.339844 L 127.90625 27.144531 L 128.058594 26.546875 L 128.207031 25.945312 L 128.355469 25.347656 L 128.507812 24.75 L 128.65625 24.152344 L 128.804688 23.550781 L 128.953125 23.550781 L 129.105469 24.152344 L 129.402344 25.347656 L 129.554688 25.945312 L 129.703125 26.546875 L 129.851562 27.144531 L 130.003906 27.742188 L 130.300781 28.9375 L 130.449219 29.539062 L 130.601562 30.136719 L 130.898438 31.332031 L 131.050781 31.933594 L 131.347656 33.128906 L 131.5 33.726562 L 131.648438 34.324219 L 131.796875 34.925781 L 131.949219 35.523438 L 132.246094 36.71875 L 132.394531 37.320312 L 132.546875 37.917969 L 132.84375 39.113281 L 132.996094 39.714844 L 133.292969 40.910156 L 133.445312 41.507812 L 133.59375 42.105469 L 133.742188 42.707031 L 133.894531 43.304688 L 134.191406 44.5 L 134.339844 45.101562 L 134.492188 45.699219 L 134.789062 46.894531 L 134.941406 47.492188 L 135.089844 48.09375 L 135.238281 48.691406 L 135.390625 49.289062 L 135.539062 49.886719 L 135.6875 50.488281 L 135.839844 51.085938 L 136.285156 52.878906 L 136.4375 53.480469 L 136.734375 54.675781 L 136.886719 55.273438 L 137.035156 55.875 L 137.183594 56.472656 L 137.335938 57.070312 L 137.632812 58.265625 L 137.78125 58.867188 L 137.933594 59.464844 L 138.230469 60.660156 L 138.382812 61.261719 L 138.679688 62.457031 L 138.832031 63.054688 L 138.980469 63.652344 L 139.128906 64.253906 L 139.28125 64.851562 L 139.578125 66.046875 L 139.726562 66.648438 L 139.878906 67.246094 L 140.175781 68.441406 L 140.328125 69.039062 L 140.476562 69.640625 L 140.625 70.238281 L 140.777344 70.835938 L 140.925781 71.433594 L 141.074219 72.035156 L 141.226562 72.632812 L 141.671875 74.425781 L 141.824219 75.027344 L 142.121094 76.222656 L 142.273438 76.820312 L 142.421875 77.421875 L 142.570312 78.019531 L 142.722656 78.617188 L 142.871094 79.214844 L 143.019531 79.816406 L 143.167969 80.414062 L 143.320312 81.011719 L 143.617188 82.207031 L 143.769531 82.808594 L 144.066406 84.003906 L 144.21875 84.601562 L 144.367188 85.203125 L 144.515625 85.800781 L 144.667969 86.398438 L 144.964844 87.59375 L 145.113281 88.195312 L 145.265625 88.792969 L 145.5625 89.988281 L 145.714844 90.589844 L 146.011719 91.785156 L 146.164062 92.382812 L 146.3125 92.980469 L 146.460938 93.582031 L 146.613281 94.179688 L 146.910156 95.375 L 147.058594 95.976562 L 147.210938 96.574219 L 147.507812 97.769531 L 147.660156 98.367188 L 147.808594 98.96875 L 147.957031 99.566406 L 148.109375 100.164062 L 148.257812 100.761719 L 148.40625 101.363281 L 148.558594 101.960938 L 149.003906 103.753906 L 149.15625 104.355469 L 149.453125 105.550781 L 149.605469 106.148438 L 149.753906 106.75 L 149.902344 107.347656 L 150.054688 107.945312 L 150.351562 109.140625 L 150.5 109.742188 L 150.652344 110.339844 L 150.949219 111.535156 L 151.101562 112.136719 L 151.398438 113.332031 L 151.550781 113.929688 L 151.699219 114.527344 L 151.847656 115.128906 L 152 115.726562 L 152.296875 116.921875 L 152.445312 117.523438 L 152.597656 118.121094 L 152.894531 119.316406 L 153.046875 119.914062 L 153.195312 120.515625 L 153.34375 121.113281 L 153.496094 121.710938 L 153.644531 122.308594 L 153.792969 122.910156 L 153.945312 123.507812 L 154.242188 124.703125 L 154.390625 125.304688 L 154.542969 125.902344 L 154.839844 127.097656 L 154.992188 127.695312 L 155.140625 128.296875 L 155.289062 128.894531 L 155.441406 129.492188 L 155.589844 130.089844 L 155.738281 130.691406 L 155.890625 131.289062 L 156.335938 133.082031 L 156.488281 133.683594 L 156.785156 134.878906 L 156.9375 135.476562 L 157.085938 136.078125 L 157.234375 136.675781 L 157.386719 137.273438 L 157.683594 138.46875 L 157.832031 139.070312 L 157.984375 139.667969 L 158.28125 140.863281 L 158.433594 141.464844 L 158.730469 142.660156 L 158.882812 143.257812 L 159.03125 143.855469 L 159.179688 144.457031 L 159.332031 145.054688 L 159.628906 146.25 L 159.777344 146.851562 L 159.929688 147.449219 L 160.226562 148.644531 L 160.378906 149.242188 L 160.527344 149.84375 L 160.675781 150.441406 L 160.828125 151.039062 L 160.976562 151.636719 L 161.125 152.238281 L 161.277344 152.835938 L 161.722656 154.628906 L 161.875 155.230469 L 162.171875 156.425781 L 162.324219 157.023438 L 162.472656 157.625 L 162.621094 158.222656 L 162.773438 158.820312 L 163.070312 160.015625 L 163.21875 160.617188 L 163.371094 161.214844 L 163.667969 162.410156 L 163.820312 163.011719 L 164.117188 164.207031 L 164.269531 164.804688 L 164.417969 165.40625 L 164.566406 166.003906 L 164.71875 166.601562 L 165.015625 167.796875 L 165.164062 168.398438 L 165.316406 168.996094 L 165.613281 170.191406 L 165.765625 170.792969 L 166.0625 171.988281 L 166.214844 172.585938 "/>
+<path style="fill:none;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 128.878906 172.585938 L 129.03125 171.988281 L 129.328125 170.792969 L 129.480469 170.191406 L 129.925781 168.398438 L 130.078125 167.796875 L 130.375 166.601562 L 130.527344 166.003906 L 130.675781 165.40625 L 130.824219 164.804688 L 130.976562 164.207031 L 131.273438 163.011719 L 131.421875 162.410156 L 131.574219 161.8125 L 131.871094 160.617188 L 132.023438 160.015625 L 132.320312 158.820312 L 132.472656 158.222656 L 132.621094 157.625 L 132.769531 157.023438 L 132.921875 156.425781 L 133.21875 155.230469 L 133.367188 154.628906 L 133.519531 154.03125 L 133.816406 152.835938 L 133.96875 152.238281 L 134.117188 151.636719 L 134.265625 151.039062 L 134.417969 150.441406 L 134.566406 149.84375 L 134.714844 149.242188 L 134.867188 148.644531 L 135.3125 146.851562 L 135.464844 146.25 L 135.761719 145.054688 L 135.914062 144.457031 L 136.0625 143.855469 L 136.210938 143.257812 L 136.363281 142.660156 L 136.660156 141.464844 L 136.808594 140.863281 L 136.960938 140.265625 L 137.257812 139.070312 L 137.410156 138.46875 L 137.707031 137.273438 L 137.859375 136.675781 L 138.007812 136.078125 L 138.15625 135.476562 L 138.308594 134.878906 L 138.605469 133.683594 L 138.753906 133.082031 L 138.90625 132.484375 L 139.203125 131.289062 L 139.355469 130.691406 L 139.503906 130.089844 L 139.652344 129.492188 L 139.804688 128.894531 L 139.953125 128.296875 L 140.101562 127.695312 L 140.253906 127.097656 L 140.699219 125.304688 L 140.851562 124.703125 L 141.148438 123.507812 L 141.300781 122.910156 L 141.449219 122.308594 L 141.597656 121.710938 L 141.75 121.113281 L 141.898438 120.515625 L 142.046875 119.914062 L 142.199219 119.316406 L 142.644531 117.523438 L 142.796875 116.921875 L 143.09375 115.726562 L 143.246094 115.128906 L 143.394531 114.527344 L 143.542969 113.929688 L 143.695312 113.332031 L 143.992188 112.136719 L 144.140625 111.535156 L 144.292969 110.9375 L 144.589844 109.742188 L 144.742188 109.140625 L 145.039062 107.945312 L 145.191406 107.347656 L 145.339844 106.75 L 145.488281 106.148438 L 145.640625 105.550781 L 145.9375 104.355469 L 146.085938 103.753906 L 146.238281 103.15625 L 146.535156 101.960938 L 146.6875 101.363281 L 146.835938 100.761719 L 146.984375 100.164062 L 147.136719 99.566406 L 147.285156 98.96875 L 147.433594 98.367188 L 147.585938 97.769531 L 148.03125 95.976562 L 148.183594 95.375 L 148.480469 94.179688 L 148.632812 93.582031 L 148.78125 92.980469 L 148.929688 92.382812 L 149.082031 91.785156 L 149.378906 90.589844 L 149.53125 89.988281 L 149.976562 88.195312 L 150.128906 87.59375 L 150.425781 86.398438 L 150.578125 85.800781 L 150.726562 85.203125 L 150.875 84.601562 L 151.027344 84.003906 L 151.324219 82.808594 L 151.472656 82.207031 L 151.625 81.609375 L 151.921875 80.414062 L 152.074219 79.816406 L 152.222656 79.214844 L 152.371094 78.617188 L 152.523438 78.019531 L 152.671875 77.421875 L 152.820312 76.820312 L 152.972656 76.222656 L 153.269531 75.027344 L 153.417969 74.425781 L 153.570312 73.828125 L 153.867188 72.632812 L 154.019531 72.035156 L 154.167969 71.433594 L 154.316406 70.835938 L 154.46875 70.238281 L 154.617188 69.640625 L 154.765625 69.039062 L 154.917969 68.441406 L 155.363281 66.648438 L 155.515625 66.046875 L 155.8125 64.851562 L 155.964844 64.253906 L 156.113281 63.652344 L 156.261719 63.054688 L 156.414062 62.457031 L 156.710938 61.261719 L 156.859375 60.660156 L 157.011719 60.0625 L 157.308594 58.867188 L 157.460938 58.265625 L 157.757812 57.070312 L 157.910156 56.472656 L 158.058594 55.875 L 158.207031 55.273438 L 158.359375 54.675781 L 158.65625 53.480469 L 158.804688 52.878906 L 158.957031 52.28125 L 159.253906 51.085938 L 159.40625 50.488281 L 159.554688 49.886719 L 159.703125 49.289062 L 159.855469 48.691406 L 160.003906 48.09375 L 160.152344 47.492188 L 160.304688 46.894531 L 160.75 45.101562 L 160.902344 44.5 L 161.199219 43.304688 L 161.351562 42.707031 L 161.5 42.105469 L 161.648438 41.507812 L 161.800781 40.910156 L 162.097656 39.714844 L 162.25 39.113281 L 162.695312 37.320312 L 162.847656 36.71875 L 163.144531 35.523438 L 163.296875 34.925781 L 163.445312 34.324219 L 163.59375 33.726562 L 163.746094 33.128906 L 164.042969 31.933594 L 164.191406 31.332031 L 164.34375 30.734375 L 164.640625 29.539062 L 164.792969 28.9375 L 165.089844 27.742188 L 165.242188 27.144531 L 165.390625 26.546875 L 165.539062 25.945312 L 165.691406 25.347656 L 165.988281 24.152344 L 166.136719 23.550781 L 166.289062 23.550781 L 166.4375 24.152344 L 166.585938 24.75 L 166.738281 25.347656 L 166.886719 25.945312 L 167.035156 26.546875 L 167.1875 27.144531 L 167.484375 28.339844 L 167.636719 28.9375 L 167.785156 29.539062 L 168.082031 30.734375 L 168.234375 31.332031 L 168.382812 31.933594 L 168.53125 32.53125 L 168.683594 33.128906 L 168.980469 34.324219 L 169.132812 34.925781 L 169.578125 36.71875 L 169.730469 37.320312 L 170.027344 38.515625 L 170.179688 39.113281 L 170.328125 39.714844 L 170.476562 40.3125 L 170.628906 40.910156 L 170.925781 42.105469 L 171.078125 42.707031 L 171.523438 44.5 L 171.675781 45.101562 L 171.972656 46.296875 L 172.125 46.894531 L 172.273438 47.492188 L 172.421875 48.09375 L 172.574219 48.691406 L 172.871094 49.886719 L 173.023438 50.488281 L 173.46875 52.28125 L 173.621094 52.878906 L 173.769531 53.480469 L 173.917969 54.078125 L 174.070312 54.675781 L 174.21875 55.273438 L 174.367188 55.875 L 174.519531 56.472656 L 174.816406 57.667969 L 174.96875 58.265625 L 175.117188 58.867188 L 175.414062 60.0625 L 175.566406 60.660156 L 175.714844 61.261719 L 175.863281 61.859375 L 176.015625 62.457031 L 176.3125 63.652344 L 176.464844 64.253906 L 176.910156 66.046875 L 177.0625 66.648438 L 177.359375 67.84375 L 177.511719 68.441406 L 177.660156 69.039062 L 177.808594 69.640625 L 177.960938 70.238281 L 178.257812 71.433594 L 178.410156 72.035156 L 178.855469 73.828125 L 179.007812 74.425781 L 179.15625 75.027344 L 179.304688 75.625 L 179.457031 76.222656 L 179.605469 76.820312 L 179.753906 77.421875 L 179.90625 78.019531 L 180.203125 79.214844 L 180.355469 79.816406 L 180.800781 81.609375 L 180.953125 82.207031 L 181.101562 82.808594 L 181.25 83.40625 L 181.402344 84.003906 L 181.550781 84.601562 L 181.699219 85.203125 L 181.851562 85.800781 L 182.148438 86.996094 L 182.300781 87.59375 L 182.449219 88.195312 L 182.746094 89.390625 L 182.898438 89.988281 L 183.046875 90.589844 L 183.195312 91.1875 L 183.347656 91.785156 L 183.644531 92.980469 L 183.796875 93.582031 L 184.242188 95.375 L 184.394531 95.976562 L 184.691406 97.171875 L 184.84375 97.769531 L 184.992188 98.367188 L 185.140625 98.96875 L 185.292969 99.566406 L 185.589844 100.761719 L 185.742188 101.363281 L 186.1875 103.15625 L 186.339844 103.753906 L 186.488281 104.355469 L 186.636719 104.953125 L 186.789062 105.550781 L 186.9375 106.148438 L 187.085938 106.75 L 187.238281 107.347656 L 187.535156 108.542969 L 187.6875 109.140625 L 187.835938 109.742188 L 188.132812 110.9375 L 188.285156 111.535156 L 188.433594 112.136719 L 188.582031 112.734375 L 188.734375 113.332031 L 189.03125 114.527344 L 189.183594 115.128906 L 189.628906 116.921875 L 189.78125 117.523438 L 190.078125 118.71875 L 190.230469 119.316406 L 190.378906 119.914062 L 190.527344 120.515625 L 190.679688 121.113281 L 190.976562 122.308594 L 191.128906 122.910156 L 191.574219 124.703125 L 191.726562 125.304688 L 192.023438 126.5 L 192.175781 127.097656 L 192.324219 127.695312 L 192.472656 128.296875 L 192.625 128.894531 L 192.921875 130.089844 L 193.074219 130.691406 L 193.519531 132.484375 L 193.671875 133.082031 L 193.820312 133.683594 L 193.96875 134.28125 L 194.121094 134.878906 L 194.269531 135.476562 L 194.417969 136.078125 L 194.570312 136.675781 L 194.867188 137.871094 L 195.019531 138.46875 L 195.167969 139.070312 L 195.464844 140.265625 L 195.617188 140.863281 L 195.765625 141.464844 L 195.914062 142.0625 L 196.066406 142.660156 L 196.363281 143.855469 L 196.515625 144.457031 L 196.960938 146.25 L 197.113281 146.851562 L 197.410156 148.046875 L 197.5625 148.644531 L 197.710938 149.242188 L 197.859375 149.84375 L 198.011719 150.441406 L 198.308594 151.636719 L 198.460938 152.238281 L 198.90625 154.03125 L 199.058594 154.628906 L 199.207031 155.230469 L 199.355469 155.828125 L 199.507812 156.425781 L 199.65625 157.023438 L 199.804688 157.625 L 199.957031 158.222656 L 200.253906 159.417969 L 200.40625 160.015625 L 200.554688 160.617188 L 200.851562 161.8125 L 201.003906 162.410156 L 201.152344 163.011719 L 201.300781 163.609375 L 201.453125 164.207031 L 201.601562 164.804688 L 201.75 165.40625 L 201.902344 166.003906 L 202.347656 167.796875 L 202.5 168.398438 L 202.796875 169.59375 L 202.949219 170.191406 L 203.097656 170.792969 L 203.246094 171.390625 L 203.398438 171.988281 L 203.546875 172.585938 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.214844 178.558594 L 203.546875 178.558594 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.214844 178.558594 L 54.214844 185.761719 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 91.546875 178.558594 L 91.546875 185.761719 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 128.878906 178.558594 L 128.878906 185.761719 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 166.214844 178.558594 L 166.214844 185.761719 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 203.546875 178.558594 L 203.546875 185.761719 "/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="50.542969" y="197.28125"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph0-2" x="81.640625" y="197.28125"/>
+ <use xlink:href="#glyph0-3" x="84.573944" y="197.28125"/>
+ <use xlink:href="#glyph0-4" x="91.916901" y="197.28125"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph0-5" x="153.734375" y="197.28125"/>
+ <use xlink:href="#glyph0-6" x="161.077332" y="197.28125"/>
+ <use xlink:href="#glyph0-7" x="164.010651" y="197.28125"/>
+ <use xlink:href="#glyph0-5" x="171.353607" y="197.28125"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph0-8" x="192.53125" y="197.28125"/>
+ <use xlink:href="#glyph0-1" x="199.874207" y="197.28125"/>
+ <use xlink:href="#glyph0-1" x="207.217163" y="197.28125"/>
+</g>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 43.199219 172.585938 L 43.199219 23.253906 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 43.199219 172.585938 L 36 172.585938 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 43.199219 97.921875 L 36 97.921875 "/>
+<path style="fill:none;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 43.199219 23.253906 L 36 23.253906 "/>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="33.121094" y="181.761719"/>
+ <use xlink:href="#glyph1-2" x="33.121094" y="174.418762"/>
+ <use xlink:href="#glyph1-1" x="33.121094" y="170.750504"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="33.121094" y="107.097656"/>
+ <use xlink:href="#glyph1-2" x="33.121094" y="99.7547"/>
+ <use xlink:href="#glyph1-3" x="33.121094" y="96.086441"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-4" x="33.121094" y="32.429688"/>
+ <use xlink:href="#glyph1-2" x="33.121094" y="25.086731"/>
+ <use xlink:href="#glyph1-1" x="33.121094" y="21.418472"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="103.367188" y="14.398438"/>
+ <use xlink:href="#glyph2-2" x="115.373047" y="14.398438"/>
+ <use xlink:href="#glyph2-3" x="125.383789" y="14.398438"/>
+ <use xlink:href="#glyph2-4" x="138.382812" y="14.398438"/>
+ <use xlink:href="#glyph2-5" x="148.393555" y="14.398438"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="125.128906" y="211.679688"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="15.03125" y="112.234375"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-1" x="15.03125" y="103.59375"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-1" x="15.03125" y="97.347656"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-2" x="15.03125" y="89.847656"/>
+</g>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 54.214844 178.558594 L 54.214844 17.28125 "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 91.546875 178.558594 L 91.546875 17.28125 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 128.878906 178.558594 L 128.878906 17.28125 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 166.214844 178.558594 L 166.214844 17.28125 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 203.546875 178.558594 L 203.546875 17.28125 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 43.199219 172.585938 L 214.558594 172.585938 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 43.199219 135.253906 L 214.558594 135.253906 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 43.199219 97.921875 L 214.558594 97.921875 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 43.199219 60.585938 L 214.558594 60.585938 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.125;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:1.125,3.375;stroke-miterlimit:10;" d="M 43.199219 23.253906 L 214.558594 23.253906 "/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/ramp.svg b/documentation/ui/figure/ramp.svg
new file mode 100644
index 0000000..370fab3
--- /dev/null
+++ b/documentation/ui/figure/ramp.svg
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface251">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.839844 L 201.601562 152.839844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 87.34375 171.546875 L 87.613281 171.445312 L 88.152344 170.445312 L 88.417969 169.945312 L 89.765625 167.445312 L 90.03125 166.945312 L 90.300781 166.445312 L 90.570312 165.949219 L 91.378906 164.449219 L 91.644531 163.949219 L 92.992188 161.449219 L 93.257812 160.949219 L 94.605469 158.449219 L 94.871094 157.949219 L 96.21875 155.449219 L 96.484375 154.949219 L 97.832031 152.449219 L 98.097656 151.949219 L 98.90625 150.449219 L 99.175781 149.953125 L 99.445312 149.453125 L 99.710938 148.953125 L 101.058594 146.453125 L 101.324219 145.953125 L 102.402344 143.953125 L 102.667969 143.453125 L 104.015625 140.953125 L 104.28125 140.453125 L 105.628906 137.953125 L 105.894531 137.453125 L 107.242188 134.953125 L 107.507812 134.457031 L 108.855469 131.957031 L 109.121094 131.457031 L 110.46875 128.957031 L 110.734375 128.457031 L 112.082031 125.957031 L 112.347656 125.457031 L 113.695312 122.957031 L 113.960938 122.457031 L 115.308594 119.957031 L 115.574219 119.457031 L 115.84375 118.957031 L 116.113281 118.460938 L 116.921875 116.960938 L 117.1875 116.460938 L 118.265625 114.460938 L 118.53125 113.960938 L 119.878906 111.460938 L 120.144531 110.960938 L 121.492188 108.460938 L 121.757812 107.960938 L 123.105469 105.460938 L 123.371094 104.960938 L 124.179688 103.460938 L 124.449219 102.964844 L 124.71875 102.464844 L 124.984375 101.964844 L 126.332031 99.464844 L 126.597656 98.964844 L 127.945312 96.464844 L 128.210938 95.964844 L 129.558594 93.464844 L 129.824219 92.964844 L 131.171875 90.464844 L 131.4375 89.964844 L 132.515625 87.964844 L 132.78125 87.46875 L 134.128906 84.96875 L 134.394531 84.46875 L 135.742188 81.96875 L 136.007812 81.46875 L 137.355469 78.96875 L 137.621094 78.46875 L 138.96875 75.96875 L 139.234375 75.46875 L 140.582031 72.96875 L 140.847656 72.46875 L 141.117188 71.96875 L 141.386719 71.472656 L 142.195312 69.972656 L 142.460938 69.472656 L 143.808594 66.972656 L 144.074219 66.472656 L 145.421875 63.972656 L 145.6875 63.472656 L 146.765625 61.472656 L 147.03125 60.972656 L 148.378906 58.472656 L 148.644531 57.972656 L 149.453125 56.472656 L 149.722656 55.976562 L 149.992188 55.476562 L 150.257812 54.976562 L 151.605469 52.476562 L 151.871094 51.976562 L 153.21875 49.476562 L 153.484375 48.976562 L 154.832031 46.476562 L 155.097656 45.976562 L 156.445312 43.476562 L 156.710938 42.976562 L 158.058594 40.476562 L 158.324219 39.980469 L 159.671875 37.480469 L 159.9375 36.980469 L 161.015625 34.980469 L 161.28125 34.480469 L 162.628906 31.980469 L 162.894531 31.480469 L 164.242188 28.980469 L 164.507812 28.480469 L 165.855469 25.980469 L 166.121094 25.480469 L 166.390625 24.980469 L 166.660156 24.484375 L 167.46875 22.984375 L 167.734375 22.484375 L 168.003906 21.984375 L 168.273438 21.882812 L 194.890625 21.882812 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 21.882812 L 87.34375 21.882812 L 87.613281 21.984375 L 88.152344 22.984375 L 88.417969 23.484375 L 88.957031 24.484375 L 89.226562 24.980469 L 89.765625 25.980469 L 90.03125 26.480469 L 91.378906 28.980469 L 91.644531 29.480469 L 92.992188 31.980469 L 93.257812 32.480469 L 94.605469 34.980469 L 94.871094 35.480469 L 96.21875 37.980469 L 96.484375 38.480469 L 97.292969 39.980469 L 97.5625 40.476562 L 97.832031 40.976562 L 98.097656 41.476562 L 99.445312 43.976562 L 99.710938 44.476562 L 101.058594 46.976562 L 101.324219 47.476562 L 102.402344 49.476562 L 102.667969 49.976562 L 104.015625 52.476562 L 104.28125 52.976562 L 105.628906 55.476562 L 105.894531 55.976562 L 106.164062 56.472656 L 107.242188 58.472656 L 107.507812 58.972656 L 108.855469 61.472656 L 109.121094 61.972656 L 110.46875 64.472656 L 110.734375 64.972656 L 112.082031 67.472656 L 112.347656 67.972656 L 113.695312 70.472656 L 113.960938 70.972656 L 114.230469 71.472656 L 114.5 71.96875 L 115.308594 73.46875 L 115.574219 73.96875 L 116.921875 76.46875 L 117.1875 76.96875 L 118.265625 78.96875 L 118.53125 79.46875 L 119.878906 81.96875 L 120.144531 82.46875 L 121.492188 84.96875 L 121.757812 85.46875 L 122.835938 87.46875 L 123.105469 87.964844 L 123.371094 88.464844 L 124.71875 90.964844 L 124.984375 91.464844 L 126.332031 93.964844 L 126.597656 94.464844 L 127.945312 96.964844 L 128.210938 97.464844 L 129.558594 99.964844 L 129.824219 100.464844 L 131.171875 102.964844 L 131.4375 103.460938 L 132.515625 105.460938 L 132.78125 105.960938 L 134.128906 108.460938 L 134.394531 108.960938 L 135.742188 111.460938 L 136.007812 111.960938 L 137.355469 114.460938 L 137.621094 114.960938 L 138.96875 117.460938 L 139.234375 117.960938 L 139.503906 118.460938 L 139.773438 118.957031 L 140.582031 120.457031 L 140.847656 120.957031 L 142.195312 123.457031 L 142.460938 123.957031 L 143.808594 126.457031 L 144.074219 126.957031 L 145.421875 129.457031 L 145.6875 129.957031 L 146.765625 131.957031 L 147.03125 132.457031 L 148.109375 134.457031 L 148.378906 134.953125 L 148.644531 135.453125 L 149.992188 137.953125 L 150.257812 138.453125 L 151.605469 140.953125 L 151.871094 141.453125 L 153.21875 143.953125 L 153.484375 144.453125 L 154.832031 146.953125 L 155.097656 147.453125 L 156.445312 149.953125 L 156.710938 150.449219 L 158.058594 152.949219 L 158.324219 153.449219 L 159.671875 155.949219 L 159.9375 156.449219 L 161.015625 158.449219 L 161.28125 158.949219 L 162.628906 161.449219 L 162.894531 161.949219 L 164.242188 164.449219 L 164.507812 164.949219 L 165.046875 165.949219 L 165.316406 166.445312 L 165.855469 167.445312 L 166.121094 167.945312 L 167.46875 170.445312 L 167.734375 170.945312 L 168.003906 171.445312 L 168.273438 171.546875 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/rectangle.svg b/documentation/ui/figure/rectangle.svg
new file mode 100644
index 0000000..deb6c70
--- /dev/null
+++ b/documentation/ui/figure/rectangle.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface191">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.839844 L 201.601562 152.839844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 94.066406 171.546875 L 94.335938 21.882812 L 161.28125 21.882812 L 161.550781 171.546875 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/sShape.svg b/documentation/ui/figure/sShape.svg
new file mode 100644
index 0000000..3f24ed9
--- /dev/null
+++ b/documentation/ui/figure/sShape.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface261">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.839844 L 201.601562 152.839844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 60.996094 171.542969 L 61.265625 171.542969 L 61.53125 171.535156 L 61.800781 171.527344 L 62.339844 171.503906 L 62.609375 171.488281 L 62.878906 171.46875 L 63.144531 171.449219 L 63.683594 171.402344 L 63.953125 171.371094 L 64.222656 171.34375 L 64.492188 171.308594 L 64.757812 171.277344 L 65.296875 171.199219 L 65.835938 171.113281 L 66.105469 171.066406 L 66.371094 171.015625 L 66.640625 170.964844 L 66.910156 170.910156 L 67.71875 170.734375 L 67.984375 170.667969 L 68.523438 170.535156 L 68.792969 170.464844 L 69.332031 170.316406 L 69.597656 170.238281 L 70.136719 170.074219 L 70.40625 169.988281 L 70.945312 169.808594 L 71.210938 169.71875 L 72.019531 169.425781 L 72.289062 169.324219 L 72.558594 169.21875 L 72.824219 169.113281 L 73.09375 169.003906 L 73.632812 168.777344 L 73.902344 168.660156 L 74.167969 168.539062 L 74.707031 168.296875 L 75.515625 167.910156 L 75.78125 167.777344 L 76.320312 167.503906 L 76.589844 167.363281 L 77.128906 167.074219 L 77.394531 166.925781 L 78.203125 166.46875 L 78.742188 166.148438 L 79.007812 165.988281 L 79.277344 165.824219 L 79.546875 165.65625 L 80.355469 165.140625 L 80.621094 164.964844 L 80.890625 164.785156 L 81.429688 164.417969 L 81.96875 164.042969 L 82.234375 163.851562 L 82.503906 163.660156 L 82.773438 163.464844 L 83.042969 163.265625 L 83.582031 162.859375 L 83.847656 162.65625 L 84.117188 162.445312 L 84.386719 162.238281 L 84.925781 161.808594 L 85.195312 161.589844 L 85.460938 161.371094 L 86 160.925781 L 86.269531 160.695312 L 86.539062 160.46875 L 86.808594 160.234375 L 87.074219 160 L 87.34375 159.765625 L 88.152344 159.039062 L 88.417969 158.792969 L 88.957031 158.292969 L 89.226562 158.039062 L 89.765625 157.523438 L 90.03125 157.261719 L 90.300781 157 L 90.570312 156.734375 L 91.109375 156.195312 L 91.378906 155.921875 L 91.644531 155.648438 L 91.914062 155.371094 L 92.453125 154.808594 L 92.722656 154.523438 L 92.992188 154.234375 L 93.257812 153.945312 L 93.796875 153.359375 L 94.066406 153.0625 L 94.605469 152.460938 L 94.871094 152.15625 L 95.140625 151.851562 L 95.410156 151.542969 L 95.949219 150.917969 L 96.21875 150.601562 L 96.484375 150.28125 L 96.753906 149.960938 L 97.292969 149.3125 L 97.5625 148.984375 L 97.832031 148.652344 L 98.097656 148.320312 L 98.636719 147.648438 L 98.90625 147.304688 L 99.175781 146.964844 L 99.445312 146.617188 L 99.710938 146.273438 L 100.25 145.570312 L 100.789062 144.859375 L 101.058594 144.5 L 101.324219 144.136719 L 101.59375 143.773438 L 101.863281 143.40625 L 102.402344 142.664062 L 102.667969 142.292969 L 103.476562 141.15625 L 103.746094 140.773438 L 104.015625 140.386719 L 104.28125 139.996094 L 104.820312 139.214844 L 105.089844 138.820312 L 105.359375 138.421875 L 105.628906 138.019531 L 105.894531 137.617188 L 106.433594 136.804688 L 106.972656 135.984375 L 107.242188 135.566406 L 107.507812 135.152344 L 108.316406 133.886719 L 108.855469 133.027344 L 109.121094 132.597656 L 109.390625 132.164062 L 109.929688 131.289062 L 110.199219 130.847656 L 110.46875 130.402344 L 110.734375 129.957031 L 111.273438 129.058594 L 111.542969 128.605469 L 112.082031 127.691406 L 112.347656 127.230469 L 112.617188 126.769531 L 112.886719 126.304688 L 113.425781 125.367188 L 113.695312 124.894531 L 113.960938 124.417969 L 114.230469 123.941406 L 114.769531 122.980469 L 115.039062 122.496094 L 115.308594 122.007812 L 115.574219 121.519531 L 116.113281 120.535156 L 116.382812 120.035156 L 116.652344 119.539062 L 116.921875 119.035156 L 117.1875 118.53125 L 117.457031 118.027344 L 117.726562 117.519531 L 118.265625 116.496094 L 118.53125 115.980469 L 119.070312 114.941406 L 119.339844 114.417969 L 119.878906 113.363281 L 120.144531 112.832031 L 120.414062 112.300781 L 120.953125 111.230469 L 121.222656 110.6875 L 121.492188 110.148438 L 121.757812 109.601562 L 122.296875 108.507812 L 123.105469 106.84375 L 123.371094 106.285156 L 123.910156 105.160156 L 124.179688 104.59375 L 124.71875 103.453125 L 124.984375 102.878906 L 125.253906 102.304688 L 125.523438 101.726562 L 126.0625 100.5625 L 126.332031 99.976562 L 126.597656 99.390625 L 126.867188 98.800781 L 127.40625 97.613281 L 127.675781 97.015625 L 127.945312 96.414062 L 128.210938 95.816406 L 128.75 94.628906 L 129.019531 94.039062 L 129.558594 92.867188 L 129.824219 92.285156 L 130.09375 91.703125 L 130.632812 90.546875 L 130.902344 89.976562 L 131.171875 89.402344 L 131.4375 88.835938 L 131.707031 88.269531 L 132.246094 87.144531 L 132.515625 86.585938 L 132.78125 86.027344 L 133.050781 85.472656 L 133.320312 84.921875 L 134.128906 83.28125 L 134.394531 82.738281 L 134.664062 82.199219 L 135.472656 80.59375 L 135.742188 80.066406 L 136.007812 79.539062 L 136.277344 79.011719 L 136.546875 78.488281 L 137.085938 77.449219 L 137.355469 76.933594 L 137.621094 76.421875 L 137.890625 75.910156 L 138.429688 74.894531 L 138.699219 74.390625 L 138.96875 73.890625 L 139.234375 73.390625 L 139.503906 72.894531 L 140.042969 71.910156 L 140.582031 70.933594 L 140.847656 70.449219 L 141.386719 69.488281 L 141.925781 68.535156 L 142.195312 68.0625 L 142.460938 67.59375 L 142.730469 67.125 L 143 66.660156 L 143.808594 65.277344 L 144.074219 64.824219 L 144.613281 63.917969 L 144.882812 63.472656 L 145.152344 63.023438 L 145.421875 62.582031 L 145.6875 62.140625 L 146.226562 61.265625 L 146.765625 60.398438 L 147.03125 59.96875 L 147.300781 59.542969 L 148.109375 58.277344 L 148.378906 57.859375 L 148.644531 57.445312 L 149.453125 56.214844 L 149.992188 55.410156 L 150.257812 55.007812 L 150.527344 54.609375 L 151.066406 53.820312 L 151.335938 53.429688 L 151.605469 53.042969 L 151.871094 52.65625 L 152.410156 51.890625 L 152.679688 51.515625 L 152.949219 51.136719 L 153.21875 50.765625 L 153.484375 50.390625 L 154.023438 49.65625 L 154.5625 48.929688 L 154.832031 48.570312 L 155.097656 48.214844 L 155.367188 47.859375 L 155.90625 47.15625 L 156.175781 46.808594 L 156.445312 46.464844 L 156.710938 46.121094 L 156.980469 45.78125 L 157.519531 45.109375 L 158.058594 44.445312 L 158.324219 44.117188 L 158.863281 43.46875 L 159.402344 42.828125 L 159.671875 42.511719 L 159.9375 42.199219 L 160.207031 41.886719 L 160.476562 41.578125 L 161.015625 40.96875 L 161.28125 40.667969 L 161.550781 40.367188 L 162.089844 39.773438 L 162.628906 39.195312 L 162.894531 38.90625 L 163.164062 38.621094 L 163.703125 38.058594 L 164.242188 37.503906 L 164.507812 37.234375 L 164.777344 36.960938 L 165.585938 36.164062 L 165.855469 35.90625 L 166.121094 35.644531 L 166.660156 35.136719 L 167.199219 34.636719 L 167.46875 34.390625 L 167.734375 34.144531 L 168.003906 33.902344 L 168.273438 33.664062 L 169.082031 32.960938 L 169.347656 32.730469 L 169.617188 32.503906 L 170.425781 31.835938 L 170.695312 31.621094 L 170.960938 31.40625 L 171.230469 31.191406 L 171.5 30.980469 L 172.039062 30.566406 L 172.308594 30.363281 L 172.574219 30.164062 L 172.84375 29.964844 L 173.113281 29.769531 L 173.921875 29.195312 L 174.1875 29.011719 L 174.726562 28.644531 L 174.996094 28.464844 L 175.535156 28.113281 L 175.800781 27.941406 L 176.339844 27.605469 L 176.609375 27.441406 L 176.878906 27.28125 L 177.144531 27.121094 L 177.414062 26.960938 L 177.683594 26.808594 L 177.953125 26.652344 L 178.492188 26.355469 L 178.757812 26.210938 L 179.027344 26.066406 L 179.296875 25.925781 L 179.835938 25.652344 L 180.105469 25.519531 L 180.371094 25.386719 L 180.640625 25.261719 L 180.910156 25.132812 L 181.179688 25.011719 L 181.449219 24.886719 L 181.71875 24.769531 L 181.984375 24.652344 L 182.523438 24.425781 L 182.792969 24.316406 L 183.332031 24.105469 L 183.597656 24.003906 L 183.867188 23.902344 L 184.136719 23.804688 L 184.675781 23.617188 L 184.945312 23.527344 L 185.210938 23.441406 L 185.480469 23.355469 L 186.019531 23.191406 L 186.289062 23.113281 L 186.558594 23.039062 L 186.824219 22.964844 L 187.363281 22.824219 L 187.632812 22.757812 L 188.171875 22.632812 L 188.4375 22.574219 L 188.976562 22.464844 L 189.515625 22.363281 L 189.785156 22.316406 L 190.050781 22.273438 L 190.320312 22.230469 L 190.859375 22.152344 L 191.128906 22.117188 L 191.394531 22.085938 L 191.664062 22.054688 L 191.933594 22.027344 L 192.472656 21.980469 L 192.742188 21.960938 L 193.007812 21.941406 L 193.277344 21.925781 L 193.816406 21.902344 L 194.355469 21.886719 L 194.621094 21.882812 L 194.890625 21.882812 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/sigmoid.svg b/documentation/ui/figure/sigmoid.svg
new file mode 100644
index 0000000..4e58480
--- /dev/null
+++ b/documentation/ui/figure/sigmoid.svg
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface256">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.84375 L 201.601562 152.84375 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.425781 L 201.601562 115.425781 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.003906 L 201.601562 78.003906 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.585938 L 201.601562 40.585938 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.550781 L 201.601562 171.550781 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.132812 L 201.601562 134.132812 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.875 L 201.601562 21.875 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 21.882812 L 62.070312 21.882812 L 62.339844 21.886719 L 64.492188 21.886719 L 64.757812 21.890625 L 66.371094 21.890625 L 66.640625 21.894531 L 67.984375 21.894531 L 68.253906 21.898438 L 69.0625 21.898438 L 69.332031 21.902344 L 70.136719 21.902344 L 70.40625 21.90625 L 70.945312 21.90625 L 71.210938 21.910156 L 71.75 21.910156 L 72.019531 21.914062 L 72.558594 21.914062 L 72.824219 21.917969 L 73.09375 21.917969 L 73.363281 21.921875 L 73.632812 21.921875 L 73.902344 21.925781 L 74.167969 21.925781 L 74.4375 21.929688 L 74.707031 21.929688 L 74.976562 21.933594 L 75.246094 21.933594 L 75.515625 21.9375 L 75.78125 21.941406 L 76.050781 21.941406 L 76.859375 21.953125 L 77.128906 21.953125 L 77.394531 21.957031 L 78.742188 21.976562 L 79.007812 21.980469 L 80.085938 21.996094 L 80.355469 22.003906 L 80.621094 22.007812 L 80.890625 22.011719 L 81.160156 22.019531 L 81.429688 22.023438 L 81.96875 22.039062 L 82.234375 22.042969 L 83.582031 22.082031 L 83.847656 22.089844 L 84.386719 22.105469 L 84.65625 22.117188 L 84.925781 22.125 L 85.195312 22.136719 L 85.460938 22.148438 L 85.730469 22.160156 L 86 22.167969 L 86.269531 22.183594 L 86.808594 22.207031 L 87.074219 22.222656 L 87.34375 22.234375 L 88.152344 22.28125 L 88.417969 22.296875 L 88.6875 22.3125 L 89.765625 22.390625 L 90.03125 22.410156 L 91.378906 22.527344 L 91.644531 22.554688 L 91.914062 22.582031 L 92.183594 22.613281 L 92.453125 22.640625 L 92.722656 22.671875 L 92.992188 22.707031 L 93.257812 22.738281 L 93.527344 22.773438 L 93.796875 22.8125 L 94.066406 22.847656 L 94.335938 22.886719 L 94.605469 22.929688 L 94.871094 22.972656 L 95.140625 23.015625 L 95.679688 23.109375 L 96.21875 23.210938 L 96.484375 23.265625 L 97.292969 23.441406 L 97.5625 23.507812 L 97.832031 23.570312 L 98.097656 23.640625 L 98.367188 23.710938 L 98.636719 23.785156 L 99.175781 23.941406 L 99.445312 24.027344 L 99.710938 24.113281 L 99.980469 24.203125 L 100.25 24.296875 L 100.519531 24.394531 L 100.789062 24.496094 L 101.058594 24.601562 L 101.324219 24.710938 L 101.59375 24.824219 L 101.863281 24.941406 L 102.132812 25.0625 L 102.402344 25.191406 L 102.667969 25.324219 L 102.9375 25.460938 L 103.207031 25.605469 L 103.476562 25.753906 L 103.746094 25.90625 L 104.015625 26.066406 L 104.28125 26.234375 L 104.550781 26.40625 L 104.820312 26.585938 L 105.089844 26.773438 L 105.359375 26.964844 L 105.628906 27.167969 L 105.894531 27.375 L 106.164062 27.589844 L 106.433594 27.816406 L 106.703125 28.046875 L 106.972656 28.289062 L 107.242188 28.539062 L 107.507812 28.800781 L 107.777344 29.070312 L 108.046875 29.351562 L 108.316406 29.640625 L 108.585938 29.941406 L 108.855469 30.25 L 109.121094 30.574219 L 109.390625 30.90625 L 109.660156 31.253906 L 109.929688 31.613281 L 110.199219 31.984375 L 110.46875 32.367188 L 110.734375 32.765625 L 111.003906 33.179688 L 111.273438 33.605469 L 111.542969 34.042969 L 111.8125 34.5 L 112.082031 34.972656 L 112.347656 35.457031 L 112.617188 35.960938 L 112.886719 36.480469 L 113.15625 37.019531 L 113.425781 37.574219 L 113.695312 38.144531 L 113.960938 38.734375 L 114.230469 39.34375 L 114.5 39.972656 L 114.769531 40.617188 L 115.039062 41.285156 L 115.308594 41.972656 L 115.574219 42.679688 L 115.84375 43.410156 L 116.113281 44.160156 L 116.382812 44.929688 L 116.652344 45.722656 L 116.921875 46.535156 L 117.1875 47.375 L 117.457031 48.230469 L 117.726562 49.113281 L 117.996094 50.019531 L 118.265625 50.945312 L 118.53125 51.894531 L 118.800781 52.871094 L 119.070312 53.867188 L 119.339844 54.886719 L 119.609375 55.929688 L 119.878906 56.996094 L 120.144531 58.082031 L 120.414062 59.195312 L 120.683594 60.328125 L 120.953125 61.484375 L 121.222656 62.664062 L 121.492188 63.863281 L 121.757812 65.085938 L 122.027344 66.328125 L 122.296875 67.589844 L 122.566406 68.871094 L 122.835938 70.175781 L 123.105469 71.496094 L 123.371094 72.832031 L 123.640625 74.1875 L 123.910156 75.558594 L 124.179688 76.949219 L 124.449219 78.351562 L 124.71875 79.765625 L 124.984375 81.195312 L 125.253906 82.636719 L 125.523438 84.089844 L 125.792969 85.550781 L 126.0625 87.019531 L 126.332031 88.5 L 126.597656 89.984375 L 126.867188 91.472656 L 127.40625 94.464844 L 127.945312 97.464844 L 128.210938 98.964844 L 128.75 101.957031 L 129.019531 103.445312 L 129.289062 104.929688 L 129.558594 106.40625 L 129.824219 107.878906 L 130.09375 109.339844 L 130.363281 110.792969 L 130.632812 112.234375 L 130.902344 113.664062 L 131.171875 115.078125 L 131.4375 116.480469 L 131.707031 117.867188 L 131.976562 119.242188 L 132.246094 120.597656 L 132.515625 121.933594 L 132.78125 123.253906 L 133.050781 124.558594 L 133.320312 125.839844 L 133.589844 127.101562 L 133.859375 128.34375 L 134.128906 129.566406 L 134.394531 130.765625 L 134.664062 131.945312 L 134.933594 133.101562 L 135.203125 134.234375 L 135.472656 135.347656 L 135.742188 136.433594 L 136.007812 137.5 L 136.277344 138.542969 L 136.546875 139.5625 L 136.816406 140.558594 L 137.085938 141.53125 L 137.355469 142.484375 L 137.621094 143.410156 L 137.890625 144.316406 L 138.160156 145.195312 L 138.429688 146.054688 L 138.699219 146.890625 L 138.96875 147.707031 L 139.234375 148.5 L 139.503906 149.269531 L 139.773438 150.019531 L 140.042969 150.75 L 140.3125 151.457031 L 140.582031 152.144531 L 140.847656 152.808594 L 141.117188 153.457031 L 141.386719 154.085938 L 141.65625 154.695312 L 141.925781 155.285156 L 142.195312 155.855469 L 142.460938 156.410156 L 142.730469 156.949219 L 143 157.46875 L 143.269531 157.972656 L 143.539062 158.457031 L 143.808594 158.929688 L 144.074219 159.382812 L 144.34375 159.824219 L 144.613281 160.25 L 144.882812 160.664062 L 145.152344 161.058594 L 145.421875 161.445312 L 145.6875 161.816406 L 145.957031 162.175781 L 146.226562 162.519531 L 146.496094 162.855469 L 146.765625 163.175781 L 147.03125 163.488281 L 147.300781 163.789062 L 147.570312 164.078125 L 147.839844 164.359375 L 148.109375 164.628906 L 148.378906 164.886719 L 148.644531 165.140625 L 148.914062 165.378906 L 149.183594 165.613281 L 149.453125 165.835938 L 149.722656 166.054688 L 149.992188 166.261719 L 150.257812 166.464844 L 150.527344 166.65625 L 150.796875 166.84375 L 151.066406 167.023438 L 151.335938 167.195312 L 151.605469 167.363281 L 151.871094 167.523438 L 152.140625 167.675781 L 152.410156 167.824219 L 152.679688 167.96875 L 152.949219 168.105469 L 153.21875 168.238281 L 153.484375 168.363281 L 153.753906 168.488281 L 154.023438 168.605469 L 154.292969 168.71875 L 154.5625 168.828125 L 154.832031 168.933594 L 155.097656 169.035156 L 155.367188 169.132812 L 155.636719 169.226562 L 155.90625 169.316406 L 156.175781 169.402344 L 156.445312 169.484375 L 156.710938 169.566406 L 156.980469 169.644531 L 157.25 169.71875 L 157.519531 169.789062 L 158.058594 169.921875 L 158.324219 169.984375 L 158.59375 170.046875 L 158.863281 170.105469 L 159.671875 170.269531 L 159.9375 170.316406 L 160.207031 170.367188 L 160.476562 170.414062 L 161.015625 170.5 L 161.28125 170.539062 L 161.550781 170.582031 L 161.820312 170.617188 L 162.089844 170.65625 L 162.359375 170.691406 L 162.628906 170.722656 L 162.894531 170.757812 L 163.164062 170.789062 L 163.433594 170.816406 L 163.703125 170.847656 L 163.972656 170.875 L 164.242188 170.898438 L 164.507812 170.925781 L 165.585938 171.019531 L 165.855469 171.039062 L 166.121094 171.058594 L 166.660156 171.097656 L 166.929688 171.113281 L 167.199219 171.132812 L 167.46875 171.148438 L 167.734375 171.164062 L 168.273438 171.195312 L 168.542969 171.207031 L 168.8125 171.222656 L 169.082031 171.234375 L 169.347656 171.246094 L 170.425781 171.292969 L 170.695312 171.300781 L 170.960938 171.3125 L 171.230469 171.320312 L 171.5 171.332031 L 172.308594 171.355469 L 172.574219 171.363281 L 173.382812 171.386719 L 173.652344 171.390625 L 173.921875 171.398438 L 174.1875 171.402344 L 174.457031 171.410156 L 174.726562 171.414062 L 174.996094 171.421875 L 175.535156 171.429688 L 175.800781 171.4375 L 176.878906 171.453125 L 177.144531 171.457031 L 178.222656 171.472656 L 178.492188 171.472656 L 178.757812 171.476562 L 179.296875 171.484375 L 179.566406 171.484375 L 180.105469 171.492188 L 180.371094 171.492188 L 180.910156 171.5 L 181.179688 171.5 L 181.449219 171.503906 L 181.71875 171.503906 L 181.984375 171.507812 L 182.523438 171.507812 L 182.792969 171.511719 L 183.0625 171.511719 L 183.332031 171.515625 L 183.867188 171.515625 L 184.136719 171.519531 L 184.40625 171.519531 L 184.675781 171.523438 L 185.480469 171.523438 L 185.75 171.527344 L 186.558594 171.527344 L 186.824219 171.53125 L 187.632812 171.53125 L 187.902344 171.535156 L 189.246094 171.535156 L 189.515625 171.539062 L 191.128906 171.539062 L 191.394531 171.542969 L 193.816406 171.542969 L 194.085938 171.546875 L 194.890625 171.546875 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 61.53125 171.546875 L 61.800781 171.542969 L 64.222656 171.542969 L 64.492188 171.539062 L 66.105469 171.539062 L 66.371094 171.535156 L 67.71875 171.535156 L 67.984375 171.53125 L 68.792969 171.53125 L 69.0625 171.527344 L 69.867188 171.527344 L 70.136719 171.523438 L 70.945312 171.523438 L 71.210938 171.519531 L 71.480469 171.519531 L 71.75 171.515625 L 72.289062 171.515625 L 72.558594 171.511719 L 72.824219 171.511719 L 73.09375 171.507812 L 73.632812 171.507812 L 73.902344 171.503906 L 74.167969 171.503906 L 74.4375 171.5 L 74.707031 171.5 L 75.246094 171.492188 L 75.515625 171.492188 L 75.78125 171.488281 L 76.050781 171.484375 L 76.320312 171.484375 L 77.128906 171.472656 L 77.394531 171.472656 L 78.742188 171.453125 L 79.007812 171.449219 L 79.816406 171.4375 L 80.085938 171.429688 L 80.355469 171.425781 L 80.621094 171.421875 L 80.890625 171.414062 L 81.160156 171.410156 L 81.429688 171.402344 L 81.699219 171.398438 L 81.96875 171.390625 L 82.234375 171.386719 L 83.582031 171.347656 L 83.847656 171.339844 L 84.117188 171.332031 L 84.386719 171.320312 L 84.65625 171.3125 L 84.925781 171.300781 L 85.195312 171.292969 L 85.460938 171.28125 L 86.808594 171.222656 L 87.074219 171.207031 L 87.34375 171.195312 L 88.152344 171.148438 L 88.417969 171.132812 L 88.6875 171.113281 L 88.957031 171.097656 L 89.765625 171.039062 L 90.03125 171.019531 L 91.109375 170.925781 L 91.378906 170.898438 L 91.644531 170.875 L 91.914062 170.847656 L 92.183594 170.816406 L 92.453125 170.789062 L 92.722656 170.757812 L 92.992188 170.722656 L 93.257812 170.691406 L 93.527344 170.65625 L 93.796875 170.617188 L 94.066406 170.582031 L 94.335938 170.539062 L 94.605469 170.5 L 94.871094 170.457031 L 95.140625 170.414062 L 95.410156 170.367188 L 95.679688 170.316406 L 95.949219 170.269531 L 96.21875 170.214844 L 96.484375 170.160156 L 96.753906 170.105469 L 97.023438 170.046875 L 97.5625 169.921875 L 97.832031 169.855469 L 98.097656 169.789062 L 98.367188 169.71875 L 98.636719 169.644531 L 98.90625 169.566406 L 99.445312 169.402344 L 99.710938 169.316406 L 99.980469 169.226562 L 100.25 169.132812 L 100.519531 169.035156 L 100.789062 168.933594 L 101.058594 168.828125 L 101.324219 168.71875 L 101.59375 168.605469 L 101.863281 168.488281 L 102.402344 168.238281 L 102.667969 168.105469 L 102.9375 167.96875 L 103.207031 167.824219 L 103.476562 167.675781 L 103.746094 167.523438 L 104.015625 167.363281 L 104.28125 167.195312 L 104.550781 167.023438 L 104.820312 166.84375 L 105.089844 166.65625 L 105.359375 166.464844 L 105.628906 166.261719 L 105.894531 166.054688 L 106.164062 165.835938 L 106.433594 165.613281 L 106.703125 165.378906 L 106.972656 165.140625 L 107.242188 164.886719 L 107.507812 164.628906 L 107.777344 164.359375 L 108.046875 164.078125 L 108.316406 163.789062 L 108.585938 163.488281 L 108.855469 163.175781 L 109.121094 162.855469 L 109.390625 162.519531 L 109.660156 162.175781 L 109.929688 161.816406 L 110.199219 161.445312 L 110.46875 161.058594 L 110.734375 160.664062 L 111.003906 160.25 L 111.273438 159.824219 L 111.542969 159.382812 L 111.8125 158.929688 L 112.082031 158.457031 L 112.347656 157.972656 L 112.617188 157.46875 L 112.886719 156.949219 L 113.15625 156.410156 L 113.425781 155.855469 L 113.695312 155.285156 L 113.960938 154.695312 L 114.230469 154.085938 L 114.5 153.457031 L 114.769531 152.808594 L 115.039062 152.144531 L 115.308594 151.457031 L 115.574219 150.75 L 115.84375 150.019531 L 116.113281 149.269531 L 116.382812 148.5 L 116.652344 147.707031 L 116.921875 146.890625 L 117.1875 146.054688 L 117.457031 145.195312 L 117.726562 144.316406 L 117.996094 143.410156 L 118.265625 142.484375 L 118.53125 141.53125 L 118.800781 140.558594 L 119.070312 139.5625 L 119.339844 138.542969 L 119.609375 137.5 L 119.878906 136.433594 L 120.144531 135.347656 L 120.414062 134.234375 L 120.683594 133.101562 L 120.953125 131.945312 L 121.222656 130.765625 L 121.492188 129.566406 L 121.757812 128.34375 L 122.027344 127.101562 L 122.296875 125.839844 L 122.566406 124.558594 L 122.835938 123.253906 L 123.105469 121.933594 L 123.371094 120.597656 L 123.640625 119.242188 L 123.910156 117.867188 L 124.179688 116.480469 L 124.449219 115.078125 L 124.71875 113.664062 L 124.984375 112.234375 L 125.253906 110.792969 L 125.523438 109.339844 L 125.792969 107.878906 L 126.0625 106.40625 L 126.332031 104.929688 L 126.597656 103.445312 L 126.867188 101.957031 L 127.40625 98.964844 L 127.945312 95.964844 L 128.210938 94.464844 L 128.75 91.472656 L 129.019531 89.984375 L 129.289062 88.5 L 129.558594 87.019531 L 129.824219 85.550781 L 130.09375 84.089844 L 130.363281 82.636719 L 130.632812 81.195312 L 130.902344 79.765625 L 131.171875 78.351562 L 131.4375 76.949219 L 131.707031 75.558594 L 131.976562 74.1875 L 132.246094 72.832031 L 132.515625 71.496094 L 132.78125 70.175781 L 133.050781 68.871094 L 133.320312 67.589844 L 133.589844 66.328125 L 133.859375 65.085938 L 134.128906 63.863281 L 134.394531 62.664062 L 134.664062 61.484375 L 134.933594 60.328125 L 135.203125 59.195312 L 135.472656 58.082031 L 135.742188 56.996094 L 136.007812 55.929688 L 136.277344 54.886719 L 136.546875 53.867188 L 136.816406 52.871094 L 137.085938 51.894531 L 137.355469 50.945312 L 137.621094 50.019531 L 137.890625 49.113281 L 138.160156 48.230469 L 138.429688 47.375 L 138.699219 46.535156 L 138.96875 45.722656 L 139.234375 44.929688 L 139.503906 44.160156 L 139.773438 43.410156 L 140.042969 42.679688 L 140.3125 41.972656 L 140.582031 41.285156 L 140.847656 40.617188 L 141.117188 39.972656 L 141.386719 39.34375 L 141.65625 38.734375 L 141.925781 38.144531 L 142.195312 37.574219 L 142.460938 37.019531 L 142.730469 36.480469 L 143 35.960938 L 143.269531 35.457031 L 143.539062 34.972656 L 143.808594 34.5 L 144.074219 34.042969 L 144.34375 33.605469 L 144.613281 33.179688 L 144.882812 32.765625 L 145.152344 32.367188 L 145.421875 31.984375 L 145.6875 31.613281 L 145.957031 31.253906 L 146.226562 30.90625 L 146.496094 30.574219 L 146.765625 30.25 L 147.03125 29.941406 L 147.300781 29.640625 L 147.570312 29.351562 L 147.839844 29.070312 L 148.109375 28.800781 L 148.378906 28.539062 L 148.644531 28.289062 L 148.914062 28.046875 L 149.183594 27.816406 L 149.453125 27.589844 L 149.722656 27.375 L 149.992188 27.167969 L 150.257812 26.964844 L 150.527344 26.773438 L 150.796875 26.585938 L 151.066406 26.40625 L 151.335938 26.234375 L 151.605469 26.066406 L 151.871094 25.90625 L 152.140625 25.753906 L 152.410156 25.605469 L 152.679688 25.460938 L 152.949219 25.324219 L 153.21875 25.191406 L 153.484375 25.0625 L 153.753906 24.941406 L 154.023438 24.824219 L 154.292969 24.710938 L 154.5625 24.601562 L 154.832031 24.496094 L 155.097656 24.394531 L 155.367188 24.296875 L 155.636719 24.203125 L 155.90625 24.113281 L 156.445312 23.941406 L 156.710938 23.863281 L 156.980469 23.785156 L 157.25 23.710938 L 157.789062 23.570312 L 158.058594 23.507812 L 158.324219 23.441406 L 159.132812 23.265625 L 159.402344 23.210938 L 159.671875 23.160156 L 159.9375 23.109375 L 160.476562 23.015625 L 161.015625 22.929688 L 161.28125 22.886719 L 161.550781 22.847656 L 161.820312 22.8125 L 162.089844 22.773438 L 162.359375 22.738281 L 162.628906 22.707031 L 162.894531 22.671875 L 163.164062 22.640625 L 163.433594 22.613281 L 163.703125 22.582031 L 164.242188 22.527344 L 164.507812 22.503906 L 165.585938 22.410156 L 165.855469 22.390625 L 166.121094 22.371094 L 166.929688 22.3125 L 167.46875 22.28125 L 167.734375 22.265625 L 168.273438 22.234375 L 168.542969 22.222656 L 168.8125 22.207031 L 169.082031 22.195312 L 169.347656 22.183594 L 169.617188 22.167969 L 169.886719 22.160156 L 170.695312 22.125 L 170.960938 22.117188 L 171.230469 22.105469 L 172.308594 22.074219 L 172.574219 22.066406 L 173.382812 22.042969 L 173.652344 22.039062 L 173.921875 22.03125 L 174.1875 22.023438 L 174.457031 22.019531 L 174.726562 22.011719 L 175.265625 22.003906 L 175.535156 21.996094 L 175.800781 21.992188 L 176.878906 21.976562 L 177.144531 21.972656 L 178.492188 21.953125 L 178.757812 21.953125 L 179.566406 21.941406 L 179.835938 21.941406 L 180.105469 21.9375 L 180.371094 21.933594 L 180.640625 21.933594 L 180.910156 21.929688 L 181.179688 21.929688 L 181.449219 21.925781 L 181.71875 21.925781 L 181.984375 21.921875 L 182.253906 21.921875 L 182.523438 21.917969 L 182.792969 21.917969 L 183.0625 21.914062 L 183.597656 21.914062 L 183.867188 21.910156 L 184.40625 21.910156 L 184.675781 21.90625 L 185.210938 21.90625 L 185.480469 21.902344 L 186.289062 21.902344 L 186.558594 21.898438 L 187.363281 21.898438 L 187.632812 21.894531 L 188.976562 21.894531 L 189.246094 21.890625 L 190.859375 21.890625 L 191.128906 21.886719 L 193.277344 21.886719 L 193.546875 21.882812 L 194.890625 21.882812 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.988281"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.988281"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.988281"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.988281"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.570312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.570312"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.570312"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.570312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.3125"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.3125"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.3125"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.3125"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.550781 L 54.019531 171.550781 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.132812 L 54.019531 134.132812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.875 L 54.019531 21.875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/sigmoidDifference.svg b/documentation/ui/figure/sigmoidDifference.svg
new file mode 100644
index 0000000..ca75ba2
--- /dev/null
+++ b/documentation/ui/figure/sigmoidDifference.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 153 L 202 153 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 76 L 202 76 L 202 78 L 54.019531 78 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 38 L 202 38 L 202 40 L 54.019531 40 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 172 L 202.601562 172 L 202.601562 174 L 54.019531 174 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 95 L 202.601562 95 L 202.601562 97 L 54.019531 97 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 57 L 202.601562 57 L 202.601562 59 L 54.019531 59 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 19 L 202.601562 19 L 202.601562 21 L 54.019531 21 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface226">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 153.476562 L 201.601562 153.476562 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.292969 L 201.601562 115.292969 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 77.113281 L 201.601562 77.113281 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 38.929688 L 201.601562 38.929688 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 172.566406 L 201.601562 172.566406 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.386719 L 201.601562 134.386719 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.203125 L 201.601562 96.203125 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 58.019531 L 201.601562 58.019531 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 19.839844 L 201.601562 19.839844 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 61.265625 171.460938 L 61.53125 171.417969 L 61.800781 171.371094 L 62.609375 171.21875 L 62.878906 171.164062 L 63.144531 171.105469 L 63.414062 171.046875 L 63.953125 170.921875 L 64.222656 170.855469 L 64.492188 170.785156 L 64.757812 170.714844 L 65.027344 170.636719 L 65.296875 170.5625 L 65.566406 170.480469 L 66.105469 170.308594 L 66.371094 170.21875 L 66.910156 170.023438 L 67.179688 169.921875 L 67.449219 169.816406 L 67.71875 169.707031 L 67.984375 169.589844 L 68.253906 169.472656 L 68.523438 169.347656 L 68.792969 169.21875 L 69.0625 169.085938 L 69.332031 168.945312 L 69.597656 168.800781 L 69.867188 168.652344 L 70.136719 168.496094 L 70.40625 168.332031 L 70.675781 168.164062 L 70.945312 167.988281 L 71.210938 167.808594 L 71.480469 167.621094 L 71.75 167.425781 L 72.019531 167.222656 L 72.289062 167.011719 L 72.558594 166.792969 L 72.824219 166.566406 L 73.09375 166.332031 L 73.363281 166.085938 L 73.632812 165.832031 L 73.902344 165.570312 L 74.167969 165.296875 L 74.4375 165.015625 L 74.707031 164.722656 L 74.976562 164.417969 L 75.246094 164.101562 L 75.515625 163.777344 L 75.78125 163.4375 L 76.050781 163.089844 L 76.320312 162.726562 L 76.589844 162.351562 L 76.859375 161.960938 L 77.128906 161.558594 L 77.394531 161.144531 L 77.664062 160.710938 L 77.933594 160.265625 L 78.203125 159.804688 L 78.472656 159.328125 L 78.742188 158.835938 L 79.007812 158.328125 L 79.277344 157.800781 L 79.546875 157.257812 L 79.816406 156.695312 L 80.085938 156.117188 L 80.355469 155.519531 L 80.621094 154.902344 L 80.890625 154.265625 L 81.160156 153.609375 L 81.429688 152.933594 L 81.699219 152.238281 L 81.96875 151.523438 L 82.234375 150.785156 L 82.503906 150.027344 L 82.773438 149.246094 L 83.042969 148.441406 L 83.3125 147.617188 L 83.582031 146.769531 L 83.847656 145.898438 L 84.117188 145.003906 L 84.386719 144.085938 L 84.65625 143.144531 L 84.925781 142.183594 L 85.195312 141.195312 L 85.460938 140.183594 L 85.730469 139.148438 L 86 138.089844 L 86.269531 137.007812 L 86.539062 135.90625 L 86.808594 134.777344 L 87.074219 133.625 L 87.34375 132.449219 L 87.613281 131.253906 L 87.882812 130.035156 L 88.152344 128.792969 L 88.417969 127.53125 L 88.6875 126.25 L 88.957031 124.945312 L 89.226562 123.621094 L 89.496094 122.28125 L 89.765625 120.917969 L 90.03125 119.539062 L 90.300781 118.144531 L 90.570312 116.734375 L 90.839844 115.304688 L 91.109375 113.863281 L 91.378906 112.410156 L 91.644531 110.941406 L 91.914062 109.464844 L 92.183594 107.972656 L 92.453125 106.476562 L 92.722656 104.96875 L 92.992188 103.457031 L 93.257812 101.9375 L 93.527344 100.414062 L 94.066406 97.359375 L 94.605469 94.296875 L 94.871094 92.769531 L 95.410156 89.722656 L 95.679688 88.207031 L 95.949219 86.695312 L 96.21875 85.195312 L 96.484375 83.703125 L 96.753906 82.21875 L 97.023438 80.746094 L 97.292969 79.285156 L 97.5625 77.835938 L 97.832031 76.402344 L 98.097656 74.980469 L 98.367188 73.578125 L 98.636719 72.191406 L 98.90625 70.820312 L 99.175781 69.46875 L 99.445312 68.136719 L 99.710938 66.824219 L 99.980469 65.53125 L 100.25 64.261719 L 100.519531 63.007812 L 100.789062 61.78125 L 101.058594 60.574219 L 101.324219 59.386719 L 101.59375 58.226562 L 101.863281 57.085938 L 102.132812 55.972656 L 102.402344 54.878906 L 102.667969 53.808594 L 102.9375 52.765625 L 103.207031 51.742188 L 103.476562 50.742188 L 103.746094 49.769531 L 104.015625 48.820312 L 104.28125 47.890625 L 104.550781 46.988281 L 104.820312 46.105469 L 105.089844 45.246094 L 105.359375 44.414062 L 105.628906 43.601562 L 105.894531 42.808594 L 106.164062 42.039062 L 106.433594 41.292969 L 106.703125 40.566406 L 106.972656 39.863281 L 107.242188 39.179688 L 107.507812 38.515625 L 107.777344 37.871094 L 108.046875 37.25 L 108.316406 36.644531 L 108.585938 36.058594 L 108.855469 35.488281 L 109.121094 34.941406 L 109.390625 34.40625 L 109.660156 33.894531 L 109.929688 33.394531 L 110.199219 32.914062 L 110.46875 32.445312 L 110.734375 31.996094 L 111.003906 31.5625 L 111.273438 31.140625 L 111.542969 30.734375 L 111.8125 30.34375 L 112.082031 29.964844 L 112.347656 29.601562 L 112.617188 29.25 L 112.886719 28.910156 L 113.15625 28.582031 L 113.425781 28.265625 L 113.695312 27.960938 L 113.960938 27.667969 L 114.230469 27.386719 L 114.5 27.113281 L 114.769531 26.851562 L 115.039062 26.597656 L 115.308594 26.355469 L 115.574219 26.125 L 115.84375 25.898438 L 116.113281 25.683594 L 116.382812 25.476562 L 116.652344 25.277344 L 116.921875 25.085938 L 117.1875 24.902344 L 117.457031 24.726562 L 117.726562 24.558594 L 117.996094 24.394531 L 118.265625 24.238281 L 118.53125 24.089844 L 118.800781 23.949219 L 119.070312 23.8125 L 119.339844 23.679688 L 119.878906 23.4375 L 120.144531 23.324219 L 120.414062 23.214844 L 120.683594 23.113281 L 120.953125 23.015625 L 121.222656 22.921875 L 121.492188 22.832031 L 121.757812 22.75 L 122.027344 22.667969 L 122.296875 22.59375 L 122.566406 22.523438 L 122.835938 22.457031 L 123.105469 22.394531 L 123.371094 22.335938 L 123.640625 22.28125 L 123.910156 22.230469 L 124.179688 22.183594 L 124.71875 22.097656 L 124.984375 22.0625 L 125.523438 22 L 125.792969 21.972656 L 126.0625 21.949219 L 126.332031 21.929688 L 126.597656 21.914062 L 126.867188 21.902344 L 127.40625 21.886719 L 127.675781 21.882812 L 127.945312 21.882812 L 128.210938 21.886719 L 128.75 21.902344 L 129.019531 21.914062 L 129.289062 21.929688 L 129.558594 21.949219 L 129.824219 21.972656 L 130.09375 22 L 130.632812 22.0625 L 130.902344 22.097656 L 131.171875 22.140625 L 131.4375 22.183594 L 131.707031 22.230469 L 131.976562 22.28125 L 132.246094 22.335938 L 132.515625 22.394531 L 132.78125 22.457031 L 133.050781 22.523438 L 133.320312 22.59375 L 133.589844 22.667969 L 134.128906 22.832031 L 134.394531 22.921875 L 134.664062 23.015625 L 134.933594 23.113281 L 135.203125 23.214844 L 135.472656 23.324219 L 135.742188 23.4375 L 136.007812 23.558594 L 136.277344 23.679688 L 136.546875 23.8125 L 136.816406 23.949219 L 137.085938 24.089844 L 137.355469 24.238281 L 137.621094 24.394531 L 137.890625 24.558594 L 138.160156 24.726562 L 138.429688 24.902344 L 138.699219 25.085938 L 138.96875 25.277344 L 139.234375 25.476562 L 139.503906 25.683594 L 139.773438 25.898438 L 140.042969 26.125 L 140.3125 26.355469 L 140.582031 26.597656 L 140.847656 26.851562 L 141.117188 27.113281 L 141.386719 27.386719 L 141.65625 27.667969 L 141.925781 27.960938 L 142.195312 28.265625 L 142.460938 28.582031 L 142.730469 28.910156 L 143 29.25 L 143.269531 29.601562 L 143.539062 29.964844 L 143.808594 30.34375 L 144.074219 30.734375 L 144.34375 31.140625 L 144.613281 31.5625 L 144.882812 31.996094 L 145.152344 32.445312 L 145.421875 32.914062 L 145.6875 33.394531 L 145.957031 33.894531 L 146.226562 34.40625 L 146.496094 34.941406 L 146.765625 35.488281 L 147.03125 36.058594 L 147.300781 36.644531 L 147.570312 37.25 L 147.839844 37.871094 L 148.109375 38.515625 L 148.378906 39.179688 L 148.644531 39.863281 L 148.914062 40.566406 L 149.183594 41.292969 L 149.453125 42.039062 L 149.722656 42.808594 L 149.992188 43.601562 L 150.257812 44.414062 L 150.527344 45.246094 L 150.796875 46.105469 L 151.066406 46.988281 L 151.335938 47.890625 L 151.605469 48.820312 L 151.871094 49.769531 L 152.140625 50.742188 L 152.410156 51.742188 L 152.679688 52.765625 L 152.949219 53.808594 L 153.21875 54.878906 L 153.484375 55.972656 L 153.753906 57.085938 L 154.023438 58.226562 L 154.292969 59.386719 L 154.5625 60.574219 L 154.832031 61.78125 L 155.097656 63.007812 L 155.367188 64.261719 L 155.636719 65.53125 L 155.90625 66.824219 L 156.175781 68.136719 L 156.445312 69.46875 L 156.710938 70.820312 L 156.980469 72.191406 L 157.25 73.578125 L 157.519531 74.980469 L 157.789062 76.402344 L 158.058594 77.835938 L 158.324219 79.285156 L 158.59375 80.746094 L 158.863281 82.21875 L 159.132812 83.703125 L 159.402344 85.195312 L 159.671875 86.695312 L 159.9375 88.207031 L 160.207031 89.722656 L 160.746094 92.769531 L 161.015625 94.296875 L 161.28125 95.828125 L 161.550781 97.359375 L 162.089844 100.414062 L 162.359375 101.9375 L 162.628906 103.457031 L 162.894531 104.96875 L 163.164062 106.476562 L 163.433594 107.972656 L 163.703125 109.464844 L 163.972656 110.941406 L 164.242188 112.410156 L 164.507812 113.863281 L 164.777344 115.304688 L 165.046875 116.734375 L 165.316406 118.144531 L 165.585938 119.539062 L 165.855469 120.917969 L 166.121094 122.28125 L 166.390625 123.621094 L 166.660156 124.945312 L 166.929688 126.25 L 167.199219 127.53125 L 167.46875 128.792969 L 167.734375 130.035156 L 168.003906 131.253906 L 168.273438 132.449219 L 168.542969 133.625 L 168.8125 134.777344 L 169.082031 135.90625 L 169.347656 137.007812 L 169.617188 138.089844 L 169.886719 139.148438 L 170.15625 140.183594 L 170.425781 141.195312 L 170.695312 142.183594 L 170.960938 143.144531 L 171.230469 144.085938 L 171.5 145.003906 L 171.769531 145.898438 L 172.039062 146.769531 L 172.308594 147.617188 L 172.574219 148.441406 L 172.84375 149.246094 L 173.113281 150.027344 L 173.382812 150.785156 L 173.652344 151.523438 L 173.921875 152.238281 L 174.1875 152.933594 L 174.457031 153.609375 L 174.726562 154.265625 L 174.996094 154.902344 L 175.265625 155.519531 L 175.535156 156.117188 L 175.800781 156.695312 L 176.070312 157.257812 L 176.339844 157.800781 L 176.609375 158.328125 L 176.878906 158.835938 L 177.144531 159.328125 L 177.414062 159.804688 L 177.683594 160.265625 L 177.953125 160.710938 L 178.222656 161.144531 L 178.492188 161.558594 L 178.757812 161.960938 L 179.027344 162.351562 L 179.296875 162.726562 L 179.566406 163.089844 L 179.835938 163.4375 L 180.105469 163.777344 L 180.371094 164.101562 L 180.640625 164.417969 L 180.910156 164.722656 L 181.179688 165.015625 L 181.449219 165.296875 L 181.71875 165.570312 L 181.984375 165.832031 L 182.253906 166.085938 L 182.523438 166.332031 L 182.792969 166.566406 L 183.0625 166.792969 L 183.332031 167.011719 L 183.597656 167.222656 L 183.867188 167.425781 L 184.136719 167.621094 L 184.40625 167.808594 L 184.675781 167.988281 L 184.945312 168.164062 L 185.210938 168.332031 L 185.480469 168.496094 L 185.75 168.652344 L 186.019531 168.800781 L 186.289062 168.945312 L 186.558594 169.085938 L 186.824219 169.21875 L 187.09375 169.347656 L 187.363281 169.472656 L 187.902344 169.707031 L 188.171875 169.816406 L 188.4375 169.921875 L 188.707031 170.023438 L 189.246094 170.21875 L 189.515625 170.308594 L 189.785156 170.394531 L 190.050781 170.480469 L 190.320312 170.5625 L 190.589844 170.636719 L 190.859375 170.714844 L 191.128906 170.785156 L 191.394531 170.855469 L 191.664062 170.921875 L 192.203125 171.046875 L 192.742188 171.164062 L 193.007812 171.21875 L 193.816406 171.371094 L 194.085938 171.417969 L 194.355469 171.460938 L 194.621094 171.503906 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="176.003906"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="176.003906"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="176.003906"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="176.003906"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.824219"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.824219"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.824219"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.824219"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="99.640625"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="99.640625"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="99.640625"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="99.640625"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="61.457031"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="61.457031"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="61.457031"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="61.457031"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="23.277344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="23.277344"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="23.277344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="23.277344"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 172.566406 L 54.019531 172.566406 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.386719 L 54.019531 134.386719 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.203125 L 54.019531 96.203125 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 58.019531 L 54.019531 58.019531 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 19.839844 L 54.019531 19.839844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/sigmoidProduct.svg b/documentation/ui/figure/sigmoidProduct.svg
new file mode 100644
index 0000000..61543c9
--- /dev/null
+++ b/documentation/ui/figure/sigmoidProduct.svg
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 3.171875 -2.375 L 3.171875 -5.421875 L 1.015625 -2.375 Z M 3.1875 0 L 3.1875 -1.640625 L 0.25 -1.640625 L 0.25 -2.46875 L 3.3125 -6.734375 L 4.03125 -6.734375 L 4.03125 -2.375 L 5.015625 -2.375 L 5.015625 -1.640625 L 4.03125 -1.640625 L 4.03125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 2.8125 -6.734375 C 3.5625 -6.734375 4.082031 -6.535156 4.375 -6.140625 C 4.664062 -5.753906 4.8125 -5.359375 4.8125 -4.953125 L 3.984375 -4.953125 C 3.929688 -5.210938 3.851562 -5.421875 3.75 -5.578125 C 3.539062 -5.859375 3.226562 -6 2.8125 -6 C 2.34375 -6 1.96875 -5.78125 1.6875 -5.34375 C 1.414062 -4.90625 1.265625 -4.28125 1.234375 -3.46875 C 1.421875 -3.75 1.664062 -3.960938 1.96875 -4.109375 C 2.226562 -4.234375 2.523438 -4.296875 2.859375 -4.296875 C 3.421875 -4.296875 3.910156 -4.113281 4.328125 -3.75 C 4.742188 -3.394531 4.953125 -2.863281 4.953125 -2.15625 C 4.953125 -1.539062 4.753906 -1 4.359375 -0.53125 C 3.960938 -0.0625 3.398438 0.171875 2.671875 0.171875 C 2.046875 0.171875 1.503906 -0.0625 1.046875 -0.53125 C 0.585938 -1.007812 0.359375 -1.816406 0.359375 -2.953125 C 0.359375 -3.785156 0.460938 -4.488281 0.671875 -5.0625 C 1.054688 -6.175781 1.769531 -6.734375 2.8125 -6.734375 Z M 2.75 -0.578125 C 3.1875 -0.578125 3.515625 -0.722656 3.734375 -1.015625 C 3.960938 -1.316406 4.078125 -1.671875 4.078125 -2.078125 C 4.078125 -2.421875 3.976562 -2.75 3.78125 -3.0625 C 3.582031 -3.375 3.222656 -3.53125 2.703125 -3.53125 C 2.335938 -3.53125 2.019531 -3.410156 1.75 -3.171875 C 1.476562 -2.929688 1.34375 -2.566406 1.34375 -2.078125 C 1.34375 -1.648438 1.460938 -1.289062 1.703125 -1 C 1.953125 -0.71875 2.300781 -0.578125 2.75 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 2.609375 -3.890625 C 2.984375 -3.890625 3.273438 -3.992188 3.484375 -4.203125 C 3.691406 -4.410156 3.796875 -4.660156 3.796875 -4.953125 C 3.796875 -5.203125 3.691406 -5.429688 3.484375 -5.640625 C 3.285156 -5.847656 2.984375 -5.953125 2.578125 -5.953125 C 2.171875 -5.953125 1.875 -5.847656 1.6875 -5.640625 C 1.507812 -5.429688 1.421875 -5.1875 1.421875 -4.90625 C 1.421875 -4.59375 1.535156 -4.34375 1.765625 -4.15625 C 2.003906 -3.976562 2.285156 -3.890625 2.609375 -3.890625 Z M 2.65625 -0.578125 C 3.050781 -0.578125 3.375 -0.679688 3.625 -0.890625 C 3.882812 -1.097656 4.015625 -1.414062 4.015625 -1.84375 C 4.015625 -2.269531 3.878906 -2.59375 3.609375 -2.8125 C 3.347656 -3.039062 3.007812 -3.15625 2.59375 -3.15625 C 2.195312 -3.15625 1.867188 -3.039062 1.609375 -2.8125 C 1.359375 -2.582031 1.234375 -2.265625 1.234375 -1.859375 C 1.234375 -1.515625 1.347656 -1.210938 1.578125 -0.953125 C 1.816406 -0.703125 2.175781 -0.578125 2.65625 -0.578125 Z M 1.46875 -3.578125 C 1.226562 -3.671875 1.039062 -3.785156 0.90625 -3.921875 C 0.664062 -4.171875 0.546875 -4.5 0.546875 -4.90625 C 0.546875 -5.40625 0.722656 -5.832031 1.078125 -6.1875 C 1.441406 -6.550781 1.957031 -6.734375 2.625 -6.734375 C 3.269531 -6.734375 3.773438 -6.5625 4.140625 -6.21875 C 4.503906 -5.875 4.6875 -5.476562 4.6875 -5.03125 C 4.6875 -4.613281 4.582031 -4.273438 4.375 -4.015625 C 4.25 -3.867188 4.0625 -3.722656 3.8125 -3.578125 C 4.09375 -3.453125 4.3125 -3.304688 4.46875 -3.140625 C 4.769531 -2.828125 4.921875 -2.421875 4.921875 -1.921875 C 4.921875 -1.335938 4.722656 -0.835938 4.328125 -0.421875 C 3.929688 -0.015625 3.367188 0.1875 2.640625 0.1875 C 1.984375 0.1875 1.429688 0.0078125 0.984375 -0.34375 C 0.535156 -0.695312 0.3125 -1.210938 0.3125 -1.890625 C 0.3125 -2.285156 0.40625 -2.625 0.59375 -2.90625 C 0.789062 -3.195312 1.082031 -3.421875 1.46875 -3.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-9">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 48.683594 14.398438 L 202 14.398438 L 202 180 L 48.683594 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 48.683594 166 L 202 166 L 202 168 L 48.683594 168 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 48.683594 128 L 202 128 L 202 129 L 48.683594 129 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 48.683594 89 L 202 89 L 202 91 L 48.683594 91 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 48.683594 51 L 202 51 L 202 52 L 48.683594 52 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 72 14.398438 L 74 14.398438 L 74 180 L 72 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 107 14.398438 L 109 14.398438 L 109 180 L 107 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 142 14.398438 L 143 14.398438 L 143 180 L 142 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 178 14.398438 L 178 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 48.683594 147 L 202.601562 147 L 202.601562 149 L 48.683594 149 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 48.683594 108 L 202.601562 108 L 202.601562 110 L 48.683594 110 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 48.683594 70 L 202.601562 70 L 202.601562 72 L 48.683594 72 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 48.683594 31 L 202.601562 31 L 202.601562 33 L 48.683594 33 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 55 14.398438 L 57 14.398438 L 57 180 L 55 180 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 89 14.398438 L 91 14.398438 L 91 180 L 89 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 124 14.398438 L 126 14.398438 L 126 180 L 124 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 159 14.398438 L 161 14.398438 L 161 180 L 159 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface231">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 48.683594 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 48.683594 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 166.894531 L 201.601562 166.894531 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 128.433594 L 201.601562 128.433594 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 89.96875 L 201.601562 89.96875 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 51.503906 L 201.601562 51.503906 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 73.011719 179.027344 L 73.011719 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 107.765625 179.027344 L 107.765625 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 142.519531 179.027344 L 142.519531 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 177.273438 179.027344 L 177.273438 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 147.664062 L 201.601562 147.664062 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 109.199219 L 201.601562 109.199219 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 70.738281 L 201.601562 70.738281 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.683594 32.273438 L 201.601562 32.273438 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.632812 179.027344 L 55.632812 14.398438 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 90.386719 179.027344 L 90.386719 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 125.140625 179.027344 L 125.140625 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 159.894531 179.027344 L 159.894531 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.648438 179.027344 L 194.648438 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 55.632812 171.546875 L 55.910156 171.273438 L 56.191406 170.996094 L 56.46875 170.714844 L 56.746094 170.429688 L 57.027344 170.136719 L 57.304688 169.84375 L 57.582031 169.539062 L 57.863281 169.234375 L 58.140625 168.925781 L 58.417969 168.609375 L 58.699219 168.285156 L 58.976562 167.960938 L 59.253906 167.628906 L 59.535156 167.289062 L 59.8125 166.945312 L 60.089844 166.597656 L 60.371094 166.246094 L 60.925781 165.519531 L 61.207031 165.148438 L 61.484375 164.769531 L 61.761719 164.386719 L 62.039062 164 L 62.320312 163.605469 L 62.597656 163.203125 L 62.875 162.796875 L 63.15625 162.382812 L 63.433594 161.960938 L 63.710938 161.535156 L 63.992188 161.105469 L 64.269531 160.664062 L 64.546875 160.21875 L 64.828125 159.769531 L 65.105469 159.308594 L 65.382812 158.84375 L 65.664062 158.371094 L 65.941406 157.894531 L 66.21875 157.40625 L 66.5 156.914062 L 66.777344 156.417969 L 67.054688 155.910156 L 67.335938 155.398438 L 67.613281 154.878906 L 67.890625 154.351562 L 68.167969 153.816406 L 68.449219 153.273438 L 68.726562 152.726562 L 69.285156 151.609375 L 69.5625 151.039062 L 69.839844 150.460938 L 70.121094 149.875 L 70.398438 149.285156 L 70.675781 148.6875 L 70.957031 148.078125 L 71.234375 147.464844 L 71.511719 146.84375 L 71.792969 146.214844 L 72.070312 145.582031 L 72.347656 144.9375 L 72.628906 144.285156 L 72.90625 143.628906 L 73.183594 142.964844 L 73.464844 142.292969 L 73.742188 141.613281 L 74.019531 140.925781 L 74.300781 140.230469 L 74.578125 139.527344 L 74.855469 138.820312 L 75.132812 138.105469 L 75.414062 137.382812 L 75.691406 136.652344 L 75.96875 135.914062 L 76.25 135.171875 L 76.527344 134.417969 L 76.804688 133.660156 L 77.085938 132.898438 L 77.363281 132.125 L 77.640625 131.347656 L 77.921875 130.5625 L 78.199219 129.773438 L 78.476562 128.976562 L 78.757812 128.171875 L 79.035156 127.359375 L 79.3125 126.542969 L 79.59375 125.722656 L 79.871094 124.894531 L 80.148438 124.058594 L 80.429688 123.21875 L 80.707031 122.375 L 80.984375 121.523438 L 81.261719 120.667969 L 81.542969 119.804688 L 81.820312 118.9375 L 82.097656 118.066406 L 82.378906 117.1875 L 82.65625 116.308594 L 82.933594 115.421875 L 83.214844 114.53125 L 83.492188 113.636719 L 83.769531 112.738281 L 84.050781 111.832031 L 84.328125 110.925781 L 84.605469 110.015625 L 84.886719 109.101562 L 85.164062 108.1875 L 85.441406 107.265625 L 85.722656 106.34375 L 86 105.414062 L 86.277344 104.488281 L 86.558594 103.554688 L 87.113281 101.6875 L 87.390625 100.75 L 87.671875 99.8125 L 88.226562 97.929688 L 88.507812 96.988281 L 88.785156 96.042969 L 89.0625 95.101562 L 89.34375 94.15625 L 89.898438 92.265625 L 90.179688 91.320312 L 90.457031 90.375 L 90.734375 89.433594 L 91.015625 88.488281 L 91.570312 86.605469 L 91.851562 85.667969 L 92.40625 83.792969 L 92.6875 82.859375 L 92.964844 81.925781 L 93.242188 80.996094 L 93.519531 80.070312 L 93.800781 79.144531 L 94.355469 77.308594 L 94.636719 76.390625 L 94.914062 75.480469 L 95.191406 74.574219 L 95.472656 73.671875 L 95.75 72.769531 L 96.027344 71.875 L 96.308594 70.984375 L 96.863281 69.21875 L 97.144531 68.34375 L 97.421875 67.472656 L 97.699219 66.605469 L 97.980469 65.746094 L 98.535156 64.042969 L 98.816406 63.203125 L 99.09375 62.367188 L 99.371094 61.535156 L 99.652344 60.710938 L 99.929688 59.894531 L 100.207031 59.085938 L 100.484375 58.28125 L 100.765625 57.484375 L 101.042969 56.695312 L 101.320312 55.914062 L 101.601562 55.140625 L 101.878906 54.371094 L 102.15625 53.613281 L 102.4375 52.859375 L 102.714844 52.117188 L 102.992188 51.378906 L 103.273438 50.652344 L 103.550781 49.929688 L 103.828125 49.21875 L 104.109375 48.515625 L 104.386719 47.820312 L 104.664062 47.132812 L 104.945312 46.453125 L 105.222656 45.78125 L 105.5 45.121094 L 105.78125 44.46875 L 106.058594 43.824219 L 106.335938 43.191406 L 106.613281 42.5625 L 106.894531 41.945312 L 107.171875 41.335938 L 107.449219 40.738281 L 107.730469 40.148438 L 108.007812 39.566406 L 108.285156 38.996094 L 108.84375 37.878906 L 109.121094 37.335938 L 109.402344 36.800781 L 109.679688 36.273438 L 109.957031 35.757812 L 110.238281 35.25 L 110.515625 34.753906 L 110.792969 34.265625 L 111.074219 33.785156 L 111.351562 33.316406 L 111.628906 32.855469 L 111.910156 32.40625 L 112.1875 31.964844 L 112.464844 31.535156 L 112.742188 31.113281 L 113.023438 30.699219 L 113.300781 30.296875 L 113.578125 29.902344 L 113.859375 29.519531 L 114.136719 29.144531 L 114.414062 28.78125 L 114.695312 28.425781 L 114.972656 28.078125 L 115.25 27.742188 L 115.53125 27.414062 L 115.808594 27.097656 L 116.085938 26.789062 L 116.367188 26.492188 L 116.644531 26.203125 L 116.921875 25.921875 L 117.203125 25.652344 L 117.480469 25.390625 L 117.757812 25.140625 L 118.039062 24.898438 L 118.316406 24.664062 L 118.59375 24.441406 L 118.875 24.230469 L 119.152344 24.023438 L 119.429688 23.828125 L 119.707031 23.644531 L 119.988281 23.46875 L 120.265625 23.300781 L 120.542969 23.144531 L 120.824219 22.996094 L 121.101562 22.855469 L 121.378906 22.726562 L 121.660156 22.605469 L 121.9375 22.492188 L 122.214844 22.390625 L 122.496094 22.300781 L 122.773438 22.214844 L 123.050781 22.140625 L 123.332031 22.078125 L 123.609375 22.023438 L 123.886719 21.976562 L 124.167969 21.9375 L 124.445312 21.910156 L 124.722656 21.890625 L 125.003906 21.882812 L 125.28125 21.882812 L 125.558594 21.890625 L 125.835938 21.910156 L 126.117188 21.9375 L 126.394531 21.976562 L 126.671875 22.023438 L 126.953125 22.078125 L 127.230469 22.140625 L 127.507812 22.214844 L 127.789062 22.300781 L 128.066406 22.390625 L 128.34375 22.492188 L 128.625 22.605469 L 128.902344 22.726562 L 129.179688 22.855469 L 129.460938 22.996094 L 129.738281 23.144531 L 130.015625 23.300781 L 130.296875 23.46875 L 130.574219 23.644531 L 130.851562 23.828125 L 131.132812 24.023438 L 131.410156 24.230469 L 131.6875 24.441406 L 131.964844 24.664062 L 132.246094 24.898438 L 132.523438 25.140625 L 132.800781 25.390625 L 133.082031 25.652344 L 133.359375 25.921875 L 133.636719 26.203125 L 133.917969 26.492188 L 134.195312 26.789062 L 134.472656 27.097656 L 134.753906 27.414062 L 135.03125 27.742188 L 135.308594 28.078125 L 135.589844 28.425781 L 135.867188 28.78125 L 136.144531 29.144531 L 136.425781 29.519531 L 136.703125 29.902344 L 136.980469 30.296875 L 137.261719 30.699219 L 137.539062 31.113281 L 137.816406 31.535156 L 138.09375 31.964844 L 138.375 32.40625 L 138.652344 32.855469 L 138.929688 33.316406 L 139.210938 33.785156 L 139.488281 34.265625 L 139.765625 34.753906 L 140.046875 35.25 L 140.324219 35.757812 L 140.601562 36.273438 L 140.882812 36.800781 L 141.160156 37.335938 L 141.4375 37.878906 L 141.71875 38.433594 L 141.996094 38.996094 L 142.273438 39.566406 L 142.554688 40.148438 L 142.832031 40.738281 L 143.109375 41.335938 L 143.390625 41.945312 L 143.667969 42.5625 L 143.945312 43.191406 L 144.226562 43.824219 L 144.503906 44.46875 L 144.78125 45.121094 L 145.058594 45.78125 L 145.339844 46.453125 L 145.617188 47.132812 L 145.894531 47.820312 L 146.175781 48.515625 L 146.453125 49.21875 L 146.730469 49.929688 L 147.011719 50.652344 L 147.289062 51.378906 L 147.566406 52.117188 L 147.847656 52.859375 L 148.125 53.613281 L 148.402344 54.371094 L 148.683594 55.140625 L 148.960938 55.914062 L 149.238281 56.695312 L 149.519531 57.484375 L 149.796875 58.28125 L 150.074219 59.085938 L 150.355469 59.894531 L 150.632812 60.710938 L 150.910156 61.535156 L 151.1875 62.367188 L 151.46875 63.203125 L 151.746094 64.042969 L 152.023438 64.894531 L 152.304688 65.746094 L 152.582031 66.605469 L 152.859375 67.472656 L 153.140625 68.34375 L 153.417969 69.21875 L 153.695312 70.101562 L 153.976562 70.984375 L 154.253906 71.875 L 154.53125 72.769531 L 154.8125 73.671875 L 155.089844 74.574219 L 155.367188 75.480469 L 155.648438 76.390625 L 156.203125 78.226562 L 156.484375 79.144531 L 157.039062 80.996094 L 157.316406 81.925781 L 157.597656 82.859375 L 157.875 83.792969 L 158.152344 84.730469 L 158.433594 85.667969 L 158.710938 86.605469 L 158.988281 87.546875 L 159.269531 88.488281 L 159.546875 89.433594 L 159.824219 90.375 L 160.105469 91.320312 L 160.660156 93.210938 L 160.941406 94.15625 L 161.21875 95.101562 L 161.496094 96.042969 L 161.777344 96.988281 L 162.332031 98.871094 L 162.613281 99.8125 L 163.167969 101.6875 L 163.445312 102.621094 L 163.726562 103.554688 L 164.003906 104.488281 L 164.28125 105.414062 L 164.5625 106.34375 L 165.117188 108.1875 L 165.398438 109.101562 L 165.675781 110.015625 L 165.953125 110.925781 L 166.234375 111.832031 L 166.511719 112.738281 L 166.789062 113.636719 L 167.070312 114.53125 L 167.347656 115.421875 L 167.625 116.308594 L 167.90625 117.1875 L 168.183594 118.066406 L 168.460938 118.9375 L 168.742188 119.804688 L 169.019531 120.667969 L 169.296875 121.523438 L 169.578125 122.375 L 169.855469 123.21875 L 170.132812 124.058594 L 170.410156 124.894531 L 170.691406 125.722656 L 170.96875 126.542969 L 171.246094 127.359375 L 171.527344 128.171875 L 171.804688 128.976562 L 172.082031 129.773438 L 172.363281 130.5625 L 172.640625 131.347656 L 172.917969 132.125 L 173.199219 132.898438 L 173.476562 133.660156 L 173.753906 134.417969 L 174.035156 135.171875 L 174.3125 135.914062 L 174.589844 136.652344 L 174.871094 137.382812 L 175.148438 138.105469 L 175.425781 138.820312 L 175.707031 139.527344 L 175.984375 140.230469 L 176.261719 140.925781 L 176.539062 141.613281 L 176.820312 142.292969 L 177.097656 142.964844 L 177.375 143.628906 L 177.65625 144.285156 L 177.933594 144.9375 L 178.210938 145.582031 L 178.492188 146.214844 L 178.769531 146.84375 L 179.046875 147.464844 L 179.328125 148.078125 L 179.605469 148.6875 L 179.882812 149.285156 L 180.164062 149.875 L 180.441406 150.460938 L 180.71875 151.039062 L 181 151.609375 L 181.277344 152.171875 L 181.554688 152.726562 L 181.835938 153.273438 L 182.113281 153.816406 L 182.390625 154.351562 L 182.667969 154.878906 L 182.949219 155.398438 L 183.226562 155.910156 L 183.503906 156.417969 L 183.785156 156.914062 L 184.0625 157.40625 L 184.339844 157.894531 L 184.621094 158.371094 L 184.898438 158.84375 L 185.175781 159.308594 L 185.457031 159.769531 L 185.734375 160.21875 L 186.011719 160.664062 L 186.292969 161.105469 L 186.570312 161.535156 L 186.847656 161.960938 L 187.128906 162.382812 L 187.40625 162.796875 L 187.683594 163.203125 L 187.964844 163.605469 L 188.242188 164 L 188.519531 164.386719 L 188.800781 164.769531 L 189.078125 165.148438 L 189.355469 165.519531 L 189.632812 165.882812 L 189.914062 166.246094 L 190.191406 166.597656 L 190.46875 166.945312 L 190.75 167.289062 L 191.027344 167.628906 L 191.304688 167.960938 L 191.585938 168.285156 L 191.863281 168.609375 L 192.140625 168.925781 L 192.421875 169.234375 L 192.976562 169.84375 L 193.257812 170.136719 L 193.535156 170.429688 L 193.8125 170.714844 L 194.371094 171.273438 L 194.648438 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="151.101562"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="151.101562"/>
+ <use xlink:href="#glyph0-3" x="36.262756" y="151.101562"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="112.636719"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="112.636719"/>
+ <use xlink:href="#glyph0-4" x="36.262756" y="112.636719"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="74.175781"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="74.175781"/>
+ <use xlink:href="#glyph0-5" x="36.262756" y="74.175781"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.261719" y="35.710938"/>
+ <use xlink:href="#glyph0-2" x="33.597305" y="35.710938"/>
+ <use xlink:href="#glyph0-6" x="36.262756" y="35.710938"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 147.664062 L 48.683594 147.664062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 109.199219 L 48.683594 109.199219 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 70.738281 L 48.683594 70.738281 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.429688 32.273438 L 48.683594 32.273438 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.632812 183.28125 L 55.632812 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 90.386719 183.28125 L 90.386719 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 125.140625 183.28125 L 125.140625 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 159.894531 183.28125 L 159.894531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.648438 183.28125 L 194.648438 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="46.296875" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="51.632462" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="54.297913" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.633499" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="81.050781" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="86.386368" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="89.051819" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="94.387405" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="115.804688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="121.140274" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="123.805725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="129.141312" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="150.558594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="155.89418" y="192.992188"/>
+ <use xlink:href="#glyph0-8" x="158.559631" y="192.992188"/>
+ <use xlink:href="#glyph0-7" x="163.895218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-9" x="185.3125" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.648087" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.313538" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.649124" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="122.140625" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/spike.svg b/documentation/ui/figure/spike.svg
new file mode 100644
index 0000000..5bf788b
--- /dev/null
+++ b/documentation/ui/figure/spike.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 153 L 202 153 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 78 L 54.019531 78 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 39 L 202 39 L 202 40 L 54.019531 40 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 172 L 202.601562 172 L 202.601562 174 L 54.019531 174 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 136 L 54.019531 136 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 95 L 202.601562 95 L 202.601562 97 L 54.019531 97 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 57 L 202.601562 57 L 202.601562 59 L 54.019531 59 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 19 L 202.601562 19 L 202.601562 21 L 54.019531 21 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface236">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 153.546875 L 201.601562 153.546875 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.496094 L 201.601562 115.496094 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 77.441406 L 201.601562 77.441406 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 39.390625 L 201.601562 39.390625 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 172.570312 L 201.601562 172.570312 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.519531 L 201.601562 134.519531 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.46875 L 201.601562 96.46875 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 58.417969 L 201.601562 58.417969 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 20.367188 L 201.601562 20.367188 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 60.996094 171.523438 L 61.265625 171.503906 L 61.53125 171.480469 L 61.800781 171.460938 L 62.878906 171.367188 L 63.144531 171.34375 L 63.414062 171.316406 L 63.683594 171.292969 L 63.953125 171.265625 L 64.222656 171.242188 L 64.492188 171.214844 L 64.757812 171.1875 L 65.027344 171.15625 L 65.566406 171.101562 L 66.105469 171.039062 L 66.371094 171.007812 L 67.179688 170.914062 L 67.71875 170.84375 L 67.984375 170.808594 L 68.523438 170.738281 L 68.792969 170.699219 L 69.0625 170.664062 L 69.332031 170.625 L 69.597656 170.585938 L 69.867188 170.542969 L 70.136719 170.503906 L 70.945312 170.375 L 71.210938 170.332031 L 72.289062 170.144531 L 72.558594 170.09375 L 72.824219 170.042969 L 73.363281 169.941406 L 73.902344 169.832031 L 74.167969 169.777344 L 74.4375 169.722656 L 75.246094 169.546875 L 75.515625 169.484375 L 75.78125 169.421875 L 76.050781 169.359375 L 76.859375 169.160156 L 77.128906 169.089844 L 77.394531 169.019531 L 77.664062 168.945312 L 77.933594 168.875 L 78.203125 168.796875 L 78.472656 168.722656 L 78.742188 168.644531 L 79.007812 168.566406 L 79.546875 168.402344 L 80.085938 168.230469 L 80.355469 168.140625 L 80.621094 168.054688 L 81.429688 167.773438 L 81.96875 167.578125 L 82.234375 167.476562 L 83.042969 167.160156 L 83.3125 167.050781 L 83.582031 166.9375 L 83.847656 166.824219 L 84.386719 166.589844 L 84.65625 166.46875 L 85.195312 166.21875 L 85.460938 166.089844 L 86 165.824219 L 86.539062 165.550781 L 86.808594 165.40625 L 87.074219 165.261719 L 87.613281 164.964844 L 88.152344 164.652344 L 88.417969 164.492188 L 88.6875 164.328125 L 89.226562 163.992188 L 89.765625 163.640625 L 90.03125 163.460938 L 90.570312 163.085938 L 90.839844 162.894531 L 91.109375 162.699219 L 91.378906 162.5 L 91.644531 162.296875 L 92.183594 161.875 L 92.453125 161.660156 L 92.722656 161.4375 L 92.992188 161.210938 L 93.257812 160.980469 L 93.527344 160.746094 L 93.796875 160.507812 L 94.066406 160.265625 L 94.335938 160.015625 L 94.605469 159.761719 L 94.871094 159.5 L 95.140625 159.238281 L 95.410156 158.96875 L 95.679688 158.691406 L 95.949219 158.410156 L 96.21875 158.125 L 96.484375 157.832031 L 97.023438 157.230469 L 97.292969 156.917969 L 97.5625 156.601562 L 97.832031 156.277344 L 98.097656 155.949219 L 98.367188 155.613281 L 98.636719 155.269531 L 98.90625 154.917969 L 99.175781 154.5625 L 99.445312 154.195312 L 99.710938 153.824219 L 99.980469 153.445312 L 100.25 153.058594 L 100.519531 152.664062 L 100.789062 152.257812 L 101.058594 151.847656 L 101.324219 151.429688 L 101.59375 151 L 101.863281 150.5625 L 102.132812 150.117188 L 102.402344 149.664062 L 102.667969 149.199219 L 102.9375 148.726562 L 103.207031 148.246094 L 103.476562 147.753906 L 103.746094 147.25 L 104.015625 146.738281 L 104.28125 146.214844 L 104.550781 145.679688 L 104.820312 145.136719 L 105.089844 144.582031 L 105.359375 144.015625 L 105.628906 143.4375 L 105.894531 142.847656 L 106.164062 142.246094 L 106.433594 141.632812 L 106.703125 141.003906 L 106.972656 140.367188 L 107.242188 139.714844 L 107.507812 139.050781 L 107.777344 138.371094 L 108.046875 137.679688 L 108.316406 136.972656 L 108.585938 136.25 L 108.855469 135.515625 L 109.121094 134.765625 L 109.390625 134 L 109.660156 133.21875 L 109.929688 132.421875 L 110.199219 131.609375 L 110.46875 130.78125 L 110.734375 129.9375 L 111.003906 129.074219 L 111.273438 128.191406 L 111.542969 127.292969 L 111.8125 126.378906 L 112.082031 125.441406 L 112.347656 124.488281 L 112.617188 123.515625 L 112.886719 122.523438 L 113.15625 121.507812 L 113.425781 120.476562 L 113.695312 119.421875 L 113.960938 118.34375 L 114.230469 117.246094 L 114.5 116.128906 L 114.769531 114.984375 L 115.039062 113.820312 L 115.308594 112.628906 L 115.574219 111.417969 L 115.84375 110.179688 L 116.113281 108.914062 L 116.382812 107.628906 L 116.652344 106.3125 L 116.921875 104.972656 L 117.1875 103.601562 L 117.457031 102.207031 L 117.726562 100.78125 L 117.996094 99.328125 L 118.265625 97.847656 L 118.53125 96.335938 L 118.800781 94.789062 L 119.070312 93.214844 L 119.339844 91.609375 L 119.609375 89.972656 L 119.878906 88.300781 L 120.144531 86.59375 L 120.414062 84.851562 L 120.683594 83.078125 L 120.953125 81.265625 L 121.222656 79.417969 L 121.492188 77.53125 L 121.757812 75.609375 L 122.027344 73.644531 L 122.296875 71.644531 L 122.566406 69.601562 L 122.835938 67.515625 L 123.105469 65.390625 L 123.371094 63.21875 L 123.640625 61.007812 L 123.910156 58.746094 L 124.179688 56.445312 L 124.449219 54.09375 L 124.71875 51.695312 L 124.984375 49.246094 L 125.253906 46.75 L 125.523438 44.203125 L 125.792969 41.605469 L 126.0625 38.953125 L 126.332031 36.25 L 126.597656 33.492188 L 126.867188 30.675781 L 127.136719 27.804688 L 127.40625 24.871094 L 127.675781 21.882812 L 127.945312 21.882812 L 128.210938 24.871094 L 128.480469 27.804688 L 128.75 30.675781 L 129.019531 33.492188 L 129.289062 36.25 L 129.558594 38.953125 L 129.824219 41.605469 L 130.09375 44.203125 L 130.363281 46.75 L 130.632812 49.246094 L 130.902344 51.695312 L 131.171875 54.09375 L 131.4375 56.445312 L 131.707031 58.746094 L 131.976562 61.007812 L 132.246094 63.21875 L 132.515625 65.390625 L 132.78125 67.515625 L 133.050781 69.601562 L 133.320312 71.644531 L 133.589844 73.644531 L 133.859375 75.609375 L 134.128906 77.53125 L 134.394531 79.417969 L 134.664062 81.265625 L 134.933594 83.078125 L 135.203125 84.851562 L 135.472656 86.59375 L 135.742188 88.300781 L 136.007812 89.972656 L 136.277344 91.609375 L 136.546875 93.214844 L 136.816406 94.789062 L 137.085938 96.335938 L 137.355469 97.847656 L 137.621094 99.328125 L 137.890625 100.78125 L 138.160156 102.207031 L 138.429688 103.601562 L 138.699219 104.972656 L 138.96875 106.3125 L 139.234375 107.628906 L 139.503906 108.914062 L 139.773438 110.179688 L 140.042969 111.417969 L 140.3125 112.628906 L 140.582031 113.820312 L 140.847656 114.984375 L 141.117188 116.128906 L 141.386719 117.246094 L 141.65625 118.34375 L 141.925781 119.421875 L 142.195312 120.476562 L 142.460938 121.507812 L 142.730469 122.523438 L 143 123.515625 L 143.269531 124.488281 L 143.539062 125.441406 L 143.808594 126.378906 L 144.074219 127.292969 L 144.34375 128.191406 L 144.613281 129.074219 L 144.882812 129.9375 L 145.152344 130.78125 L 145.421875 131.609375 L 145.6875 132.421875 L 145.957031 133.21875 L 146.226562 134 L 146.496094 134.765625 L 146.765625 135.515625 L 147.03125 136.25 L 147.300781 136.972656 L 147.570312 137.679688 L 147.839844 138.371094 L 148.109375 139.050781 L 148.378906 139.714844 L 148.644531 140.367188 L 148.914062 141.003906 L 149.183594 141.632812 L 149.453125 142.246094 L 149.722656 142.847656 L 149.992188 143.4375 L 150.257812 144.015625 L 150.527344 144.582031 L 150.796875 145.136719 L 151.066406 145.679688 L 151.335938 146.214844 L 151.605469 146.738281 L 151.871094 147.25 L 152.140625 147.753906 L 152.410156 148.246094 L 152.679688 148.726562 L 152.949219 149.199219 L 153.21875 149.664062 L 153.484375 150.117188 L 153.753906 150.5625 L 154.023438 151 L 154.292969 151.429688 L 154.5625 151.847656 L 154.832031 152.257812 L 155.097656 152.664062 L 155.367188 153.058594 L 155.636719 153.445312 L 155.90625 153.824219 L 156.175781 154.195312 L 156.445312 154.5625 L 156.710938 154.917969 L 156.980469 155.269531 L 157.25 155.613281 L 157.519531 155.949219 L 157.789062 156.277344 L 158.058594 156.601562 L 158.324219 156.917969 L 158.59375 157.230469 L 159.132812 157.832031 L 159.402344 158.125 L 159.671875 158.410156 L 159.9375 158.691406 L 160.207031 158.96875 L 160.476562 159.238281 L 161.015625 159.761719 L 161.28125 160.015625 L 161.550781 160.265625 L 161.820312 160.507812 L 162.089844 160.746094 L 162.359375 160.980469 L 162.628906 161.210938 L 162.894531 161.4375 L 163.164062 161.660156 L 163.433594 161.875 L 163.972656 162.296875 L 164.242188 162.5 L 164.507812 162.699219 L 164.777344 162.894531 L 165.046875 163.085938 L 165.585938 163.460938 L 165.855469 163.640625 L 166.121094 163.816406 L 166.390625 163.992188 L 166.929688 164.328125 L 167.199219 164.492188 L 167.46875 164.652344 L 167.734375 164.808594 L 168.003906 164.964844 L 168.542969 165.261719 L 169.082031 165.550781 L 169.347656 165.6875 L 169.617188 165.824219 L 170.15625 166.089844 L 170.425781 166.21875 L 170.695312 166.34375 L 170.960938 166.46875 L 171.230469 166.589844 L 171.769531 166.824219 L 172.308594 167.050781 L 172.574219 167.160156 L 173.382812 167.476562 L 173.652344 167.578125 L 173.921875 167.675781 L 174.1875 167.773438 L 174.996094 168.054688 L 175.265625 168.140625 L 175.535156 168.230469 L 175.800781 168.316406 L 176.070312 168.402344 L 176.609375 168.566406 L 176.878906 168.644531 L 177.144531 168.722656 L 177.414062 168.796875 L 177.683594 168.875 L 177.953125 168.945312 L 178.222656 169.019531 L 178.492188 169.089844 L 178.757812 169.160156 L 179.566406 169.359375 L 180.105469 169.484375 L 180.371094 169.546875 L 181.179688 169.722656 L 181.71875 169.832031 L 181.984375 169.886719 L 182.253906 169.941406 L 183.332031 170.144531 L 183.597656 170.191406 L 184.40625 170.332031 L 184.945312 170.417969 L 185.210938 170.460938 L 185.480469 170.503906 L 185.75 170.542969 L 186.019531 170.585938 L 186.558594 170.664062 L 186.824219 170.699219 L 187.09375 170.738281 L 188.171875 170.878906 L 188.4375 170.914062 L 189.785156 171.070312 L 190.050781 171.101562 L 190.589844 171.15625 L 190.859375 171.1875 L 191.128906 171.214844 L 191.394531 171.242188 L 191.664062 171.265625 L 191.933594 171.292969 L 192.203125 171.316406 L 192.472656 171.34375 L 192.742188 171.367188 L 193.007812 171.390625 L 193.816406 171.460938 L 194.085938 171.480469 L 194.355469 171.503906 L 194.621094 171.523438 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="176.007812"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="176.007812"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="176.007812"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="176.007812"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.957031"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.957031"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.957031"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.957031"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="99.90625"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="99.90625"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="99.90625"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="99.90625"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="61.855469"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="61.855469"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="61.855469"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="61.855469"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="23.804688"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="23.804688"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="23.804688"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="23.804688"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 172.570312 L 54.019531 172.570312 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.519531 L 54.019531 134.519531 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.46875 L 54.019531 96.46875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 58.417969 L 54.019531 58.417969 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 20.367188 L 54.019531 20.367188 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/terms.svg b/documentation/ui/figure/terms.svg
new file mode 100644
index 0000000..acc306a
--- /dev/null
+++ b/documentation/ui/figure/terms.svg
@@ -0,0 +1,4955 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="712pt" height="1512pt" viewBox="0 0 712 1512" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-7">
+<path style="stroke:none;" d="M 3.171875 -2.375 L 3.171875 -5.421875 L 1.015625 -2.375 Z M 3.1875 0 L 3.1875 -1.640625 L 0.25 -1.640625 L 0.25 -2.46875 L 3.3125 -6.734375 L 4.03125 -6.734375 L 4.03125 -2.375 L 5.015625 -2.375 L 5.015625 -1.640625 L 4.03125 -1.640625 L 4.03125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-8">
+<path style="stroke:none;" d="M 2.8125 -6.734375 C 3.5625 -6.734375 4.082031 -6.535156 4.375 -6.140625 C 4.664062 -5.753906 4.8125 -5.359375 4.8125 -4.953125 L 3.984375 -4.953125 C 3.929688 -5.210938 3.851562 -5.421875 3.75 -5.578125 C 3.539062 -5.859375 3.226562 -6 2.8125 -6 C 2.34375 -6 1.96875 -5.78125 1.6875 -5.34375 C 1.414062 -4.90625 1.265625 -4.28125 1.234375 -3.46875 C 1.421875 -3.75 1.664062 -3.960938 1.96875 -4.109375 C 2.226562 -4.234375 2.523438 -4.296875 2.859375 -4.296875 C 3.421875 -4.296875 3.910156 -4.113281 4.328125 -3.75 C 4.742188 -3.394531 4.953125 -2.863281 4.953125 -2.15625 C 4.953125 -1.539062 4.753906 -1 4.359375 -0.53125 C 3.960938 -0.0625 3.398438 0.171875 2.671875 0.171875 C 2.046875 0.171875 1.503906 -0.0625 1.046875 -0.53125 C 0.585938 -1.007812 0.359375 -1.816406 0.359375 -2.953125 C 0.359375 -3.785156 0.460938 -4.488281 0.671875 -5.0625 C 1.054688 -6.175781 1.769531 -6.734375 2.8125 -6.734375 Z M 2.75 -0.578125 C 3.1875 -0.578125 3.515625 -0.722656 3.734375 -1.015625 C 3.960938 -1.316406 4.078125 -1.671875 4.078125 -2.078125 C 4.078125 -2.421875 3.976562 -2.75 3.78125 -3.0625 C 3.582031 -3.375 3.222656 -3.53125 2.703125 -3.53125 C 2.335938 -3.53125 2.019531 -3.410156 1.75 -3.171875 C 1.476562 -2.929688 1.34375 -2.566406 1.34375 -2.078125 C 1.34375 -1.648438 1.460938 -1.289062 1.703125 -1 C 1.953125 -0.71875 2.300781 -0.578125 2.75 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-9">
+<path style="stroke:none;" d="M 2.609375 -3.890625 C 2.984375 -3.890625 3.273438 -3.992188 3.484375 -4.203125 C 3.691406 -4.410156 3.796875 -4.660156 3.796875 -4.953125 C 3.796875 -5.203125 3.691406 -5.429688 3.484375 -5.640625 C 3.285156 -5.847656 2.984375 -5.953125 2.578125 -5.953125 C 2.171875 -5.953125 1.875 -5.847656 1.6875 -5.640625 C 1.507812 -5.429688 1.421875 -5.1875 1.421875 -4.90625 C 1.421875 -4.59375 1.535156 -4.34375 1.765625 -4.15625 C 2.003906 -3.976562 2.285156 -3.890625 2.609375 -3.890625 Z M 2.65625 -0.578125 C 3.050781 -0.578125 3.375 -0.679688 3.625 -0.890625 C 3.882812 -1.097656 4.015625 -1.414062 4.015625 -1.84375 C 4.015625 -2.269531 3.878906 -2.59375 3.609375 -2.8125 C 3.347656 -3.039062 3.007812 -3.15625 2.59375 -3.15625 C 2.195312 -3.15625 1.867188 -3.039062 1.609375 -2.8125 C 1.359375 -2.582031 1.234375 -2.265625 1.234375 -1.859375 C 1.234375 -1.515625 1.347656 -1.210938 1.578125 -0.953125 C 1.816406 -0.703125 2.175781 -0.578125 2.65625 -0.578125 Z M 1.46875 -3.578125 C 1.226562 -3.671875 1.039062 -3.785156 0.90625 -3.921875 C 0.664062 -4.171875 0.546875 -4.5 0.546875 -4.90625 C 0.546875 -5.40625 0.722656 -5.832031 1.078125 -6.1875 C 1.441406 -6.550781 1.957031 -6.734375 2.625 -6.734375 C 3.269531 -6.734375 3.773438 -6.5625 4.140625 -6.21875 C 4.503906 -5.875 4.6875 -5.476562 4.6875 -5.03125 C 4.6875 -4.613281 4.582031 -4.273438 4.375 -4.015625 C 4.25 -3.867188 4.0625 -3.722656 3.8125 -3.578125 C 4.09375 -3.453125 4.3125 -3.304688 4.46875 -3.140625 C 4.769531 -2.828125 4.921875 -2.421875 4.921875 -1.921875 C 4.921875 -1.335938 4.722656 -0.835938 4.328125 -0.421875 C 3.929688 -0.015625 3.367188 0.1875 2.640625 0.1875 C 1.984375 0.1875 1.429688 0.0078125 0.984375 -0.34375 C 0.535156 -0.695312 0.3125 -1.210938 0.3125 -1.890625 C 0.3125 -2.285156 0.40625 -2.625 0.59375 -2.90625 C 0.789062 -3.195312 1.082031 -3.421875 1.46875 -3.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-2">
+<path style="stroke:none;" d="M -7.234375 -1.03125 C -7.671875 -1.050781 -7.988281 -1.128906 -8.1875 -1.265625 C -8.550781 -1.515625 -8.734375 -1.988281 -8.734375 -2.6875 C -8.734375 -2.757812 -8.726562 -2.828125 -8.71875 -2.890625 C -8.71875 -2.960938 -8.710938 -3.046875 -8.703125 -3.140625 L -7.75 -3.140625 C -7.757812 -3.023438 -7.765625 -2.941406 -7.765625 -2.890625 C -7.765625 -2.847656 -7.765625 -2.804688 -7.765625 -2.765625 C -7.765625 -2.441406 -7.679688 -2.25 -7.515625 -2.1875 C -7.347656 -2.125 -6.925781 -2.09375 -6.25 -2.09375 L -6.25 -3.140625 L -5.421875 -3.140625 L -5.421875 -2.078125 L 0 -2.078125 L 0 -1.03125 L -5.421875 -1.03125 L -5.421875 -0.171875 L -6.25 -0.171875 L -6.25 -1.03125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-0">
+<path style="stroke:none;" d="M 0.90625 0 L 0.90625 -8.640625 L 7.859375 -8.640625 L 7.859375 0 Z M 6.78125 -1.078125 L 6.78125 -7.5625 L 1.984375 -7.5625 L 1.984375 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-1">
+<path style="stroke:none;" d="M 7.1875 -8.640625 L 7.1875 -7.109375 L 4.609375 -7.109375 L 4.609375 0 L 2.796875 0 L 2.796875 -7.109375 L 0.1875 -7.109375 L 0.1875 -8.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-2">
+<path style="stroke:none;" d="M 4.25 -6.546875 C 4.28125 -6.546875 4.304688 -6.539062 4.328125 -6.53125 C 4.347656 -6.53125 4.394531 -6.53125 4.46875 -6.53125 L 4.46875 -4.8125 C 4.363281 -4.820312 4.269531 -4.828125 4.1875 -4.828125 C 4.101562 -4.835938 4.035156 -4.84375 3.984375 -4.84375 C 3.316406 -4.84375 2.867188 -4.625 2.640625 -4.1875 C 2.503906 -3.945312 2.4375 -3.566406 2.4375 -3.046875 L 2.4375 0 L 0.765625 0 L 0.765625 -6.390625 L 2.359375 -6.390625 L 2.359375 -5.28125 C 2.617188 -5.695312 2.84375 -5.984375 3.03125 -6.140625 C 3.34375 -6.410156 3.75 -6.546875 4.25 -6.546875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-3">
+<path style="stroke:none;" d="M 2.5 -7.15625 L 0.796875 -7.15625 L 0.796875 -8.6875 L 2.5 -8.6875 Z M 0.796875 -6.390625 L 2.5 -6.390625 L 2.5 0 L 0.796875 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-4">
+<path style="stroke:none;" d="M 4.296875 -3.109375 C 4.191406 -3.035156 4.085938 -2.976562 3.984375 -2.9375 C 3.878906 -2.90625 3.734375 -2.867188 3.546875 -2.828125 L 3.171875 -2.765625 C 2.816406 -2.703125 2.5625 -2.625 2.40625 -2.53125 C 2.144531 -2.375 2.015625 -2.140625 2.015625 -1.828125 C 2.015625 -1.535156 2.09375 -1.328125 2.25 -1.203125 C 2.414062 -1.078125 2.613281 -1.015625 2.84375 -1.015625 C 3.195312 -1.015625 3.523438 -1.117188 3.828125 -1.328125 C 4.128906 -1.535156 4.285156 -1.921875 4.296875 -2.484375 Z M 3.28125 -3.890625 C 3.59375 -3.921875 3.816406 -3.96875 3.953125 -4.03125 C 4.191406 -4.132812 4.3125 -4.289062 4.3125 -4.5 C 4.3125 -4.769531 4.21875 -4.953125 4.03125 -5.046875 C 3.851562 -5.148438 3.585938 -5.203125 3.234375 -5.203125 C 2.835938 -5.203125 2.554688 -5.101562 2.390625 -4.90625 C 2.273438 -4.757812 2.195312 -4.5625 2.15625 -4.3125 L 0.546875 -4.3125 C 0.585938 -4.875 0.742188 -5.335938 1.015625 -5.703125 C 1.460938 -6.265625 2.222656 -6.546875 3.296875 -6.546875 C 3.992188 -6.546875 4.613281 -6.40625 5.15625 -6.125 C 5.695312 -5.84375 5.96875 -5.316406 5.96875 -4.546875 L 5.96875 -1.625 C 5.96875 -1.414062 5.972656 -1.171875 5.984375 -0.890625 C 5.992188 -0.671875 6.023438 -0.519531 6.078125 -0.4375 C 6.140625 -0.363281 6.222656 -0.300781 6.328125 -0.25 L 6.328125 0 L 4.515625 0 C 4.460938 -0.125 4.425781 -0.242188 4.40625 -0.359375 C 4.382812 -0.472656 4.367188 -0.601562 4.359375 -0.75 C 4.128906 -0.5 3.863281 -0.285156 3.5625 -0.109375 C 3.207031 0.0976562 2.800781 0.203125 2.34375 0.203125 C 1.769531 0.203125 1.289062 0.0351562 0.90625 -0.296875 C 0.53125 -0.628906 0.34375 -1.097656 0.34375 -1.703125 C 0.34375 -2.484375 0.644531 -3.050781 1.25 -3.40625 C 1.582031 -3.59375 2.070312 -3.726562 2.71875 -3.8125 Z M 3.375 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-5">
+<path style="stroke:none;" d="M 4.3125 -6.546875 C 4.976562 -6.546875 5.519531 -6.367188 5.9375 -6.015625 C 6.351562 -5.671875 6.5625 -5.097656 6.5625 -4.296875 L 6.5625 0 L 4.859375 0 L 4.859375 -3.890625 C 4.859375 -4.222656 4.8125 -4.476562 4.71875 -4.65625 C 4.5625 -4.988281 4.25 -5.15625 3.78125 -5.15625 C 3.21875 -5.15625 2.832031 -4.914062 2.625 -4.4375 C 2.507812 -4.175781 2.453125 -3.847656 2.453125 -3.453125 L 2.453125 0 L 0.796875 0 L 0.796875 -6.375 L 2.40625 -6.375 L 2.40625 -5.4375 C 2.613281 -5.769531 2.816406 -6.007812 3.015625 -6.15625 C 3.359375 -6.414062 3.789062 -6.546875 4.3125 -6.546875 Z M 3.703125 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-6">
+<path style="stroke:none;" d="M 3.515625 -1.375 C 3.910156 -1.375 4.242188 -1.519531 4.515625 -1.8125 C 4.785156 -2.101562 4.921875 -2.570312 4.921875 -3.21875 C 4.921875 -3.820312 4.789062 -4.28125 4.53125 -4.59375 C 4.28125 -4.914062 3.9375 -5.078125 3.5 -5.078125 C 2.914062 -5.078125 2.515625 -4.800781 2.296875 -4.25 C 2.171875 -3.957031 2.109375 -3.597656 2.109375 -3.171875 C 2.109375 -2.796875 2.171875 -2.46875 2.296875 -2.1875 C 2.523438 -1.644531 2.929688 -1.375 3.515625 -1.375 Z M 3.109375 -6.546875 C 3.429688 -6.546875 3.707031 -6.492188 3.9375 -6.390625 C 4.34375 -6.222656 4.671875 -5.914062 4.921875 -5.46875 L 4.921875 -6.390625 L 6.546875 -6.390625 L 6.546875 -0.328125 C 6.546875 0.492188 6.410156 1.113281 6.140625 1.53125 C 5.660156 2.25 4.742188 2.609375 3.390625 2.609375 C 2.578125 2.609375 1.910156 2.445312 1.390625 2.125 C 0.878906 1.8125 0.597656 1.335938 0.546875 0.703125 L 2.359375 0.703125 C 2.398438 0.890625 2.472656 1.03125 2.578125 1.125 C 2.765625 1.269531 3.070312 1.34375 3.5 1.34375 C 4.09375 1.34375 4.492188 1.144531 4.703125 0.75 C 4.835938 0.488281 4.90625 0.0507812 4.90625 -0.5625 L 4.90625 -0.96875 C 4.738281 -0.695312 4.566406 -0.492188 4.390625 -0.359375 C 4.054688 -0.0976562 3.625 0.03125 3.09375 0.03125 C 2.269531 0.03125 1.613281 -0.253906 1.125 -0.828125 C 0.632812 -1.410156 0.390625 -2.191406 0.390625 -3.171875 C 0.390625 -4.117188 0.625 -4.914062 1.09375 -5.5625 C 1.570312 -6.21875 2.242188 -6.546875 3.109375 -6.546875 Z M 3.640625 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-7">
+<path style="stroke:none;" d="M 2.484375 0 L 0.8125 0 L 0.8125 -8.640625 L 2.484375 -8.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-8">
+<path style="stroke:none;" d="M 3.296875 -5.1875 C 2.910156 -5.1875 2.609375 -5.0625 2.390625 -4.8125 C 2.179688 -4.570312 2.050781 -4.242188 2 -3.828125 L 4.59375 -3.828125 C 4.5625 -4.273438 4.425781 -4.613281 4.1875 -4.84375 C 3.945312 -5.070312 3.648438 -5.1875 3.296875 -5.1875 Z M 3.296875 -6.5625 C 3.828125 -6.5625 4.304688 -6.457031 4.734375 -6.25 C 5.160156 -6.050781 5.515625 -5.738281 5.796875 -5.3125 C 6.046875 -4.9375 6.207031 -4.5 6.28125 -4 C 6.320312 -3.707031 6.335938 -3.285156 6.328125 -2.734375 L 1.953125 -2.734375 C 1.984375 -2.085938 2.1875 -1.640625 2.5625 -1.390625 C 2.789062 -1.222656 3.066406 -1.140625 3.390625 -1.140625 C 3.734375 -1.140625 4.015625 -1.238281 4.234375 -1.4375 C 4.347656 -1.539062 4.453125 -1.6875 4.546875 -1.875 L 6.25 -1.875 C 6.207031 -1.5 6.007812 -1.113281 5.65625 -0.71875 C 5.101562 -0.09375 4.335938 0.21875 3.359375 0.21875 C 2.546875 0.21875 1.828125 -0.0390625 1.203125 -0.5625 C 0.585938 -1.09375 0.28125 -1.945312 0.28125 -3.125 C 0.28125 -4.226562 0.554688 -5.078125 1.109375 -5.671875 C 1.671875 -6.265625 2.398438 -6.5625 3.296875 -6.5625 Z M 3.421875 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-9">
+<path style="stroke:none;" d="M 2.671875 -7.140625 L 2.671875 -5.234375 L 4.78125 -5.234375 C 5.164062 -5.234375 5.472656 -5.300781 5.703125 -5.4375 C 5.941406 -5.582031 6.0625 -5.835938 6.0625 -6.203125 C 6.0625 -6.609375 5.90625 -6.875 5.59375 -7 C 5.320312 -7.09375 4.976562 -7.140625 4.5625 -7.140625 Z M 2.671875 -3.796875 L 2.671875 -1.5 L 4.78125 -1.5 C 5.164062 -1.5 5.460938 -1.550781 5.671875 -1.65625 C 6.054688 -1.84375 6.25 -2.203125 6.25 -2.734375 C 6.25 -3.179688 6.0625 -3.488281 5.6875 -3.65625 C 5.476562 -3.75 5.1875 -3.796875 4.8125 -3.796875 Z M 5.140625 -8.640625 C 6.203125 -8.617188 6.953125 -8.3125 7.390625 -7.71875 C 7.648438 -7.351562 7.78125 -6.914062 7.78125 -6.40625 C 7.78125 -5.875 7.648438 -5.445312 7.390625 -5.125 C 7.242188 -4.945312 7.023438 -4.785156 6.734375 -4.640625 C 7.171875 -4.472656 7.5 -4.21875 7.71875 -3.875 C 7.945312 -3.53125 8.0625 -3.109375 8.0625 -2.609375 C 8.0625 -2.097656 7.9375 -1.640625 7.6875 -1.234375 C 7.519531 -0.960938 7.3125 -0.734375 7.0625 -0.546875 C 6.789062 -0.335938 6.460938 -0.191406 6.078125 -0.109375 C 5.703125 -0.0351562 5.296875 0 4.859375 0 L 0.9375 0 L 0.9375 -8.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-10">
+<path style="stroke:none;" d="M 5.78125 -5.890625 C 5.78125 -6.335938 5.660156 -6.65625 5.421875 -6.84375 C 5.179688 -7.039062 4.851562 -7.140625 4.4375 -7.140625 L 2.75 -7.140625 L 2.75 -4.59375 L 4.4375 -4.59375 C 4.851562 -4.59375 5.179688 -4.695312 5.421875 -4.90625 C 5.660156 -5.113281 5.78125 -5.441406 5.78125 -5.890625 Z M 7.5625 -5.90625 C 7.5625 -4.882812 7.300781 -4.160156 6.78125 -3.734375 C 6.269531 -3.316406 5.535156 -3.109375 4.578125 -3.109375 L 2.75 -3.109375 L 2.75 0 L 0.953125 0 L 0.953125 -8.640625 L 4.71875 -8.640625 C 5.582031 -8.640625 6.269531 -8.414062 6.78125 -7.96875 C 7.300781 -7.519531 7.5625 -6.832031 7.5625 -5.90625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-11">
+<path style="stroke:none;" d="M 2.21875 -2.671875 C 2.269531 -2.273438 2.378906 -1.976562 2.546875 -1.78125 C 2.835938 -1.425781 3.335938 -1.25 4.046875 -1.25 C 4.472656 -1.25 4.820312 -1.296875 5.09375 -1.390625 C 5.59375 -1.566406 5.84375 -1.898438 5.84375 -2.390625 C 5.84375 -2.671875 5.71875 -2.890625 5.46875 -3.046875 C 5.21875 -3.203125 4.828125 -3.335938 4.296875 -3.453125 L 3.375 -3.65625 C 2.476562 -3.863281 1.859375 -4.085938 1.515625 -4.328125 C 0.929688 -4.722656 0.640625 -5.34375 0.640625 -6.1875 C 0.640625 -6.96875 0.921875 -7.613281 1.484375 -8.125 C 2.046875 -8.632812 2.875 -8.890625 3.96875 -8.890625 C 4.875 -8.890625 5.644531 -8.644531 6.28125 -8.15625 C 6.925781 -7.675781 7.265625 -6.976562 7.296875 -6.0625 L 5.5625 -6.0625 C 5.53125 -6.582031 5.304688 -6.953125 4.890625 -7.171875 C 4.609375 -7.316406 4.257812 -7.390625 3.84375 -7.390625 C 3.375 -7.390625 3 -7.296875 2.71875 -7.109375 C 2.445312 -6.921875 2.3125 -6.660156 2.3125 -6.328125 C 2.3125 -6.015625 2.445312 -5.78125 2.71875 -5.625 C 2.894531 -5.53125 3.269531 -5.414062 3.84375 -5.28125 L 5.328125 -4.921875 C 5.984375 -4.765625 6.476562 -4.554688 6.8125 -4.296875 C 7.320312 -3.890625 7.578125 -3.300781 7.578125 -2.53125 C 7.578125 -1.738281 7.273438 -1.082031 6.671875 -0.5625 C 6.066406 -0.0390625 5.21875 0.21875 4.125 0.21875 C 3 0.21875 2.113281 -0.0351562 1.46875 -0.546875 C 0.820312 -1.054688 0.5 -1.765625 0.5 -2.671875 Z M 3.96875 -8.90625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-12">
+<path style="stroke:none;" d="M 4.296875 -6.546875 C 4.691406 -6.546875 5.050781 -6.476562 5.375 -6.34375 C 5.695312 -6.207031 5.960938 -6 6.171875 -5.71875 C 6.347656 -5.476562 6.453125 -5.234375 6.484375 -4.984375 C 6.523438 -4.734375 6.546875 -4.320312 6.546875 -3.75 L 6.546875 0 L 4.84375 0 L 4.84375 -3.890625 C 4.84375 -4.234375 4.785156 -4.507812 4.671875 -4.71875 C 4.515625 -5.007812 4.222656 -5.15625 3.796875 -5.15625 C 3.359375 -5.15625 3.023438 -5.007812 2.796875 -4.71875 C 2.566406 -4.425781 2.453125 -4.003906 2.453125 -3.453125 L 2.453125 0 L 0.796875 0 L 0.796875 -8.609375 L 2.453125 -8.609375 L 2.453125 -5.5625 C 2.691406 -5.925781 2.972656 -6.179688 3.296875 -6.328125 C 3.617188 -6.472656 3.953125 -6.546875 4.296875 -6.546875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-13">
+<path style="stroke:none;" d="M 5.1875 -3.1875 C 5.1875 -3.6875 5.070312 -4.125 4.84375 -4.5 C 4.613281 -4.875 4.25 -5.0625 3.75 -5.0625 C 3.144531 -5.0625 2.726562 -4.773438 2.5 -4.203125 C 2.382812 -3.898438 2.328125 -3.515625 2.328125 -3.046875 C 2.328125 -2.304688 2.523438 -1.785156 2.921875 -1.484375 C 3.148438 -1.304688 3.425781 -1.21875 3.75 -1.21875 C 4.21875 -1.21875 4.570312 -1.394531 4.8125 -1.75 C 5.0625 -2.113281 5.1875 -2.59375 5.1875 -3.1875 Z M 4.234375 -6.53125 C 4.972656 -6.53125 5.601562 -6.253906 6.125 -5.703125 C 6.644531 -5.148438 6.90625 -4.34375 6.90625 -3.28125 C 6.90625 -2.15625 6.648438 -1.296875 6.140625 -0.703125 C 5.640625 -0.109375 4.988281 0.1875 4.1875 0.1875 C 3.675781 0.1875 3.253906 0.0546875 2.921875 -0.203125 C 2.742188 -0.335938 2.566406 -0.539062 2.390625 -0.8125 L 2.390625 2.515625 L 0.734375 2.515625 L 0.734375 -6.390625 L 2.328125 -6.390625 L 2.328125 -5.4375 C 2.515625 -5.71875 2.707031 -5.9375 2.90625 -6.09375 C 3.28125 -6.382812 3.722656 -6.53125 4.234375 -6.53125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-14">
+<path style="stroke:none;" d="M 0.421875 -5.03125 L 0.421875 -6.390625 L 5.59375 -6.390625 L 5.59375 -5 L 2.359375 -1.375 L 5.703125 -1.375 L 5.703125 0 L 0.1875 0 L 0.1875 -1.296875 L 3.46875 -5.03125 Z M 3 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-15">
+<path style="stroke:none;" d="M 3.640625 -1.171875 C 4.128906 -1.171875 4.503906 -1.34375 4.765625 -1.6875 C 5.023438 -2.039062 5.15625 -2.539062 5.15625 -3.1875 C 5.15625 -3.820312 5.023438 -4.3125 4.765625 -4.65625 C 4.503906 -5.007812 4.128906 -5.1875 3.640625 -5.1875 C 3.148438 -5.1875 2.773438 -5.007812 2.515625 -4.65625 C 2.253906 -4.3125 2.125 -3.820312 2.125 -3.1875 C 2.125 -2.539062 2.253906 -2.039062 2.515625 -1.6875 C 2.773438 -1.34375 3.148438 -1.171875 3.640625 -1.171875 Z M 6.921875 -3.1875 C 6.921875 -2.25 6.648438 -1.445312 6.109375 -0.78125 C 5.566406 -0.113281 4.75 0.21875 3.65625 0.21875 C 2.550781 0.21875 1.726562 -0.113281 1.1875 -0.78125 C 0.65625 -1.445312 0.390625 -2.25 0.390625 -3.1875 C 0.390625 -4.101562 0.65625 -4.898438 1.1875 -5.578125 C 1.726562 -6.253906 2.550781 -6.59375 3.65625 -6.59375 C 4.75 -6.59375 5.566406 -6.253906 6.109375 -5.578125 C 6.648438 -4.898438 6.921875 -4.101562 6.921875 -3.1875 Z M 3.65625 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-16">
+<path style="stroke:none;" d="M 3.140625 -6.546875 C 3.523438 -6.546875 3.867188 -6.457031 4.171875 -6.28125 C 4.472656 -6.113281 4.71875 -5.878906 4.90625 -5.578125 L 4.90625 -8.625 L 6.59375 -8.625 L 6.59375 0 L 4.96875 0 L 4.96875 -0.890625 C 4.726562 -0.503906 4.457031 -0.222656 4.15625 -0.046875 C 3.851562 0.117188 3.472656 0.203125 3.015625 0.203125 C 2.273438 0.203125 1.648438 -0.0976562 1.140625 -0.703125 C 0.628906 -1.304688 0.375 -2.082031 0.375 -3.03125 C 0.375 -4.125 0.625 -4.984375 1.125 -5.609375 C 1.625 -6.234375 2.296875 -6.546875 3.140625 -6.546875 Z M 3.5 -1.203125 C 3.96875 -1.203125 4.328125 -1.378906 4.578125 -1.734375 C 4.828125 -2.085938 4.953125 -2.539062 4.953125 -3.09375 C 4.953125 -3.875 4.753906 -4.4375 4.359375 -4.78125 C 4.109375 -4.976562 3.828125 -5.078125 3.515625 -5.078125 C 3.023438 -5.078125 2.664062 -4.890625 2.4375 -4.515625 C 2.207031 -4.148438 2.09375 -3.695312 2.09375 -3.15625 C 2.09375 -2.5625 2.207031 -2.085938 2.4375 -1.734375 C 2.675781 -1.378906 3.03125 -1.203125 3.5 -1.203125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-17">
+<path style="stroke:none;" d="M 0.546875 -4.25 C 0.546875 -5.757812 0.945312 -6.921875 1.75 -7.734375 C 2.457031 -8.441406 3.351562 -8.796875 4.4375 -8.796875 C 5.882812 -8.796875 6.945312 -8.320312 7.625 -7.375 C 8 -6.832031 8.195312 -6.296875 8.21875 -5.765625 L 6.421875 -5.765625 C 6.296875 -6.171875 6.144531 -6.484375 5.96875 -6.703125 C 5.632812 -7.078125 5.144531 -7.265625 4.5 -7.265625 C 3.84375 -7.265625 3.328125 -7 2.953125 -6.46875 C 2.578125 -5.9375 2.390625 -5.1875 2.390625 -4.21875 C 2.390625 -3.25 2.585938 -2.519531 2.984375 -2.03125 C 3.390625 -1.550781 3.898438 -1.3125 4.515625 -1.3125 C 5.148438 -1.3125 5.628906 -1.519531 5.953125 -1.9375 C 6.140625 -2.164062 6.296875 -2.5 6.421875 -2.9375 L 8.203125 -2.9375 C 8.046875 -2 7.644531 -1.234375 7 -0.640625 C 6.363281 -0.0546875 5.539062 0.234375 4.53125 0.234375 C 3.289062 0.234375 2.316406 -0.160156 1.609375 -0.953125 C 0.898438 -1.753906 0.546875 -2.851562 0.546875 -4.25 Z M 4.390625 -8.90625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-18">
+<path style="stroke:none;" d="M 2.078125 -2.046875 C 2.117188 -1.742188 2.195312 -1.53125 2.3125 -1.40625 C 2.519531 -1.1875 2.898438 -1.078125 3.453125 -1.078125 C 3.785156 -1.078125 4.046875 -1.125 4.234375 -1.21875 C 4.429688 -1.3125 4.53125 -1.457031 4.53125 -1.65625 C 4.53125 -1.84375 4.453125 -1.988281 4.296875 -2.09375 C 4.140625 -2.1875 3.5625 -2.351562 2.5625 -2.59375 C 1.832031 -2.769531 1.320312 -2.992188 1.03125 -3.265625 C 0.726562 -3.523438 0.578125 -3.90625 0.578125 -4.40625 C 0.578125 -5 0.804688 -5.503906 1.265625 -5.921875 C 1.734375 -6.347656 2.390625 -6.5625 3.234375 -6.5625 C 4.023438 -6.5625 4.671875 -6.398438 5.171875 -6.078125 C 5.679688 -5.765625 5.972656 -5.21875 6.046875 -4.4375 L 4.375 -4.4375 C 4.351562 -4.65625 4.289062 -4.828125 4.1875 -4.953125 C 4.007812 -5.179688 3.695312 -5.296875 3.25 -5.296875 C 2.882812 -5.296875 2.625 -5.238281 2.46875 -5.125 C 2.320312 -5.007812 2.25 -4.875 2.25 -4.71875 C 2.25 -4.53125 2.328125 -4.394531 2.484375 -4.3125 C 2.648438 -4.21875 3.234375 -4.0625 4.234375 -3.84375 C 4.898438 -3.6875 5.394531 -3.453125 5.71875 -3.140625 C 6.050781 -2.816406 6.21875 -2.414062 6.21875 -1.9375 C 6.21875 -1.300781 5.984375 -0.78125 5.515625 -0.375 C 5.046875 0.0195312 4.316406 0.21875 3.328125 0.21875 C 2.328125 0.21875 1.585938 0.00390625 1.109375 -0.421875 C 0.628906 -0.847656 0.390625 -1.390625 0.390625 -2.046875 Z M 3.359375 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-19">
+<path style="stroke:none;" d="M 7.921875 -6.53125 C 8.203125 -6.53125 8.476562 -6.472656 8.75 -6.359375 C 9.019531 -6.253906 9.269531 -6.066406 9.5 -5.796875 C 9.675781 -5.566406 9.796875 -5.289062 9.859375 -4.96875 C 9.898438 -4.75 9.921875 -4.4375 9.921875 -4.03125 L 9.90625 0 L 8.1875 0 L 8.1875 -4.0625 C 8.1875 -4.3125 8.148438 -4.515625 8.078125 -4.671875 C 7.929688 -4.960938 7.65625 -5.109375 7.25 -5.109375 C 6.789062 -5.109375 6.472656 -4.914062 6.296875 -4.53125 C 6.210938 -4.332031 6.171875 -4.085938 6.171875 -3.796875 L 6.171875 0 L 4.484375 0 L 4.484375 -3.796875 C 4.484375 -4.179688 4.441406 -4.457031 4.359375 -4.625 C 4.222656 -4.9375 3.953125 -5.09375 3.546875 -5.09375 C 3.066406 -5.09375 2.742188 -4.9375 2.578125 -4.625 C 2.484375 -4.445312 2.4375 -4.1875 2.4375 -3.84375 L 2.4375 0 L 0.75 0 L 0.75 -6.375 L 2.375 -6.375 L 2.375 -5.4375 C 2.582031 -5.769531 2.773438 -6.007812 2.953125 -6.15625 C 3.285156 -6.40625 3.707031 -6.53125 4.21875 -6.53125 C 4.707031 -6.53125 5.101562 -6.421875 5.40625 -6.203125 C 5.644531 -6.003906 5.828125 -5.75 5.953125 -5.4375 C 6.171875 -5.8125 6.441406 -6.085938 6.765625 -6.265625 C 7.109375 -6.441406 7.492188 -6.53125 7.921875 -6.53125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-20">
+<path style="stroke:none;" d="M 2.671875 -7.140625 L 2.671875 -1.5 L 4.328125 -1.5 C 5.179688 -1.5 5.773438 -1.921875 6.109375 -2.765625 C 6.296875 -3.222656 6.390625 -3.769531 6.390625 -4.40625 C 6.390625 -5.28125 6.25 -5.953125 5.96875 -6.421875 C 5.695312 -6.898438 5.148438 -7.140625 4.328125 -7.140625 Z M 4.640625 -8.640625 C 5.171875 -8.628906 5.613281 -8.566406 5.96875 -8.453125 C 6.570312 -8.253906 7.0625 -7.890625 7.4375 -7.359375 C 7.738281 -6.921875 7.941406 -6.453125 8.046875 -5.953125 C 8.160156 -5.453125 8.21875 -4.976562 8.21875 -4.53125 C 8.21875 -3.382812 7.988281 -2.410156 7.53125 -1.609375 C 6.90625 -0.535156 5.941406 0 4.640625 0 L 0.921875 0 L 0.921875 -8.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-21">
+<path style="stroke:none;" d="M 3.140625 -8.71875 C 3.242188 -8.71875 3.335938 -8.710938 3.421875 -8.703125 C 3.503906 -8.703125 3.625 -8.695312 3.78125 -8.6875 L 3.78125 -7.328125 C 3.6875 -7.335938 3.523438 -7.34375 3.296875 -7.34375 C 3.078125 -7.351562 2.925781 -7.304688 2.84375 -7.203125 C 2.757812 -7.109375 2.71875 -7 2.71875 -6.875 C 2.71875 -6.75 2.71875 -6.566406 2.71875 -6.328125 L 3.8125 -6.328125 L 3.8125 -5.15625 L 2.71875 -5.15625 L 2.71875 0 L 1.0625 0 L 1.0625 -5.15625 L 0.125 -5.15625 L 0.125 -6.328125 L 1.03125 -6.328125 L 1.03125 -6.734375 C 1.03125 -7.421875 1.148438 -7.894531 1.390625 -8.15625 C 1.628906 -8.53125 2.210938 -8.71875 3.140625 -8.71875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-22">
+<path style="stroke:none;" d="M 4.59375 -4.09375 C 4.5625 -4.332031 4.484375 -4.546875 4.359375 -4.734375 C 4.171875 -4.992188 3.878906 -5.125 3.484375 -5.125 C 2.921875 -5.125 2.535156 -4.847656 2.328125 -4.296875 C 2.210938 -3.992188 2.15625 -3.597656 2.15625 -3.109375 C 2.15625 -2.640625 2.210938 -2.257812 2.328125 -1.96875 C 2.523438 -1.4375 2.898438 -1.171875 3.453125 -1.171875 C 3.835938 -1.171875 4.113281 -1.273438 4.28125 -1.484375 C 4.445312 -1.703125 4.546875 -1.976562 4.578125 -2.3125 L 6.28125 -2.3125 C 6.25 -1.800781 6.066406 -1.320312 5.734375 -0.875 C 5.210938 -0.144531 4.4375 0.21875 3.40625 0.21875 C 2.382812 0.21875 1.628906 -0.0820312 1.140625 -0.6875 C 0.660156 -1.300781 0.421875 -2.09375 0.421875 -3.0625 C 0.421875 -4.164062 0.6875 -5.019531 1.21875 -5.625 C 1.75 -6.238281 2.488281 -6.546875 3.4375 -6.546875 C 4.238281 -6.546875 4.894531 -6.363281 5.40625 -6 C 5.914062 -5.644531 6.21875 -5.007812 6.3125 -4.09375 Z M 3.46875 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-23">
+<path style="stroke:none;" d="M 2.71875 -7.140625 L 2.71875 -4.8125 L 4.765625 -4.8125 C 5.171875 -4.8125 5.472656 -4.859375 5.671875 -4.953125 C 6.035156 -5.117188 6.21875 -5.445312 6.21875 -5.9375 C 6.21875 -6.457031 6.046875 -6.804688 5.703125 -6.984375 C 5.503906 -7.085938 5.207031 -7.140625 4.8125 -7.140625 Z M 5.1875 -8.640625 C 5.789062 -8.628906 6.253906 -8.550781 6.578125 -8.40625 C 6.910156 -8.269531 7.191406 -8.070312 7.421875 -7.8125 C 7.609375 -7.59375 7.753906 -7.347656 7.859375 -7.078125 C 7.972656 -6.816406 8.03125 -6.515625 8.03125 -6.171875 C 8.03125 -5.765625 7.925781 -5.363281 7.71875 -4.96875 C 7.507812 -4.570312 7.164062 -4.289062 6.6875 -4.125 C 7.09375 -3.96875 7.375 -3.738281 7.53125 -3.4375 C 7.695312 -3.144531 7.78125 -2.695312 7.78125 -2.09375 L 7.78125 -1.515625 C 7.78125 -1.117188 7.796875 -0.847656 7.828125 -0.703125 C 7.878906 -0.484375 7.988281 -0.320312 8.15625 -0.21875 L 8.15625 0 L 6.171875 0 C 6.117188 -0.1875 6.082031 -0.34375 6.0625 -0.46875 C 6.007812 -0.707031 5.984375 -0.953125 5.984375 -1.203125 L 5.96875 -2.015625 C 5.957031 -2.566406 5.851562 -2.929688 5.65625 -3.109375 C 5.46875 -3.296875 5.109375 -3.390625 4.578125 -3.390625 L 2.71875 -3.390625 L 2.71875 0 L 0.953125 0 L 0.953125 -8.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-24">
+<path style="stroke:none;" d="M 0.125 -5.140625 L 0.125 -6.328125 L 1.015625 -6.328125 L 1.015625 -8.109375 L 2.671875 -8.109375 L 2.671875 -6.328125 L 3.703125 -6.328125 L 3.703125 -5.140625 L 2.671875 -5.140625 L 2.671875 -1.765625 C 2.671875 -1.503906 2.703125 -1.335938 2.765625 -1.265625 C 2.828125 -1.203125 3.03125 -1.171875 3.375 -1.171875 C 3.425781 -1.171875 3.476562 -1.171875 3.53125 -1.171875 C 3.59375 -1.179688 3.648438 -1.1875 3.703125 -1.1875 L 3.703125 0.0625 L 2.90625 0.09375 C 2.125 0.113281 1.585938 -0.0234375 1.296875 -0.328125 C 1.109375 -0.515625 1.015625 -0.804688 1.015625 -1.203125 L 1.015625 -5.140625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-25">
+<path style="stroke:none;" d="M 6.71875 -5.9375 C 6.582031 -6.53125 6.25 -6.941406 5.71875 -7.171875 C 5.425781 -7.304688 5.097656 -7.375 4.734375 -7.375 C 4.035156 -7.375 3.460938 -7.109375 3.015625 -6.578125 C 2.566406 -6.054688 2.34375 -5.269531 2.34375 -4.21875 C 2.34375 -3.15625 2.582031 -2.398438 3.0625 -1.953125 C 3.550781 -1.515625 4.101562 -1.296875 4.71875 -1.296875 C 5.320312 -1.296875 5.816406 -1.46875 6.203125 -1.8125 C 6.597656 -2.164062 6.835938 -2.625 6.921875 -3.1875 L 4.921875 -3.1875 L 4.921875 -4.640625 L 8.53125 -4.640625 L 8.53125 0 L 7.328125 0 L 7.15625 -1.078125 C 6.800781 -0.671875 6.488281 -0.382812 6.21875 -0.21875 C 5.738281 0.0820312 5.148438 0.234375 4.453125 0.234375 C 3.304688 0.234375 2.367188 -0.164062 1.640625 -0.96875 C 0.878906 -1.757812 0.5 -2.847656 0.5 -4.234375 C 0.5 -5.628906 0.882812 -6.75 1.65625 -7.59375 C 2.425781 -8.4375 3.441406 -8.859375 4.703125 -8.859375 C 5.804688 -8.859375 6.6875 -8.578125 7.34375 -8.015625 C 8.007812 -7.460938 8.394531 -6.769531 8.5 -5.9375 Z M 4.703125 -8.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-26">
+<path style="stroke:none;" d="M 2.4375 -6.390625 L 2.4375 -2.53125 C 2.4375 -2.175781 2.484375 -1.90625 2.578125 -1.71875 C 2.722656 -1.394531 3.019531 -1.234375 3.46875 -1.234375 C 4.039062 -1.234375 4.429688 -1.460938 4.640625 -1.921875 C 4.753906 -2.171875 4.8125 -2.5 4.8125 -2.90625 L 4.8125 -6.390625 L 6.5 -6.390625 L 6.5 0 L 4.875 0 L 4.875 -0.90625 C 4.863281 -0.882812 4.828125 -0.820312 4.765625 -0.71875 C 4.703125 -0.625 4.625 -0.539062 4.53125 -0.46875 C 4.269531 -0.238281 4.015625 -0.0820312 3.765625 0 C 3.523438 0.09375 3.242188 0.140625 2.921875 0.140625 C 1.972656 0.140625 1.335938 -0.195312 1.015625 -0.875 C 0.828125 -1.25 0.734375 -1.800781 0.734375 -2.53125 L 0.734375 -6.390625 Z M 3.609375 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-27">
+<path style="stroke:none;" d="M 0.765625 -8.609375 L 2.40625 -8.609375 L 2.40625 -3.953125 L 4.484375 -6.359375 L 6.546875 -6.359375 L 4.3125 -3.921875 L 6.640625 0 L 4.625 0 L 3.09375 -2.734375 L 2.40625 -2.015625 L 2.40625 0 L 0.765625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-28">
+<path style="stroke:none;" d="M 1.03125 1.21875 L 1.25 1.234375 C 1.414062 1.242188 1.570312 1.238281 1.71875 1.21875 C 1.863281 1.195312 1.988281 1.148438 2.09375 1.078125 C 2.1875 1.015625 2.273438 0.878906 2.359375 0.671875 C 2.441406 0.460938 2.476562 0.332031 2.46875 0.28125 L 0.125 -6.390625 L 1.984375 -6.390625 L 3.375 -1.671875 L 4.6875 -6.390625 L 6.46875 -6.390625 L 4.28125 -0.109375 C 3.851562 1.109375 3.515625 1.859375 3.265625 2.140625 C 3.023438 2.429688 2.535156 2.578125 1.796875 2.578125 C 1.648438 2.578125 1.53125 2.578125 1.4375 2.578125 C 1.351562 2.578125 1.21875 2.570312 1.03125 2.5625 Z M 3.296875 -6.5625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-29">
+<path style="stroke:none;" d="M 4.71875 -6.390625 L 6.515625 -6.390625 L 4.203125 0 L 2.4375 0 L 0.15625 -6.390625 L 2.03125 -6.390625 L 3.359375 -1.671875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-30">
+<path style="stroke:none;" d="M 0.3125 -1.53125 L 4.765625 -7.109375 L 0.421875 -7.109375 L 0.421875 -8.640625 L 7.015625 -8.640625 L 7.015625 -7.1875 L 2.5 -1.53125 L 7.03125 -1.53125 L 7.03125 0 L 0.3125 0 Z M 3.71875 -8.640625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-31">
+<path style="stroke:none;" d="M 0.921875 -8.625 L 7.03125 -8.625 L 7.03125 -7.109375 L 2.703125 -7.109375 L 2.703125 -5.125 L 6.5 -5.125 L 6.5 -3.625 L 2.703125 -3.625 L 2.703125 0 L 0.921875 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph5-32">
+<path style="stroke:none;" d="M 0.921875 -8.640625 L 2.71875 -8.640625 L 2.71875 -1.546875 L 7 -1.546875 L 7 0 L 0.921875 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph6-0">
+<path style="stroke:none;" d="M 0.90625 0 L 0.90625 -20.328125 L 17.046875 -20.328125 L 17.046875 0 Z M 14.5 -2.546875 L 14.5 -17.78125 L 3.453125 -17.78125 L 3.453125 -2.546875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph6-1">
+<path style="stroke:none;" d="M 2.453125 -17.078125 C 2.484375 -18.109375 2.660156 -18.863281 2.984375 -19.34375 C 3.566406 -20.195312 4.691406 -20.625 6.359375 -20.625 C 6.515625 -20.625 6.675781 -20.617188 6.84375 -20.609375 C 7.007812 -20.597656 7.195312 -20.582031 7.40625 -20.5625 L 7.40625 -18.296875 C 7.144531 -18.316406 6.957031 -18.328125 6.84375 -18.328125 C 6.726562 -18.335938 6.617188 -18.34375 6.515625 -18.34375 C 5.765625 -18.34375 5.3125 -18.144531 5.15625 -17.75 C 5.007812 -17.351562 4.9375 -16.351562 4.9375 -14.75 L 7.40625 -14.75 L 7.40625 -12.78125 L 4.90625 -12.78125 L 4.90625 0 L 2.453125 0 L 2.453125 -12.78125 L 0.390625 -12.78125 L 0.390625 -14.75 L 2.453125 -14.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph6-2">
+<path style="stroke:none;" d="M 0.421875 -14.828125 L 3.640625 -14.828125 L 7.046875 -9.609375 L 10.484375 -14.828125 L 13.515625 -14.75 L 8.53125 -7.59375 L 13.75 0 L 10.5625 0 L 6.875 -5.5625 L 3.3125 0 L 0.15625 0 L 5.375 -7.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph6-3">
+<path style="stroke:none;" d="M 1.765625 -20.328125 L 4.171875 -20.328125 L 4.171875 -8.53125 L 10.5625 -14.828125 L 13.75 -14.828125 L 8.0625 -9.265625 L 14.0625 0 L 10.875 0 L 6.25 -7.46875 L 4.171875 -5.5625 L 4.171875 0 L 1.765625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph7-0">
+<path style="stroke:none;" d="M 1.40625 5.015625 L 1.40625 -19.984375 L 15.578125 -19.984375 L 15.578125 5.015625 Z M 3 3.4375 L 14 3.4375 L 14 -18.390625 L 3 -18.390625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph7-1">
+<path style="stroke:none;" d="M 5.671875 -11.328125 C 5.671875 -10.878906 5.5 -10.492188 5.15625 -10.171875 C 4.820312 -9.847656 4.414062 -9.6875 3.9375 -9.6875 C 3.457031 -9.6875 3.050781 -9.847656 2.71875 -10.171875 C 2.382812 -10.492188 2.21875 -10.878906 2.21875 -11.328125 C 2.21875 -11.796875 2.382812 -12.1875 2.71875 -12.5 C 3.050781 -12.820312 3.457031 -12.984375 3.9375 -12.984375 C 4.414062 -12.984375 4.820312 -12.820312 5.15625 -12.5 C 5.5 -12.1875 5.671875 -11.796875 5.671875 -11.328125 Z M 5.671875 -1.328125 C 5.671875 -0.878906 5.5 -0.492188 5.15625 -0.171875 C 4.820312 0.148438 4.414062 0.3125 3.9375 0.3125 C 3.457031 0.3125 3.050781 0.148438 2.71875 -0.171875 C 2.382812 -0.492188 2.21875 -0.878906 2.21875 -1.328125 C 2.21875 -1.785156 2.382812 -2.175781 2.71875 -2.5 C 3.050781 -2.832031 3.457031 -3 3.9375 -3 C 4.414062 -3 4.820312 -2.832031 5.15625 -2.5 C 5.5 -2.175781 5.671875 -1.785156 5.671875 -1.328125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph7-2">
+<path style="stroke:none;" d="M 23.265625 -9.390625 L 17.46875 -11.734375 L 18.09375 -13.171875 L 26.390625 -9.65625 L 26.390625 -7.515625 L 18.09375 -4 L 17.46875 -5.4375 L 23.265625 -7.796875 L 1.59375 -7.796875 L 1.59375 -9.390625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph7-3">
+<path style="stroke:none;" d="M 14.359375 -3.859375 L 1.21875 -3.859375 L 1.21875 -5.78125 L 14.359375 -5.78125 Z M 14.359375 -7.59375 L 1.21875 -7.59375 L 1.21875 -9.515625 L 14.359375 -9.515625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph8-0">
+<path style="stroke:none;" d="M 1.765625 6.265625 L 1.765625 -24.984375 L 19.484375 -24.984375 L 19.484375 6.265625 Z M 3.75 4.296875 L 17.515625 4.296875 L 17.515625 -23 L 3.75 -23 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph8-1">
+<path style="stroke:none;" d="M 10.140625 -24.921875 C 8.191406 -23.140625 6.796875 -21.078125 5.953125 -18.734375 C 5.117188 -16.398438 4.703125 -13.265625 4.703125 -9.328125 C 4.703125 -5.378906 5.117188 -2.242188 5.953125 0.078125 C 6.796875 2.410156 8.191406 4.460938 10.140625 6.234375 L 9.4375 6.96875 C 6.988281 5.1875 5.070312 2.859375 3.6875 -0.015625 C 2.3125 -2.898438 1.625 -6.003906 1.625 -9.328125 C 1.625 -12.648438 2.316406 -15.753906 3.703125 -18.640625 C 5.085938 -21.535156 7 -23.875 9.4375 -25.65625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph8-2">
+<path style="stroke:none;" d="M 1.65625 -24.921875 L 2.34375 -25.65625 C 4.78125 -23.875 6.691406 -21.535156 8.078125 -18.640625 C 9.472656 -15.742188 10.171875 -12.640625 10.171875 -9.328125 C 10.171875 -6.015625 9.472656 -2.914062 8.078125 -0.03125 C 6.691406 2.851562 4.78125 5.1875 2.34375 6.96875 L 1.65625 6.234375 C 3.625 4.472656 5.019531 2.429688 5.84375 0.109375 C 6.675781 -2.210938 7.09375 -5.359375 7.09375 -9.328125 C 7.09375 -13.296875 6.675781 -16.441406 5.84375 -18.765625 C 5.019531 -21.097656 3.625 -23.148438 1.65625 -24.921875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph9-0">
+<path style="stroke:none;" d="M 0.640625 -0.640625 L -13.734375 -15.015625 L -2.328125 -26.421875 L 12.046875 -12.046875 Z M 8.453125 -12.046875 L -2.328125 -22.828125 L -10.140625 -15.015625 L 0.640625 -4.234375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph9-1">
+<path style="stroke:none;" d="M -10.34375 -13.8125 C -11.050781 -14.5625 -11.457031 -15.21875 -11.5625 -15.78125 C -11.75 -16.800781 -11.253906 -17.898438 -10.078125 -19.078125 C -9.972656 -19.179688 -9.859375 -19.289062 -9.734375 -19.40625 C -9.609375 -19.519531 -9.46875 -19.644531 -9.3125 -19.78125 L -7.703125 -18.171875 C -7.898438 -17.992188 -8.039062 -17.867188 -8.125 -17.796875 C -8.207031 -17.722656 -8.285156 -17.648438 -8.359375 -17.578125 C -8.890625 -17.046875 -9.066406 -16.582031 -8.890625 -16.1875 C -8.722656 -15.800781 -8.070312 -15.039062 -6.9375 -13.90625 L -5.1875 -15.65625 L -3.796875 -14.265625 L -5.5625 -12.5 L 3.46875 -3.46875 L 1.734375 -1.734375 L -7.296875 -10.765625 L -8.75 -9.3125 L -10.140625 -10.703125 L -8.6875 -12.15625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph9-2">
+<path style="stroke:none;" d="M -10.1875 -10.78125 L -7.90625 -13.0625 L -1.8125 -11.78125 L -3.078125 -17.890625 L -0.859375 -19.984375 L 0.65625 -11.40625 L 9.71875 -9.71875 L 7.46875 -7.46875 L 0.921875 -8.796875 L 2.34375 -2.34375 L 0.109375 -0.109375 L -1.578125 -9.171875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph9-3">
+<path style="stroke:none;" d="M -5.4375 -16.125 C -4.257812 -17.300781 -3.015625 -17.972656 -1.703125 -18.140625 C -0.390625 -18.304688 1.039062 -17.757812 2.59375 -16.5 L 0.875 -14.78125 C 0.125 -15.320312 -0.644531 -15.617188 -1.4375 -15.671875 C -2.238281 -15.734375 -3.046875 -15.359375 -3.859375 -14.546875 C -4.992188 -13.410156 -5.253906 -12.054688 -4.640625 -10.484375 C -4.242188 -9.460938 -3.519531 -8.425781 -2.46875 -7.375 C -1.425781 -6.332031 -0.320312 -5.675781 0.84375 -5.40625 C 2.007812 -5.132812 3.066406 -5.472656 4.015625 -6.421875 C 4.742188 -7.148438 5.097656 -7.953125 5.078125 -8.828125 C 5.054688 -9.703125 4.734375 -10.609375 4.109375 -11.546875 L 5.828125 -13.265625 C 7.035156 -11.679688 7.566406 -10.175781 7.421875 -8.75 C 7.273438 -7.320312 6.59375 -6 5.375 -4.78125 C 4.007812 -3.414062 2.414062 -2.820312 0.59375 -3 C -1.21875 -3.1875 -2.875 -4.03125 -4.375 -5.53125 C -6.21875 -7.375 -7.203125 -9.253906 -7.328125 -11.171875 C -7.453125 -13.085938 -6.820312 -14.738281 -5.4375 -16.125 Z M -5.671875 -15.796875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph9-4">
+<path style="stroke:none;" d="M -8.328125 -12.640625 L 3.015625 -6.890625 L -2.609375 -18.359375 L -0.671875 -20.296875 L 5.859375 -5.859375 L 3.984375 -3.984375 L -10.375 -10.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph9-5">
+<path style="stroke:none;" d="M -13.125 -15.625 L -11.421875 -17.328125 L -3.078125 -8.984375 L -3.015625 -17.953125 L -0.765625 -20.203125 L -0.84375 -12.25 L 9.9375 -9.9375 L 7.6875 -7.6875 L -0.859375 -9.703125 L -0.984375 -6.890625 L 2.953125 -2.953125 L 1.25 -1.25 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph10-0">
+<path style="stroke:none;" d="M 5.6875 3.1875 L -16.421875 -18.921875 L -3.890625 -31.453125 L 18.21875 -9.34375 Z M 5.6875 0.375 L 15.421875 -9.359375 L -3.875 -28.65625 L -13.609375 -18.921875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph10-1">
+<path style="stroke:none;" d="M -10.453125 -24.796875 C -10.566406 -22.160156 -10.09375 -19.71875 -9.03125 -17.46875 C -7.96875 -15.21875 -6.046875 -12.703125 -3.265625 -9.921875 C -0.472656 -7.128906 2.039062 -5.207031 4.28125 -4.15625 C 6.519531 -3.101562 8.953125 -2.640625 11.578125 -2.765625 L 11.59375 -1.75 C 8.601562 -1.28125 5.601562 -1.578125 2.59375 -2.640625 C -0.414062 -3.703125 -3.09375 -5.40625 -5.4375 -7.75 C -7.789062 -10.101562 -9.5 -12.789062 -10.5625 -15.8125 C -11.625 -18.832031 -11.925781 -21.832031 -11.46875 -24.8125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph10-2">
+<path style="stroke:none;" d="M -16.453125 -18.796875 L -16.484375 -19.796875 C -13.492188 -20.265625 -10.484375 -19.960938 -7.453125 -18.890625 C -4.429688 -17.828125 -1.75 -16.125 0.59375 -13.78125 C 2.9375 -11.4375 4.632812 -8.753906 5.6875 -5.734375 C 6.75 -2.722656 7.046875 0.273438 6.578125 3.265625 L 5.578125 3.234375 C 5.734375 0.597656 5.28125 -1.832031 4.21875 -4.0625 C 3.15625 -6.289062 1.222656 -8.804688 -1.578125 -11.609375 C -4.390625 -14.421875 -6.910156 -16.359375 -9.140625 -17.421875 C -11.367188 -18.484375 -13.804688 -18.941406 -16.453125 -18.796875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph10-3">
+<path style="stroke:none;" d="M -0.625 -31.59375 L 2.984375 -28.734375 L 1.890625 -27.640625 C -0.398438 -28.867188 -2.3125 -29.359375 -3.84375 -29.109375 C -5.382812 -28.867188 -7.125 -27.78125 -9.0625 -25.84375 L -12.359375 -22.546875 L 6.3125 -19.65625 L 7.5625 -1.15625 L 12.234375 -5.828125 C 14.265625 -7.859375 15.441406 -9.554688 15.765625 -10.921875 C 16.085938 -12.285156 15.816406 -13.960938 14.953125 -15.953125 L 16.0625 -17.0625 L 18.5625 -13.0625 L 18.6875 -12.8125 C 19.957031 -10.789062 19.859375 -9.046875 18.390625 -7.578125 L 6.3125 4.5 L 4.875 -16.40625 L -17.40625 -19.90625 L -5.890625 -31.421875 C -4.785156 -32.523438 -3.96875 -33.09375 -3.4375 -33.125 C -2.914062 -33.164062 -1.976562 -32.65625 -0.625 -31.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph11-0">
+<path style="stroke:none;" d="M 4.546875 2.546875 L -13.125 -15.125 L -3.109375 -25.140625 L 14.5625 -7.46875 Z M 4.5625 0.3125 L 12.34375 -7.46875 L -3.09375 -22.90625 L -10.875 -15.125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph11-1">
+<path style="stroke:none;" d="M 7.421875 -12.890625 L -1.875 -3.59375 L -3.234375 -4.953125 L 6.0625 -14.25 Z M 4.78125 -15.53125 L -4.515625 -6.234375 L -5.875 -7.59375 L 3.421875 -16.890625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph11-2">
+<path style="stroke:none;" d="M 0.796875 -11.609375 L 4.734375 -15.546875 L 6.078125 -14.203125 L 2.140625 -10.265625 L 6.203125 -6.203125 L 4.84375 -4.84375 L 0.78125 -8.90625 L -3.171875 -4.953125 L -4.515625 -6.296875 L -0.5625 -10.25 L -4.625 -14.3125 L -3.265625 -15.671875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph12-0">
+<path style="stroke:none;" d="M 0.453125 -0.453125 L -9.609375 -10.515625 L -1.625 -18.5 L 8.4375 -8.4375 Z M 5.921875 -8.453125 L -1.625 -16 L -7.09375 -10.53125 L 0.453125 -2.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph12-1">
+<path style="stroke:none;" d="M -6.390625 -8.203125 L -5.140625 -9.453125 L 2.15625 -2.15625 L 0.90625 -0.90625 Z M -9.15625 -10.96875 L -7.90625 -12.21875 L -6.5 -10.8125 L -7.75 -9.5625 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 223 14.398438 L 223 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 223.933594 152 L 223.933594 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 223.933594 115 L 223.933594 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 223.933594 77 L 223.933594 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 223.933594 40 L 223.933594 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 80 14.398438 L 82 14.398438 L 82 180 L 80 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 119 14.398438 L 120 14.398438 L 120 180 L 119 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 157 14.398438 L 158 14.398438 L 158 180 L 157 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 195 14.398438 L 197 14.398438 L 197 180 L 195 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 223.933594 171 L 223.933594 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 223.933594 133 L 223.933594 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 223.933594 96 L 223.933594 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 223.933594 58 L 223.933594 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 223.933594 21 L 223.933594 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 61 14.398438 L 63 14.398438 L 63 180 L 61 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 99 14.398438 L 101 14.398438 L 101 180 L 99 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 137 14.398438 L 140 14.398438 L 140 180 L 137 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 176 14.398438 L 178 14.398438 L 178 180 L 176 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 214 14.398438 L 216 14.398438 L 216 180 L 214 180 Z "/>
+</clipPath>
+<clipPath id="clip20">
+ <path d="M 237.332031 0 L 475 0 L 475 216 L 237.332031 216 Z "/>
+</clipPath>
+<clipPath id="clip21">
+ <path d="M 237.332031 0 L 475.664062 0 L 475.664062 217 L 237.332031 217 Z "/>
+</clipPath>
+<clipPath id="clip22">
+ <path d="M 291.351562 14.398438 L 461 14.398438 L 461 180 L 291.351562 180 Z "/>
+</clipPath>
+<clipPath id="clip23">
+ <path d="M 291.351562 154 L 461 154 L 461 156 L 291.351562 156 Z "/>
+</clipPath>
+<clipPath id="clip24">
+ <path d="M 291.351562 116 L 461 116 L 461 118 L 291.351562 118 Z "/>
+</clipPath>
+<clipPath id="clip25">
+ <path d="M 291.351562 78 L 461 78 L 461 80 L 291.351562 80 Z "/>
+</clipPath>
+<clipPath id="clip26">
+ <path d="M 291.351562 40 L 461 40 L 461 42 L 291.351562 42 Z "/>
+</clipPath>
+<clipPath id="clip27">
+ <path d="M 317 14.398438 L 319 14.398438 L 319 180 L 317 180 Z "/>
+</clipPath>
+<clipPath id="clip28">
+ <path d="M 356 14.398438 L 357 14.398438 L 357 180 L 356 180 Z "/>
+</clipPath>
+<clipPath id="clip29">
+ <path d="M 394 14.398438 L 396 14.398438 L 396 180 L 394 180 Z "/>
+</clipPath>
+<clipPath id="clip30">
+ <path d="M 433 14.398438 L 434 14.398438 L 434 180 L 433 180 Z "/>
+</clipPath>
+<clipPath id="clip31">
+ <path d="M 291.351562 173 L 461 173 L 461 175 L 291.351562 175 Z "/>
+</clipPath>
+<clipPath id="clip32">
+ <path d="M 291.351562 135 L 461 135 L 461 137 L 291.351562 137 Z "/>
+</clipPath>
+<clipPath id="clip33">
+ <path d="M 291.351562 97 L 461 97 L 461 99 L 291.351562 99 Z "/>
+</clipPath>
+<clipPath id="clip34">
+ <path d="M 291.351562 59 L 461 59 L 461 61 L 291.351562 61 Z "/>
+</clipPath>
+<clipPath id="clip35">
+ <path d="M 291.351562 21 L 461 21 L 461 23 L 291.351562 23 Z "/>
+</clipPath>
+<clipPath id="clip36">
+ <path d="M 298 14.398438 L 300 14.398438 L 300 180 L 298 180 Z "/>
+</clipPath>
+<clipPath id="clip37">
+ <path d="M 336 14.398438 L 338 14.398438 L 338 180 L 336 180 Z "/>
+</clipPath>
+<clipPath id="clip38">
+ <path d="M 375 14.398438 L 377 14.398438 L 377 180 L 375 180 Z "/>
+</clipPath>
+<clipPath id="clip39">
+ <path d="M 413 14.398438 L 415 14.398438 L 415 180 L 413 180 Z "/>
+</clipPath>
+<clipPath id="clip40">
+ <path d="M 452 14.398438 L 454 14.398438 L 454 180 L 452 180 Z "/>
+</clipPath>
+<clipPath id="clip41">
+ <path d="M 474.667969 0 L 712 0 L 712 216 L 474.667969 216 Z "/>
+</clipPath>
+<clipPath id="clip42">
+ <path d="M 474.667969 0 L 712 0 L 712 217 L 474.667969 217 Z "/>
+</clipPath>
+<clipPath id="clip43">
+ <path d="M 528.683594 14.398438 L 698 14.398438 L 698 180 L 528.683594 180 Z "/>
+</clipPath>
+<clipPath id="clip44">
+ <path d="M 528.683594 152 L 698 152 L 698 154 L 528.683594 154 Z "/>
+</clipPath>
+<clipPath id="clip45">
+ <path d="M 528.683594 115 L 698 115 L 698 116 L 528.683594 116 Z "/>
+</clipPath>
+<clipPath id="clip46">
+ <path d="M 528.683594 77 L 698 77 L 698 79 L 528.683594 79 Z "/>
+</clipPath>
+<clipPath id="clip47">
+ <path d="M 528.683594 40 L 698 40 L 698 41 L 528.683594 41 Z "/>
+</clipPath>
+<clipPath id="clip48">
+ <path d="M 555 14.398438 L 556 14.398438 L 556 180 L 555 180 Z "/>
+</clipPath>
+<clipPath id="clip49">
+ <path d="M 593 14.398438 L 595 14.398438 L 595 180 L 593 180 Z "/>
+</clipPath>
+<clipPath id="clip50">
+ <path d="M 632 14.398438 L 633 14.398438 L 633 180 L 632 180 Z "/>
+</clipPath>
+<clipPath id="clip51">
+ <path d="M 670 14.398438 L 671 14.398438 L 671 180 L 670 180 Z "/>
+</clipPath>
+<clipPath id="clip52">
+ <path d="M 528.683594 171 L 698.597656 171 L 698.597656 173 L 528.683594 173 Z "/>
+</clipPath>
+<clipPath id="clip53">
+ <path d="M 528.683594 133 L 698.597656 133 L 698.597656 135 L 528.683594 135 Z "/>
+</clipPath>
+<clipPath id="clip54">
+ <path d="M 528.683594 96 L 698.597656 96 L 698.597656 98 L 528.683594 98 Z "/>
+</clipPath>
+<clipPath id="clip55">
+ <path d="M 528.683594 58 L 698.597656 58 L 698.597656 60 L 528.683594 60 Z "/>
+</clipPath>
+<clipPath id="clip56">
+ <path d="M 528.683594 21 L 698.597656 21 L 698.597656 23 L 528.683594 23 Z "/>
+</clipPath>
+<clipPath id="clip57">
+ <path d="M 535 14.398438 L 537 14.398438 L 537 180 L 535 180 Z "/>
+</clipPath>
+<clipPath id="clip58">
+ <path d="M 574 14.398438 L 576 14.398438 L 576 180 L 574 180 Z "/>
+</clipPath>
+<clipPath id="clip59">
+ <path d="M 612 14.398438 L 614 14.398438 L 614 180 L 612 180 Z "/>
+</clipPath>
+<clipPath id="clip60">
+ <path d="M 651 14.398438 L 653 14.398438 L 653 180 L 651 180 Z "/>
+</clipPath>
+<clipPath id="clip61">
+ <path d="M 689 14.398438 L 691 14.398438 L 691 180 L 689 180 Z "/>
+</clipPath>
+<clipPath id="clip62">
+ <path d="M 0 216 L 238 216 L 238 433 L 0 433 Z "/>
+</clipPath>
+<clipPath id="clip63">
+ <path d="M 54.019531 230.398438 L 223 230.398438 L 223 396 L 54.019531 396 Z "/>
+</clipPath>
+<clipPath id="clip64">
+ <path d="M 54.019531 368 L 223.933594 368 L 223.933594 370 L 54.019531 370 Z "/>
+</clipPath>
+<clipPath id="clip65">
+ <path d="M 54.019531 331 L 223.933594 331 L 223.933594 332 L 54.019531 332 Z "/>
+</clipPath>
+<clipPath id="clip66">
+ <path d="M 54.019531 293 L 223.933594 293 L 223.933594 295 L 54.019531 295 Z "/>
+</clipPath>
+<clipPath id="clip67">
+ <path d="M 54.019531 256 L 223.933594 256 L 223.933594 257 L 54.019531 257 Z "/>
+</clipPath>
+<clipPath id="clip68">
+ <path d="M 80 230.398438 L 82 230.398438 L 82 396 L 80 396 Z "/>
+</clipPath>
+<clipPath id="clip69">
+ <path d="M 119 230.398438 L 120 230.398438 L 120 396 L 119 396 Z "/>
+</clipPath>
+<clipPath id="clip70">
+ <path d="M 157 230.398438 L 158 230.398438 L 158 396 L 157 396 Z "/>
+</clipPath>
+<clipPath id="clip71">
+ <path d="M 195 230.398438 L 197 230.398438 L 197 396 L 195 396 Z "/>
+</clipPath>
+<clipPath id="clip72">
+ <path d="M 54.019531 387 L 223.933594 387 L 223.933594 389 L 54.019531 389 Z "/>
+</clipPath>
+<clipPath id="clip73">
+ <path d="M 54.019531 349 L 223.933594 349 L 223.933594 351 L 54.019531 351 Z "/>
+</clipPath>
+<clipPath id="clip74">
+ <path d="M 54.019531 312 L 223.933594 312 L 223.933594 314 L 54.019531 314 Z "/>
+</clipPath>
+<clipPath id="clip75">
+ <path d="M 54.019531 274 L 223.933594 274 L 223.933594 276 L 54.019531 276 Z "/>
+</clipPath>
+<clipPath id="clip76">
+ <path d="M 54.019531 237 L 223.933594 237 L 223.933594 239 L 54.019531 239 Z "/>
+</clipPath>
+<clipPath id="clip77">
+ <path d="M 61 230.398438 L 63 230.398438 L 63 396 L 61 396 Z "/>
+</clipPath>
+<clipPath id="clip78">
+ <path d="M 99 230.398438 L 101 230.398438 L 101 396 L 99 396 Z "/>
+</clipPath>
+<clipPath id="clip79">
+ <path d="M 137 230.398438 L 140 230.398438 L 140 396 L 137 396 Z "/>
+</clipPath>
+<clipPath id="clip80">
+ <path d="M 176 230.398438 L 178 230.398438 L 178 396 L 176 396 Z "/>
+</clipPath>
+<clipPath id="clip81">
+ <path d="M 214 230.398438 L 216 230.398438 L 216 396 L 214 396 Z "/>
+</clipPath>
+<clipPath id="clip82">
+ <path d="M 237.332031 216 L 475 216 L 475 432 L 237.332031 432 Z "/>
+</clipPath>
+<clipPath id="clip83">
+ <path d="M 237.332031 216 L 475.664062 216 L 475.664062 433 L 237.332031 433 Z "/>
+</clipPath>
+<clipPath id="clip84">
+ <path d="M 291.351562 230.398438 L 461 230.398438 L 461 396 L 291.351562 396 Z "/>
+</clipPath>
+<clipPath id="clip85">
+ <path d="M 291.351562 368 L 461 368 L 461 370 L 291.351562 370 Z "/>
+</clipPath>
+<clipPath id="clip86">
+ <path d="M 291.351562 331 L 461 331 L 461 332 L 291.351562 332 Z "/>
+</clipPath>
+<clipPath id="clip87">
+ <path d="M 291.351562 293 L 461 293 L 461 295 L 291.351562 295 Z "/>
+</clipPath>
+<clipPath id="clip88">
+ <path d="M 291.351562 256 L 461 256 L 461 257 L 291.351562 257 Z "/>
+</clipPath>
+<clipPath id="clip89">
+ <path d="M 317 230.398438 L 319 230.398438 L 319 396 L 317 396 Z "/>
+</clipPath>
+<clipPath id="clip90">
+ <path d="M 356 230.398438 L 357 230.398438 L 357 396 L 356 396 Z "/>
+</clipPath>
+<clipPath id="clip91">
+ <path d="M 394 230.398438 L 396 230.398438 L 396 396 L 394 396 Z "/>
+</clipPath>
+<clipPath id="clip92">
+ <path d="M 433 230.398438 L 434 230.398438 L 434 396 L 433 396 Z "/>
+</clipPath>
+<clipPath id="clip93">
+ <path d="M 291.351562 387 L 461 387 L 461 389 L 291.351562 389 Z "/>
+</clipPath>
+<clipPath id="clip94">
+ <path d="M 291.351562 349 L 461 349 L 461 351 L 291.351562 351 Z "/>
+</clipPath>
+<clipPath id="clip95">
+ <path d="M 291.351562 312 L 461 312 L 461 314 L 291.351562 314 Z "/>
+</clipPath>
+<clipPath id="clip96">
+ <path d="M 291.351562 274 L 461 274 L 461 276 L 291.351562 276 Z "/>
+</clipPath>
+<clipPath id="clip97">
+ <path d="M 291.351562 237 L 461 237 L 461 239 L 291.351562 239 Z "/>
+</clipPath>
+<clipPath id="clip98">
+ <path d="M 298 230.398438 L 300 230.398438 L 300 396 L 298 396 Z "/>
+</clipPath>
+<clipPath id="clip99">
+ <path d="M 336 230.398438 L 338 230.398438 L 338 396 L 336 396 Z "/>
+</clipPath>
+<clipPath id="clip100">
+ <path d="M 375 230.398438 L 377 230.398438 L 377 396 L 375 396 Z "/>
+</clipPath>
+<clipPath id="clip101">
+ <path d="M 413 230.398438 L 415 230.398438 L 415 396 L 413 396 Z "/>
+</clipPath>
+<clipPath id="clip102">
+ <path d="M 452 230.398438 L 454 230.398438 L 454 396 L 452 396 Z "/>
+</clipPath>
+<clipPath id="clip103">
+ <path d="M 474.667969 216 L 712 216 L 712 432 L 474.667969 432 Z "/>
+</clipPath>
+<clipPath id="clip104">
+ <path d="M 474.667969 216 L 712 216 L 712 433 L 474.667969 433 Z "/>
+</clipPath>
+<clipPath id="clip105">
+ <path d="M 528.683594 230.398438 L 698 230.398438 L 698 396 L 528.683594 396 Z "/>
+</clipPath>
+<clipPath id="clip106">
+ <path d="M 528.683594 369 L 698 369 L 698 370 L 528.683594 370 Z "/>
+</clipPath>
+<clipPath id="clip107">
+ <path d="M 528.683594 331 L 698 331 L 698 332 L 528.683594 332 Z "/>
+</clipPath>
+<clipPath id="clip108">
+ <path d="M 528.683594 292 L 698 292 L 698 294 L 528.683594 294 Z "/>
+</clipPath>
+<clipPath id="clip109">
+ <path d="M 528.683594 254 L 698 254 L 698 256 L 528.683594 256 Z "/>
+</clipPath>
+<clipPath id="clip110">
+ <path d="M 555 230.398438 L 556 230.398438 L 556 396 L 555 396 Z "/>
+</clipPath>
+<clipPath id="clip111">
+ <path d="M 593 230.398438 L 595 230.398438 L 595 396 L 593 396 Z "/>
+</clipPath>
+<clipPath id="clip112">
+ <path d="M 632 230.398438 L 633 230.398438 L 633 396 L 632 396 Z "/>
+</clipPath>
+<clipPath id="clip113">
+ <path d="M 670 230.398438 L 671 230.398438 L 671 396 L 670 396 Z "/>
+</clipPath>
+<clipPath id="clip114">
+ <path d="M 528.683594 388 L 698.597656 388 L 698.597656 390 L 528.683594 390 Z "/>
+</clipPath>
+<clipPath id="clip115">
+ <path d="M 528.683594 349 L 698.597656 349 L 698.597656 351 L 528.683594 351 Z "/>
+</clipPath>
+<clipPath id="clip116">
+ <path d="M 528.683594 311 L 698.597656 311 L 698.597656 313 L 528.683594 313 Z "/>
+</clipPath>
+<clipPath id="clip117">
+ <path d="M 528.683594 273 L 698.597656 273 L 698.597656 275 L 528.683594 275 Z "/>
+</clipPath>
+<clipPath id="clip118">
+ <path d="M 528.683594 235 L 698.597656 235 L 698.597656 237 L 528.683594 237 Z "/>
+</clipPath>
+<clipPath id="clip119">
+ <path d="M 535 230.398438 L 537 230.398438 L 537 396 L 535 396 Z "/>
+</clipPath>
+<clipPath id="clip120">
+ <path d="M 574 230.398438 L 576 230.398438 L 576 396 L 574 396 Z "/>
+</clipPath>
+<clipPath id="clip121">
+ <path d="M 612 230.398438 L 614 230.398438 L 614 396 L 612 396 Z "/>
+</clipPath>
+<clipPath id="clip122">
+ <path d="M 651 230.398438 L 653 230.398438 L 653 396 L 651 396 Z "/>
+</clipPath>
+<clipPath id="clip123">
+ <path d="M 689 230.398438 L 691 230.398438 L 691 396 L 689 396 Z "/>
+</clipPath>
+<clipPath id="clip124">
+ <path d="M 0 432 L 238 432 L 238 649 L 0 649 Z "/>
+</clipPath>
+<clipPath id="clip125">
+ <path d="M 54.019531 446.398438 L 223 446.398438 L 223 612 L 54.019531 612 Z "/>
+</clipPath>
+<clipPath id="clip126">
+ <path d="M 54.019531 584 L 223.933594 584 L 223.933594 586 L 54.019531 586 Z "/>
+</clipPath>
+<clipPath id="clip127">
+ <path d="M 54.019531 547 L 223.933594 547 L 223.933594 548 L 54.019531 548 Z "/>
+</clipPath>
+<clipPath id="clip128">
+ <path d="M 54.019531 509 L 223.933594 509 L 223.933594 511 L 54.019531 511 Z "/>
+</clipPath>
+<clipPath id="clip129">
+ <path d="M 54.019531 472 L 223.933594 472 L 223.933594 473 L 54.019531 473 Z "/>
+</clipPath>
+<clipPath id="clip130">
+ <path d="M 80 446.398438 L 82 446.398438 L 82 612 L 80 612 Z "/>
+</clipPath>
+<clipPath id="clip131">
+ <path d="M 119 446.398438 L 120 446.398438 L 120 612 L 119 612 Z "/>
+</clipPath>
+<clipPath id="clip132">
+ <path d="M 157 446.398438 L 158 446.398438 L 158 612 L 157 612 Z "/>
+</clipPath>
+<clipPath id="clip133">
+ <path d="M 195 446.398438 L 197 446.398438 L 197 612 L 195 612 Z "/>
+</clipPath>
+<clipPath id="clip134">
+ <path d="M 54.019531 603 L 223.933594 603 L 223.933594 605 L 54.019531 605 Z "/>
+</clipPath>
+<clipPath id="clip135">
+ <path d="M 54.019531 565 L 223.933594 565 L 223.933594 567 L 54.019531 567 Z "/>
+</clipPath>
+<clipPath id="clip136">
+ <path d="M 54.019531 528 L 223.933594 528 L 223.933594 530 L 54.019531 530 Z "/>
+</clipPath>
+<clipPath id="clip137">
+ <path d="M 54.019531 490 L 223.933594 490 L 223.933594 492 L 54.019531 492 Z "/>
+</clipPath>
+<clipPath id="clip138">
+ <path d="M 54.019531 453 L 223.933594 453 L 223.933594 455 L 54.019531 455 Z "/>
+</clipPath>
+<clipPath id="clip139">
+ <path d="M 61 446.398438 L 63 446.398438 L 63 612 L 61 612 Z "/>
+</clipPath>
+<clipPath id="clip140">
+ <path d="M 99 446.398438 L 101 446.398438 L 101 612 L 99 612 Z "/>
+</clipPath>
+<clipPath id="clip141">
+ <path d="M 137 446.398438 L 140 446.398438 L 140 612 L 137 612 Z "/>
+</clipPath>
+<clipPath id="clip142">
+ <path d="M 176 446.398438 L 178 446.398438 L 178 612 L 176 612 Z "/>
+</clipPath>
+<clipPath id="clip143">
+ <path d="M 214 446.398438 L 216 446.398438 L 216 612 L 214 612 Z "/>
+</clipPath>
+<clipPath id="clip144">
+ <path d="M 237.332031 432 L 475 432 L 475 648 L 237.332031 648 Z "/>
+</clipPath>
+<clipPath id="clip145">
+ <path d="M 237.332031 432 L 475.664062 432 L 475.664062 649 L 237.332031 649 Z "/>
+</clipPath>
+<clipPath id="clip146">
+ <path d="M 291.351562 446.398438 L 461 446.398438 L 461 612 L 291.351562 612 Z "/>
+</clipPath>
+<clipPath id="clip147">
+ <path d="M 291.351562 590 L 461 590 L 461 592 L 291.351562 592 Z "/>
+</clipPath>
+<clipPath id="clip148">
+ <path d="M 291.351562 551 L 461 551 L 461 552 L 291.351562 552 Z "/>
+</clipPath>
+<clipPath id="clip149">
+ <path d="M 291.351562 512 L 461 512 L 461 513 L 291.351562 513 Z "/>
+</clipPath>
+<clipPath id="clip150">
+ <path d="M 291.351562 473 L 461 473 L 461 474 L 291.351562 474 Z "/>
+</clipPath>
+<clipPath id="clip151">
+ <path d="M 317 446.398438 L 319 446.398438 L 319 612 L 317 612 Z "/>
+</clipPath>
+<clipPath id="clip152">
+ <path d="M 356 446.398438 L 357 446.398438 L 357 612 L 356 612 Z "/>
+</clipPath>
+<clipPath id="clip153">
+ <path d="M 394 446.398438 L 396 446.398438 L 396 612 L 394 612 Z "/>
+</clipPath>
+<clipPath id="clip154">
+ <path d="M 433 446.398438 L 434 446.398438 L 434 612 L 433 612 Z "/>
+</clipPath>
+<clipPath id="clip155">
+ <path d="M 291.351562 609 L 461 609 L 461 611 L 291.351562 611 Z "/>
+</clipPath>
+<clipPath id="clip156">
+ <path d="M 291.351562 570 L 461 570 L 461 572 L 291.351562 572 Z "/>
+</clipPath>
+<clipPath id="clip157">
+ <path d="M 291.351562 531 L 461 531 L 461 533 L 291.351562 533 Z "/>
+</clipPath>
+<clipPath id="clip158">
+ <path d="M 291.351562 492 L 461 492 L 461 494 L 291.351562 494 Z "/>
+</clipPath>
+<clipPath id="clip159">
+ <path d="M 291.351562 453 L 461 453 L 461 455 L 291.351562 455 Z "/>
+</clipPath>
+<clipPath id="clip160">
+ <path d="M 298 446.398438 L 300 446.398438 L 300 612 L 298 612 Z "/>
+</clipPath>
+<clipPath id="clip161">
+ <path d="M 336 446.398438 L 338 446.398438 L 338 612 L 336 612 Z "/>
+</clipPath>
+<clipPath id="clip162">
+ <path d="M 375 446.398438 L 377 446.398438 L 377 612 L 375 612 Z "/>
+</clipPath>
+<clipPath id="clip163">
+ <path d="M 413 446.398438 L 415 446.398438 L 415 612 L 413 612 Z "/>
+</clipPath>
+<clipPath id="clip164">
+ <path d="M 452 446.398438 L 454 446.398438 L 454 612 L 452 612 Z "/>
+</clipPath>
+<clipPath id="clip165">
+ <path d="M 474.667969 432 L 712 432 L 712 648 L 474.667969 648 Z "/>
+</clipPath>
+<clipPath id="clip166">
+ <path d="M 474.667969 432 L 712 432 L 712 649 L 474.667969 649 Z "/>
+</clipPath>
+<clipPath id="clip167">
+ <path d="M 528.683594 446.398438 L 698 446.398438 L 698 612 L 528.683594 612 Z "/>
+</clipPath>
+<clipPath id="clip168">
+ <path d="M 528.683594 598 L 698 598 L 698 600 L 528.683594 600 Z "/>
+</clipPath>
+<clipPath id="clip169">
+ <path d="M 528.683594 560 L 698 560 L 698 561 L 528.683594 561 Z "/>
+</clipPath>
+<clipPath id="clip170">
+ <path d="M 528.683594 521 L 698 521 L 698 523 L 528.683594 523 Z "/>
+</clipPath>
+<clipPath id="clip171">
+ <path d="M 528.683594 483 L 698 483 L 698 484 L 528.683594 484 Z "/>
+</clipPath>
+<clipPath id="clip172">
+ <path d="M 555 446.398438 L 556 446.398438 L 556 612 L 555 612 Z "/>
+</clipPath>
+<clipPath id="clip173">
+ <path d="M 593 446.398438 L 595 446.398438 L 595 612 L 593 612 Z "/>
+</clipPath>
+<clipPath id="clip174">
+ <path d="M 632 446.398438 L 633 446.398438 L 633 612 L 632 612 Z "/>
+</clipPath>
+<clipPath id="clip175">
+ <path d="M 670 446.398438 L 671 446.398438 L 671 612 L 670 612 Z "/>
+</clipPath>
+<clipPath id="clip176">
+ <path d="M 528.683594 579 L 698.597656 579 L 698.597656 581 L 528.683594 581 Z "/>
+</clipPath>
+<clipPath id="clip177">
+ <path d="M 528.683594 540 L 698.597656 540 L 698.597656 542 L 528.683594 542 Z "/>
+</clipPath>
+<clipPath id="clip178">
+ <path d="M 528.683594 502 L 698.597656 502 L 698.597656 504 L 528.683594 504 Z "/>
+</clipPath>
+<clipPath id="clip179">
+ <path d="M 528.683594 463 L 698.597656 463 L 698.597656 465 L 528.683594 465 Z "/>
+</clipPath>
+<clipPath id="clip180">
+ <path d="M 535 446.398438 L 537 446.398438 L 537 612 L 535 612 Z "/>
+</clipPath>
+<clipPath id="clip181">
+ <path d="M 574 446.398438 L 576 446.398438 L 576 612 L 574 612 Z "/>
+</clipPath>
+<clipPath id="clip182">
+ <path d="M 612 446.398438 L 614 446.398438 L 614 612 L 612 612 Z "/>
+</clipPath>
+<clipPath id="clip183">
+ <path d="M 651 446.398438 L 653 446.398438 L 653 612 L 651 612 Z "/>
+</clipPath>
+<clipPath id="clip184">
+ <path d="M 689 446.398438 L 691 446.398438 L 691 612 L 689 612 Z "/>
+</clipPath>
+<clipPath id="clip185">
+ <path d="M 0 648 L 238 648 L 238 865 L 0 865 Z "/>
+</clipPath>
+<clipPath id="clip186">
+ <path d="M 54.019531 662.398438 L 223 662.398438 L 223 828 L 54.019531 828 Z "/>
+</clipPath>
+<clipPath id="clip187">
+ <path d="M 54.019531 800 L 223.933594 800 L 223.933594 801 L 54.019531 801 Z "/>
+</clipPath>
+<clipPath id="clip188">
+ <path d="M 54.019531 762 L 223.933594 762 L 223.933594 763 L 54.019531 763 Z "/>
+</clipPath>
+<clipPath id="clip189">
+ <path d="M 54.019531 724 L 223.933594 724 L 223.933594 725 L 54.019531 725 Z "/>
+</clipPath>
+<clipPath id="clip190">
+ <path d="M 54.019531 686 L 223.933594 686 L 223.933594 687 L 54.019531 687 Z "/>
+</clipPath>
+<clipPath id="clip191">
+ <path d="M 80 662.398438 L 82 662.398438 L 82 828 L 80 828 Z "/>
+</clipPath>
+<clipPath id="clip192">
+ <path d="M 119 662.398438 L 120 662.398438 L 120 828 L 119 828 Z "/>
+</clipPath>
+<clipPath id="clip193">
+ <path d="M 157 662.398438 L 158 662.398438 L 158 828 L 157 828 Z "/>
+</clipPath>
+<clipPath id="clip194">
+ <path d="M 195 662.398438 L 197 662.398438 L 197 828 L 195 828 Z "/>
+</clipPath>
+<clipPath id="clip195">
+ <path d="M 54.019531 819 L 223.933594 819 L 223.933594 821 L 54.019531 821 Z "/>
+</clipPath>
+<clipPath id="clip196">
+ <path d="M 54.019531 780 L 223.933594 780 L 223.933594 783 L 54.019531 783 Z "/>
+</clipPath>
+<clipPath id="clip197">
+ <path d="M 54.019531 742 L 223.933594 742 L 223.933594 744 L 54.019531 744 Z "/>
+</clipPath>
+<clipPath id="clip198">
+ <path d="M 54.019531 704 L 223.933594 704 L 223.933594 706 L 54.019531 706 Z "/>
+</clipPath>
+<clipPath id="clip199">
+ <path d="M 54.019531 666 L 223.933594 666 L 223.933594 668 L 54.019531 668 Z "/>
+</clipPath>
+<clipPath id="clip200">
+ <path d="M 61 662.398438 L 63 662.398438 L 63 828 L 61 828 Z "/>
+</clipPath>
+<clipPath id="clip201">
+ <path d="M 99 662.398438 L 101 662.398438 L 101 828 L 99 828 Z "/>
+</clipPath>
+<clipPath id="clip202">
+ <path d="M 137 662.398438 L 140 662.398438 L 140 828 L 137 828 Z "/>
+</clipPath>
+<clipPath id="clip203">
+ <path d="M 176 662.398438 L 178 662.398438 L 178 828 L 176 828 Z "/>
+</clipPath>
+<clipPath id="clip204">
+ <path d="M 214 662.398438 L 216 662.398438 L 216 828 L 214 828 Z "/>
+</clipPath>
+<clipPath id="clip205">
+ <path d="M 237.332031 648 L 475 648 L 475 864 L 237.332031 864 Z "/>
+</clipPath>
+<clipPath id="clip206">
+ <path d="M 237.332031 648 L 475.664062 648 L 475.664062 865 L 237.332031 865 Z "/>
+</clipPath>
+<clipPath id="clip207">
+ <path d="M 291.351562 662.398438 L 461 662.398438 L 461 828 L 291.351562 828 Z "/>
+</clipPath>
+<clipPath id="clip208">
+ <path d="M 291.351562 801 L 461 801 L 461 803 L 291.351562 803 Z "/>
+</clipPath>
+<clipPath id="clip209">
+ <path d="M 291.351562 762 L 461 762 L 461 764 L 291.351562 764 Z "/>
+</clipPath>
+<clipPath id="clip210">
+ <path d="M 291.351562 723 L 461 723 L 461 725 L 291.351562 725 Z "/>
+</clipPath>
+<clipPath id="clip211">
+ <path d="M 291.351562 684 L 461 684 L 461 686 L 291.351562 686 Z "/>
+</clipPath>
+<clipPath id="clip212">
+ <path d="M 317 662.398438 L 319 662.398438 L 319 828 L 317 828 Z "/>
+</clipPath>
+<clipPath id="clip213">
+ <path d="M 356 662.398438 L 357 662.398438 L 357 828 L 356 828 Z "/>
+</clipPath>
+<clipPath id="clip214">
+ <path d="M 394 662.398438 L 396 662.398438 L 396 828 L 394 828 Z "/>
+</clipPath>
+<clipPath id="clip215">
+ <path d="M 433 662.398438 L 434 662.398438 L 434 828 L 433 828 Z "/>
+</clipPath>
+<clipPath id="clip216">
+ <path d="M 291.351562 821 L 461 821 L 461 823 L 291.351562 823 Z "/>
+</clipPath>
+<clipPath id="clip217">
+ <path d="M 291.351562 782 L 461 782 L 461 784 L 291.351562 784 Z "/>
+</clipPath>
+<clipPath id="clip218">
+ <path d="M 291.351562 743 L 461 743 L 461 745 L 291.351562 745 Z "/>
+</clipPath>
+<clipPath id="clip219">
+ <path d="M 291.351562 704 L 461 704 L 461 706 L 291.351562 706 Z "/>
+</clipPath>
+<clipPath id="clip220">
+ <path d="M 291.351562 665 L 461 665 L 461 667 L 291.351562 667 Z "/>
+</clipPath>
+<clipPath id="clip221">
+ <path d="M 298 662.398438 L 300 662.398438 L 300 828 L 298 828 Z "/>
+</clipPath>
+<clipPath id="clip222">
+ <path d="M 336 662.398438 L 338 662.398438 L 338 828 L 336 828 Z "/>
+</clipPath>
+<clipPath id="clip223">
+ <path d="M 375 662.398438 L 377 662.398438 L 377 828 L 375 828 Z "/>
+</clipPath>
+<clipPath id="clip224">
+ <path d="M 413 662.398438 L 415 662.398438 L 415 828 L 413 828 Z "/>
+</clipPath>
+<clipPath id="clip225">
+ <path d="M 452 662.398438 L 454 662.398438 L 454 828 L 452 828 Z "/>
+</clipPath>
+<clipPath id="clip226">
+ <path d="M 474.667969 648 L 712 648 L 712 864 L 474.667969 864 Z "/>
+</clipPath>
+<clipPath id="clip227">
+ <path d="M 474.667969 648 L 712 648 L 712 865 L 474.667969 865 Z "/>
+</clipPath>
+<clipPath id="clip228">
+ <path d="M 528.683594 662.398438 L 698 662.398438 L 698 828 L 528.683594 828 Z "/>
+</clipPath>
+<clipPath id="clip229">
+ <path d="M 528.683594 801 L 698 801 L 698 802 L 528.683594 802 Z "/>
+</clipPath>
+<clipPath id="clip230">
+ <path d="M 528.683594 763 L 698 763 L 698 764 L 528.683594 764 Z "/>
+</clipPath>
+<clipPath id="clip231">
+ <path d="M 528.683594 725 L 698 725 L 698 726 L 528.683594 726 Z "/>
+</clipPath>
+<clipPath id="clip232">
+ <path d="M 528.683594 687 L 698 687 L 698 688 L 528.683594 688 Z "/>
+</clipPath>
+<clipPath id="clip233">
+ <path d="M 555 662.398438 L 556 662.398438 L 556 828 L 555 828 Z "/>
+</clipPath>
+<clipPath id="clip234">
+ <path d="M 593 662.398438 L 595 662.398438 L 595 828 L 593 828 Z "/>
+</clipPath>
+<clipPath id="clip235">
+ <path d="M 632 662.398438 L 633 662.398438 L 633 828 L 632 828 Z "/>
+</clipPath>
+<clipPath id="clip236">
+ <path d="M 670 662.398438 L 671 662.398438 L 671 828 L 670 828 Z "/>
+</clipPath>
+<clipPath id="clip237">
+ <path d="M 528.683594 820 L 698.597656 820 L 698.597656 822 L 528.683594 822 Z "/>
+</clipPath>
+<clipPath id="clip238">
+ <path d="M 528.683594 781 L 698.597656 781 L 698.597656 784 L 528.683594 784 Z "/>
+</clipPath>
+<clipPath id="clip239">
+ <path d="M 528.683594 743 L 698.597656 743 L 698.597656 745 L 528.683594 745 Z "/>
+</clipPath>
+<clipPath id="clip240">
+ <path d="M 528.683594 705 L 698.597656 705 L 698.597656 707 L 528.683594 707 Z "/>
+</clipPath>
+<clipPath id="clip241">
+ <path d="M 528.683594 667 L 698.597656 667 L 698.597656 669 L 528.683594 669 Z "/>
+</clipPath>
+<clipPath id="clip242">
+ <path d="M 535 662.398438 L 537 662.398438 L 537 828 L 535 828 Z "/>
+</clipPath>
+<clipPath id="clip243">
+ <path d="M 574 662.398438 L 576 662.398438 L 576 828 L 574 828 Z "/>
+</clipPath>
+<clipPath id="clip244">
+ <path d="M 612 662.398438 L 614 662.398438 L 614 828 L 612 828 Z "/>
+</clipPath>
+<clipPath id="clip245">
+ <path d="M 651 662.398438 L 653 662.398438 L 653 828 L 651 828 Z "/>
+</clipPath>
+<clipPath id="clip246">
+ <path d="M 689 662.398438 L 691 662.398438 L 691 828 L 689 828 Z "/>
+</clipPath>
+<clipPath id="clip247">
+ <path d="M 0 864 L 238 864 L 238 1081 L 0 1081 Z "/>
+</clipPath>
+<clipPath id="clip248">
+ <path d="M 54.019531 878.398438 L 223 878.398438 L 223 1044 L 54.019531 1044 Z "/>
+</clipPath>
+<clipPath id="clip249">
+ <path d="M 54.019531 1016 L 223.933594 1016 L 223.933594 1018 L 54.019531 1018 Z "/>
+</clipPath>
+<clipPath id="clip250">
+ <path d="M 54.019531 979 L 223.933594 979 L 223.933594 980 L 54.019531 980 Z "/>
+</clipPath>
+<clipPath id="clip251">
+ <path d="M 54.019531 941 L 223.933594 941 L 223.933594 943 L 54.019531 943 Z "/>
+</clipPath>
+<clipPath id="clip252">
+ <path d="M 54.019531 904 L 223.933594 904 L 223.933594 905 L 54.019531 905 Z "/>
+</clipPath>
+<clipPath id="clip253">
+ <path d="M 80 878.398438 L 82 878.398438 L 82 1044 L 80 1044 Z "/>
+</clipPath>
+<clipPath id="clip254">
+ <path d="M 119 878.398438 L 120 878.398438 L 120 1044 L 119 1044 Z "/>
+</clipPath>
+<clipPath id="clip255">
+ <path d="M 157 878.398438 L 158 878.398438 L 158 1044 L 157 1044 Z "/>
+</clipPath>
+<clipPath id="clip256">
+ <path d="M 195 878.398438 L 197 878.398438 L 197 1044 L 195 1044 Z "/>
+</clipPath>
+<clipPath id="clip257">
+ <path d="M 54.019531 1035 L 223.933594 1035 L 223.933594 1037 L 54.019531 1037 Z "/>
+</clipPath>
+<clipPath id="clip258">
+ <path d="M 54.019531 997 L 223.933594 997 L 223.933594 999 L 54.019531 999 Z "/>
+</clipPath>
+<clipPath id="clip259">
+ <path d="M 54.019531 960 L 223.933594 960 L 223.933594 962 L 54.019531 962 Z "/>
+</clipPath>
+<clipPath id="clip260">
+ <path d="M 54.019531 922 L 223.933594 922 L 223.933594 924 L 54.019531 924 Z "/>
+</clipPath>
+<clipPath id="clip261">
+ <path d="M 54.019531 885 L 223.933594 885 L 223.933594 887 L 54.019531 887 Z "/>
+</clipPath>
+<clipPath id="clip262">
+ <path d="M 61 878.398438 L 63 878.398438 L 63 1044 L 61 1044 Z "/>
+</clipPath>
+<clipPath id="clip263">
+ <path d="M 99 878.398438 L 101 878.398438 L 101 1044 L 99 1044 Z "/>
+</clipPath>
+<clipPath id="clip264">
+ <path d="M 137 878.398438 L 140 878.398438 L 140 1044 L 137 1044 Z "/>
+</clipPath>
+<clipPath id="clip265">
+ <path d="M 176 878.398438 L 178 878.398438 L 178 1044 L 176 1044 Z "/>
+</clipPath>
+<clipPath id="clip266">
+ <path d="M 214 878.398438 L 216 878.398438 L 216 1044 L 214 1044 Z "/>
+</clipPath>
+<clipPath id="clip267">
+ <path d="M 237.332031 864 L 475 864 L 475 1080 L 237.332031 1080 Z "/>
+</clipPath>
+<clipPath id="clip268">
+ <path d="M 237.332031 864 L 475.664062 864 L 475.664062 1081 L 237.332031 1081 Z "/>
+</clipPath>
+<clipPath id="clip269">
+ <path d="M 291.351562 878.398438 L 461 878.398438 L 461 1044 L 291.351562 1044 Z "/>
+</clipPath>
+<clipPath id="clip270">
+ <path d="M 291.351562 1016 L 461 1016 L 461 1018 L 291.351562 1018 Z "/>
+</clipPath>
+<clipPath id="clip271">
+ <path d="M 291.351562 979 L 461 979 L 461 980 L 291.351562 980 Z "/>
+</clipPath>
+<clipPath id="clip272">
+ <path d="M 291.351562 941 L 461 941 L 461 943 L 291.351562 943 Z "/>
+</clipPath>
+<clipPath id="clip273">
+ <path d="M 291.351562 904 L 461 904 L 461 905 L 291.351562 905 Z "/>
+</clipPath>
+<clipPath id="clip274">
+ <path d="M 317 878.398438 L 319 878.398438 L 319 1044 L 317 1044 Z "/>
+</clipPath>
+<clipPath id="clip275">
+ <path d="M 356 878.398438 L 357 878.398438 L 357 1044 L 356 1044 Z "/>
+</clipPath>
+<clipPath id="clip276">
+ <path d="M 394 878.398438 L 396 878.398438 L 396 1044 L 394 1044 Z "/>
+</clipPath>
+<clipPath id="clip277">
+ <path d="M 433 878.398438 L 434 878.398438 L 434 1044 L 433 1044 Z "/>
+</clipPath>
+<clipPath id="clip278">
+ <path d="M 291.351562 1035 L 461 1035 L 461 1037 L 291.351562 1037 Z "/>
+</clipPath>
+<clipPath id="clip279">
+ <path d="M 291.351562 997 L 461 997 L 461 999 L 291.351562 999 Z "/>
+</clipPath>
+<clipPath id="clip280">
+ <path d="M 291.351562 960 L 461 960 L 461 962 L 291.351562 962 Z "/>
+</clipPath>
+<clipPath id="clip281">
+ <path d="M 291.351562 922 L 461 922 L 461 924 L 291.351562 924 Z "/>
+</clipPath>
+<clipPath id="clip282">
+ <path d="M 291.351562 885 L 461 885 L 461 887 L 291.351562 887 Z "/>
+</clipPath>
+<clipPath id="clip283">
+ <path d="M 298 878.398438 L 300 878.398438 L 300 1044 L 298 1044 Z "/>
+</clipPath>
+<clipPath id="clip284">
+ <path d="M 336 878.398438 L 338 878.398438 L 338 1044 L 336 1044 Z "/>
+</clipPath>
+<clipPath id="clip285">
+ <path d="M 375 878.398438 L 377 878.398438 L 377 1044 L 375 1044 Z "/>
+</clipPath>
+<clipPath id="clip286">
+ <path d="M 413 878.398438 L 415 878.398438 L 415 1044 L 413 1044 Z "/>
+</clipPath>
+<clipPath id="clip287">
+ <path d="M 452 878.398438 L 454 878.398438 L 454 1044 L 452 1044 Z "/>
+</clipPath>
+<clipPath id="clip288">
+ <path d="M 474.667969 864 L 712 864 L 712 1080 L 474.667969 1080 Z "/>
+</clipPath>
+<clipPath id="clip289">
+ <path d="M 474.667969 864 L 712 864 L 712 1081 L 474.667969 1081 Z "/>
+</clipPath>
+<clipPath id="clip290">
+ <path d="M 528.683594 878.398438 L 698 878.398438 L 698 1044 L 528.683594 1044 Z "/>
+</clipPath>
+<clipPath id="clip291">
+ <path d="M 528.683594 1016 L 698 1016 L 698 1018 L 528.683594 1018 Z "/>
+</clipPath>
+<clipPath id="clip292">
+ <path d="M 528.683594 979 L 698 979 L 698 980 L 528.683594 980 Z "/>
+</clipPath>
+<clipPath id="clip293">
+ <path d="M 528.683594 941 L 698 941 L 698 943 L 528.683594 943 Z "/>
+</clipPath>
+<clipPath id="clip294">
+ <path d="M 528.683594 904 L 698 904 L 698 905 L 528.683594 905 Z "/>
+</clipPath>
+<clipPath id="clip295">
+ <path d="M 555 878.398438 L 556 878.398438 L 556 1044 L 555 1044 Z "/>
+</clipPath>
+<clipPath id="clip296">
+ <path d="M 593 878.398438 L 595 878.398438 L 595 1044 L 593 1044 Z "/>
+</clipPath>
+<clipPath id="clip297">
+ <path d="M 632 878.398438 L 633 878.398438 L 633 1044 L 632 1044 Z "/>
+</clipPath>
+<clipPath id="clip298">
+ <path d="M 670 878.398438 L 671 878.398438 L 671 1044 L 670 1044 Z "/>
+</clipPath>
+<clipPath id="clip299">
+ <path d="M 528.683594 1035 L 698.597656 1035 L 698.597656 1037 L 528.683594 1037 Z "/>
+</clipPath>
+<clipPath id="clip300">
+ <path d="M 528.683594 997 L 698.597656 997 L 698.597656 999 L 528.683594 999 Z "/>
+</clipPath>
+<clipPath id="clip301">
+ <path d="M 528.683594 960 L 698.597656 960 L 698.597656 962 L 528.683594 962 Z "/>
+</clipPath>
+<clipPath id="clip302">
+ <path d="M 528.683594 922 L 698.597656 922 L 698.597656 924 L 528.683594 924 Z "/>
+</clipPath>
+<clipPath id="clip303">
+ <path d="M 528.683594 885 L 698.597656 885 L 698.597656 887 L 528.683594 887 Z "/>
+</clipPath>
+<clipPath id="clip304">
+ <path d="M 535 878.398438 L 537 878.398438 L 537 1044 L 535 1044 Z "/>
+</clipPath>
+<clipPath id="clip305">
+ <path d="M 574 878.398438 L 576 878.398438 L 576 1044 L 574 1044 Z "/>
+</clipPath>
+<clipPath id="clip306">
+ <path d="M 612 878.398438 L 614 878.398438 L 614 1044 L 612 1044 Z "/>
+</clipPath>
+<clipPath id="clip307">
+ <path d="M 651 878.398438 L 653 878.398438 L 653 1044 L 651 1044 Z "/>
+</clipPath>
+<clipPath id="clip308">
+ <path d="M 689 878.398438 L 691 878.398438 L 691 1044 L 689 1044 Z "/>
+</clipPath>
+<clipPath id="clip309">
+ <path d="M 0 1080 L 238 1080 L 238 1297 L 0 1297 Z "/>
+</clipPath>
+<clipPath id="clip310">
+ <path d="M 54.019531 1094.398438 L 223 1094.398438 L 223 1260 L 54.019531 1260 Z "/>
+</clipPath>
+<clipPath id="clip311">
+ <path d="M 54.019531 1245 L 223.933594 1245 L 223.933594 1247 L 54.019531 1247 Z "/>
+</clipPath>
+<clipPath id="clip312">
+ <path d="M 54.019531 1204 L 223.933594 1204 L 223.933594 1206 L 54.019531 1206 Z "/>
+</clipPath>
+<clipPath id="clip313">
+ <path d="M 54.019531 1163 L 223.933594 1163 L 223.933594 1164 L 54.019531 1164 Z "/>
+</clipPath>
+<clipPath id="clip314">
+ <path d="M 54.019531 1122 L 223.933594 1122 L 223.933594 1123 L 54.019531 1123 Z "/>
+</clipPath>
+<clipPath id="clip315">
+ <path d="M 80 1094.398438 L 82 1094.398438 L 82 1260 L 80 1260 Z "/>
+</clipPath>
+<clipPath id="clip316">
+ <path d="M 119 1094.398438 L 120 1094.398438 L 120 1260 L 119 1260 Z "/>
+</clipPath>
+<clipPath id="clip317">
+ <path d="M 157 1094.398438 L 158 1094.398438 L 158 1260 L 157 1260 Z "/>
+</clipPath>
+<clipPath id="clip318">
+ <path d="M 195 1094.398438 L 197 1094.398438 L 197 1260 L 195 1260 Z "/>
+</clipPath>
+<clipPath id="clip319">
+ <path d="M 54.019531 1224 L 223.933594 1224 L 223.933594 1226 L 54.019531 1226 Z "/>
+</clipPath>
+<clipPath id="clip320">
+ <path d="M 54.019531 1183 L 223.933594 1183 L 223.933594 1185 L 54.019531 1185 Z "/>
+</clipPath>
+<clipPath id="clip321">
+ <path d="M 54.019531 1142 L 223.933594 1142 L 223.933594 1144 L 54.019531 1144 Z "/>
+</clipPath>
+<clipPath id="clip322">
+ <path d="M 54.019531 1101 L 223.933594 1101 L 223.933594 1103 L 54.019531 1103 Z "/>
+</clipPath>
+<clipPath id="clip323">
+ <path d="M 61 1094.398438 L 63 1094.398438 L 63 1260 L 61 1260 Z "/>
+</clipPath>
+<clipPath id="clip324">
+ <path d="M 99 1094.398438 L 101 1094.398438 L 101 1260 L 99 1260 Z "/>
+</clipPath>
+<clipPath id="clip325">
+ <path d="M 137 1094.398438 L 140 1094.398438 L 140 1260 L 137 1260 Z "/>
+</clipPath>
+<clipPath id="clip326">
+ <path d="M 176 1094.398438 L 178 1094.398438 L 178 1260 L 176 1260 Z "/>
+</clipPath>
+<clipPath id="clip327">
+ <path d="M 214 1094.398438 L 216 1094.398438 L 216 1260 L 214 1260 Z "/>
+</clipPath>
+<clipPath id="clip328">
+ <path d="M 237.332031 1080 L 475 1080 L 475 1296 L 237.332031 1296 Z "/>
+</clipPath>
+<clipPath id="clip329">
+ <path d="M 237.332031 1080 L 475.664062 1080 L 475.664062 1297 L 237.332031 1297 Z "/>
+</clipPath>
+<clipPath id="clip330">
+ <path d="M 291.351562 1094.398438 L 461 1094.398438 L 461 1260 L 291.351562 1260 Z "/>
+</clipPath>
+<clipPath id="clip331">
+ <path d="M 291.351562 1232 L 461 1232 L 461 1234 L 291.351562 1234 Z "/>
+</clipPath>
+<clipPath id="clip332">
+ <path d="M 291.351562 1195 L 461 1195 L 461 1196 L 291.351562 1196 Z "/>
+</clipPath>
+<clipPath id="clip333">
+ <path d="M 291.351562 1157 L 461 1157 L 461 1159 L 291.351562 1159 Z "/>
+</clipPath>
+<clipPath id="clip334">
+ <path d="M 291.351562 1120 L 461 1120 L 461 1121 L 291.351562 1121 Z "/>
+</clipPath>
+<clipPath id="clip335">
+ <path d="M 317 1094.398438 L 319 1094.398438 L 319 1260 L 317 1260 Z "/>
+</clipPath>
+<clipPath id="clip336">
+ <path d="M 356 1094.398438 L 357 1094.398438 L 357 1260 L 356 1260 Z "/>
+</clipPath>
+<clipPath id="clip337">
+ <path d="M 394 1094.398438 L 396 1094.398438 L 396 1260 L 394 1260 Z "/>
+</clipPath>
+<clipPath id="clip338">
+ <path d="M 433 1094.398438 L 434 1094.398438 L 434 1260 L 433 1260 Z "/>
+</clipPath>
+<clipPath id="clip339">
+ <path d="M 291.351562 1251 L 461 1251 L 461 1253 L 291.351562 1253 Z "/>
+</clipPath>
+<clipPath id="clip340">
+ <path d="M 291.351562 1213 L 461 1213 L 461 1215 L 291.351562 1215 Z "/>
+</clipPath>
+<clipPath id="clip341">
+ <path d="M 291.351562 1176 L 461 1176 L 461 1178 L 291.351562 1178 Z "/>
+</clipPath>
+<clipPath id="clip342">
+ <path d="M 291.351562 1138 L 461 1138 L 461 1140 L 291.351562 1140 Z "/>
+</clipPath>
+<clipPath id="clip343">
+ <path d="M 291.351562 1101 L 461 1101 L 461 1103 L 291.351562 1103 Z "/>
+</clipPath>
+<clipPath id="clip344">
+ <path d="M 298 1094.398438 L 300 1094.398438 L 300 1260 L 298 1260 Z "/>
+</clipPath>
+<clipPath id="clip345">
+ <path d="M 336 1094.398438 L 338 1094.398438 L 338 1260 L 336 1260 Z "/>
+</clipPath>
+<clipPath id="clip346">
+ <path d="M 375 1094.398438 L 377 1094.398438 L 377 1260 L 375 1260 Z "/>
+</clipPath>
+<clipPath id="clip347">
+ <path d="M 413 1094.398438 L 415 1094.398438 L 415 1260 L 413 1260 Z "/>
+</clipPath>
+<clipPath id="clip348">
+ <path d="M 452 1094.398438 L 454 1094.398438 L 454 1260 L 452 1260 Z "/>
+</clipPath>
+<clipPath id="clip349">
+ <path d="M 474.667969 1080 L 712 1080 L 712 1296 L 474.667969 1296 Z "/>
+</clipPath>
+<clipPath id="clip350">
+ <path d="M 474.667969 1080 L 712 1080 L 712 1297 L 474.667969 1297 Z "/>
+</clipPath>
+<clipPath id="clip351">
+ <path d="M 528.683594 1094.398438 L 698 1094.398438 L 698 1260 L 528.683594 1260 Z "/>
+</clipPath>
+<clipPath id="clip352">
+ <path d="M 528.683594 1232 L 698 1232 L 698 1234 L 528.683594 1234 Z "/>
+</clipPath>
+<clipPath id="clip353">
+ <path d="M 528.683594 1195 L 698 1195 L 698 1196 L 528.683594 1196 Z "/>
+</clipPath>
+<clipPath id="clip354">
+ <path d="M 528.683594 1157 L 698 1157 L 698 1159 L 528.683594 1159 Z "/>
+</clipPath>
+<clipPath id="clip355">
+ <path d="M 528.683594 1120 L 698 1120 L 698 1121 L 528.683594 1121 Z "/>
+</clipPath>
+<clipPath id="clip356">
+ <path d="M 555 1094.398438 L 556 1094.398438 L 556 1260 L 555 1260 Z "/>
+</clipPath>
+<clipPath id="clip357">
+ <path d="M 593 1094.398438 L 595 1094.398438 L 595 1260 L 593 1260 Z "/>
+</clipPath>
+<clipPath id="clip358">
+ <path d="M 632 1094.398438 L 633 1094.398438 L 633 1260 L 632 1260 Z "/>
+</clipPath>
+<clipPath id="clip359">
+ <path d="M 670 1094.398438 L 671 1094.398438 L 671 1260 L 670 1260 Z "/>
+</clipPath>
+<clipPath id="clip360">
+ <path d="M 528.683594 1251 L 698.597656 1251 L 698.597656 1253 L 528.683594 1253 Z "/>
+</clipPath>
+<clipPath id="clip361">
+ <path d="M 528.683594 1213 L 698.597656 1213 L 698.597656 1215 L 528.683594 1215 Z "/>
+</clipPath>
+<clipPath id="clip362">
+ <path d="M 528.683594 1176 L 698.597656 1176 L 698.597656 1178 L 528.683594 1178 Z "/>
+</clipPath>
+<clipPath id="clip363">
+ <path d="M 528.683594 1138 L 698.597656 1138 L 698.597656 1140 L 528.683594 1140 Z "/>
+</clipPath>
+<clipPath id="clip364">
+ <path d="M 528.683594 1101 L 698.597656 1101 L 698.597656 1103 L 528.683594 1103 Z "/>
+</clipPath>
+<clipPath id="clip365">
+ <path d="M 535 1094.398438 L 537 1094.398438 L 537 1260 L 535 1260 Z "/>
+</clipPath>
+<clipPath id="clip366">
+ <path d="M 574 1094.398438 L 576 1094.398438 L 576 1260 L 574 1260 Z "/>
+</clipPath>
+<clipPath id="clip367">
+ <path d="M 612 1094.398438 L 614 1094.398438 L 614 1260 L 612 1260 Z "/>
+</clipPath>
+<clipPath id="clip368">
+ <path d="M 651 1094.398438 L 653 1094.398438 L 653 1260 L 651 1260 Z "/>
+</clipPath>
+<clipPath id="clip369">
+ <path d="M 689 1094.398438 L 691 1094.398438 L 691 1260 L 689 1260 Z "/>
+</clipPath>
+<clipPath id="clip370">
+ <path d="M 0 1296 L 238 1296 L 238 1512 L 0 1512 Z "/>
+</clipPath>
+<clipPath id="clip371">
+ <path d="M 54.019531 1310.398438 L 223 1310.398438 L 223 1476 L 54.019531 1476 Z "/>
+</clipPath>
+<clipPath id="clip372">
+ <path d="M 54.019531 1448 L 223.933594 1448 L 223.933594 1450 L 54.019531 1450 Z "/>
+</clipPath>
+<clipPath id="clip373">
+ <path d="M 54.019531 1411 L 223.933594 1411 L 223.933594 1412 L 54.019531 1412 Z "/>
+</clipPath>
+<clipPath id="clip374">
+ <path d="M 54.019531 1373 L 223.933594 1373 L 223.933594 1375 L 54.019531 1375 Z "/>
+</clipPath>
+<clipPath id="clip375">
+ <path d="M 54.019531 1336 L 223.933594 1336 L 223.933594 1337 L 54.019531 1337 Z "/>
+</clipPath>
+<clipPath id="clip376">
+ <path d="M 80 1310.398438 L 82 1310.398438 L 82 1476 L 80 1476 Z "/>
+</clipPath>
+<clipPath id="clip377">
+ <path d="M 119 1310.398438 L 120 1310.398438 L 120 1476 L 119 1476 Z "/>
+</clipPath>
+<clipPath id="clip378">
+ <path d="M 157 1310.398438 L 158 1310.398438 L 158 1476 L 157 1476 Z "/>
+</clipPath>
+<clipPath id="clip379">
+ <path d="M 195 1310.398438 L 197 1310.398438 L 197 1476 L 195 1476 Z "/>
+</clipPath>
+<clipPath id="clip380">
+ <path d="M 54.019531 1467 L 223.933594 1467 L 223.933594 1469 L 54.019531 1469 Z "/>
+</clipPath>
+<clipPath id="clip381">
+ <path d="M 54.019531 1429 L 223.933594 1429 L 223.933594 1431 L 54.019531 1431 Z "/>
+</clipPath>
+<clipPath id="clip382">
+ <path d="M 54.019531 1392 L 223.933594 1392 L 223.933594 1394 L 54.019531 1394 Z "/>
+</clipPath>
+<clipPath id="clip383">
+ <path d="M 54.019531 1354 L 223.933594 1354 L 223.933594 1356 L 54.019531 1356 Z "/>
+</clipPath>
+<clipPath id="clip384">
+ <path d="M 54.019531 1317 L 223.933594 1317 L 223.933594 1319 L 54.019531 1319 Z "/>
+</clipPath>
+<clipPath id="clip385">
+ <path d="M 61 1310.398438 L 63 1310.398438 L 63 1476 L 61 1476 Z "/>
+</clipPath>
+<clipPath id="clip386">
+ <path d="M 99 1310.398438 L 101 1310.398438 L 101 1476 L 99 1476 Z "/>
+</clipPath>
+<clipPath id="clip387">
+ <path d="M 137 1310.398438 L 140 1310.398438 L 140 1476 L 137 1476 Z "/>
+</clipPath>
+<clipPath id="clip388">
+ <path d="M 176 1310.398438 L 178 1310.398438 L 178 1476 L 176 1476 Z "/>
+</clipPath>
+<clipPath id="clip389">
+ <path d="M 214 1310.398438 L 216 1310.398438 L 216 1476 L 214 1476 Z "/>
+</clipPath>
+<clipPath id="clip390">
+ <path d="M 237.332031 1296 L 475 1296 L 475 1512 L 237.332031 1512 Z "/>
+</clipPath>
+<clipPath id="clip391">
+ <path d="M 237.332031 1296 L 475.664062 1296 L 475.664062 1512 L 237.332031 1512 Z "/>
+</clipPath>
+<clipPath id="clip392">
+ <path d="M 291.351562 1310.398438 L 461 1310.398438 L 461 1476 L 291.351562 1476 Z "/>
+</clipPath>
+<clipPath id="clip393">
+ <path d="M 291.351562 1448 L 461 1448 L 461 1450 L 291.351562 1450 Z "/>
+</clipPath>
+<clipPath id="clip394">
+ <path d="M 291.351562 1411 L 461 1411 L 461 1412 L 291.351562 1412 Z "/>
+</clipPath>
+<clipPath id="clip395">
+ <path d="M 291.351562 1373 L 461 1373 L 461 1375 L 291.351562 1375 Z "/>
+</clipPath>
+<clipPath id="clip396">
+ <path d="M 291.351562 1336 L 461 1336 L 461 1337 L 291.351562 1337 Z "/>
+</clipPath>
+<clipPath id="clip397">
+ <path d="M 317 1310.398438 L 319 1310.398438 L 319 1476 L 317 1476 Z "/>
+</clipPath>
+<clipPath id="clip398">
+ <path d="M 356 1310.398438 L 357 1310.398438 L 357 1476 L 356 1476 Z "/>
+</clipPath>
+<clipPath id="clip399">
+ <path d="M 394 1310.398438 L 396 1310.398438 L 396 1476 L 394 1476 Z "/>
+</clipPath>
+<clipPath id="clip400">
+ <path d="M 433 1310.398438 L 434 1310.398438 L 434 1476 L 433 1476 Z "/>
+</clipPath>
+<clipPath id="clip401">
+ <path d="M 291.351562 1467 L 461 1467 L 461 1469 L 291.351562 1469 Z "/>
+</clipPath>
+<clipPath id="clip402">
+ <path d="M 291.351562 1429 L 461 1429 L 461 1431 L 291.351562 1431 Z "/>
+</clipPath>
+<clipPath id="clip403">
+ <path d="M 291.351562 1392 L 461 1392 L 461 1394 L 291.351562 1394 Z "/>
+</clipPath>
+<clipPath id="clip404">
+ <path d="M 291.351562 1354 L 461 1354 L 461 1356 L 291.351562 1356 Z "/>
+</clipPath>
+<clipPath id="clip405">
+ <path d="M 291.351562 1317 L 461 1317 L 461 1319 L 291.351562 1319 Z "/>
+</clipPath>
+<clipPath id="clip406">
+ <path d="M 298 1310.398438 L 300 1310.398438 L 300 1476 L 298 1476 Z "/>
+</clipPath>
+<clipPath id="clip407">
+ <path d="M 336 1310.398438 L 338 1310.398438 L 338 1476 L 336 1476 Z "/>
+</clipPath>
+<clipPath id="clip408">
+ <path d="M 375 1310.398438 L 377 1310.398438 L 377 1476 L 375 1476 Z "/>
+</clipPath>
+<clipPath id="clip409">
+ <path d="M 413 1310.398438 L 415 1310.398438 L 415 1476 L 413 1476 Z "/>
+</clipPath>
+<clipPath id="clip410">
+ <path d="M 452 1310.398438 L 454 1310.398438 L 454 1476 L 452 1476 Z "/>
+</clipPath>
+<clipPath id="clip411">
+ <path d="M 474.667969 1296 L 712 1296 L 712 1512 L 474.667969 1512 Z "/>
+</clipPath>
+<clipPath id="clip412">
+ <path d="M 528.683594 1310.398438 L 698 1310.398438 L 698 1476 L 528.683594 1476 Z "/>
+</clipPath>
+<clipPath id="clip413">
+ <path d="M 528.683594 1448 L 698 1448 L 698 1450 L 528.683594 1450 Z "/>
+</clipPath>
+<clipPath id="clip414">
+ <path d="M 528.683594 1411 L 698 1411 L 698 1412 L 528.683594 1412 Z "/>
+</clipPath>
+<clipPath id="clip415">
+ <path d="M 528.683594 1373 L 698 1373 L 698 1375 L 528.683594 1375 Z "/>
+</clipPath>
+<clipPath id="clip416">
+ <path d="M 528.683594 1336 L 698 1336 L 698 1337 L 528.683594 1337 Z "/>
+</clipPath>
+<clipPath id="clip417">
+ <path d="M 555 1310.398438 L 556 1310.398438 L 556 1476 L 555 1476 Z "/>
+</clipPath>
+<clipPath id="clip418">
+ <path d="M 593 1310.398438 L 595 1310.398438 L 595 1476 L 593 1476 Z "/>
+</clipPath>
+<clipPath id="clip419">
+ <path d="M 632 1310.398438 L 633 1310.398438 L 633 1476 L 632 1476 Z "/>
+</clipPath>
+<clipPath id="clip420">
+ <path d="M 670 1310.398438 L 671 1310.398438 L 671 1476 L 670 1476 Z "/>
+</clipPath>
+<clipPath id="clip421">
+ <path d="M 528.683594 1467 L 698.597656 1467 L 698.597656 1469 L 528.683594 1469 Z "/>
+</clipPath>
+<clipPath id="clip422">
+ <path d="M 528.683594 1429 L 698.597656 1429 L 698.597656 1431 L 528.683594 1431 Z "/>
+</clipPath>
+<clipPath id="clip423">
+ <path d="M 528.683594 1392 L 698.597656 1392 L 698.597656 1394 L 528.683594 1394 Z "/>
+</clipPath>
+<clipPath id="clip424">
+ <path d="M 528.683594 1354 L 698.597656 1354 L 698.597656 1356 L 528.683594 1356 Z "/>
+</clipPath>
+<clipPath id="clip425">
+ <path d="M 528.683594 1317 L 698.597656 1317 L 698.597656 1319 L 528.683594 1319 Z "/>
+</clipPath>
+<clipPath id="clip426">
+ <path d="M 535 1310.398438 L 537 1310.398438 L 537 1476 L 535 1476 Z "/>
+</clipPath>
+<clipPath id="clip427">
+ <path d="M 574 1310.398438 L 576 1310.398438 L 576 1476 L 574 1476 Z "/>
+</clipPath>
+<clipPath id="clip428">
+ <path d="M 612 1310.398438 L 614 1310.398438 L 614 1476 L 612 1476 Z "/>
+</clipPath>
+<clipPath id="clip429">
+ <path d="M 651 1310.398438 L 653 1310.398438 L 653 1476 L 651 1476 Z "/>
+</clipPath>
+<clipPath id="clip430">
+ <path d="M 689 1310.398438 L 691 1310.398438 L 691 1476 L 689 1476 Z "/>
+</clipPath>
+</defs>
+<g id="surface1191">
+<rect x="0" y="0" width="712" height="1512" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 237.332031 216 L 237.332031 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 222.933594 179.027344 L 222.933594 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.800781 L 222.933594 152.800781 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.308594 L 222.933594 115.308594 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 77.820312 L 222.933594 77.820312 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.328125 L 222.933594 40.328125 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 179.027344 L 80.890625 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 179.027344 L 119.28125 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 179.027344 L 157.671875 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 179.027344 L 196.058594 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 222.933594 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.054688 L 222.933594 134.054688 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.5625 L 222.933594 96.5625 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.074219 L 222.933594 59.074219 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.582031 L 222.933594 21.582031 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 179.027344 L 61.695312 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 179.027344 L 100.085938 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 179.027344 L 138.476562 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 179.027344 L 176.867188 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 179.027344 L 215.253906 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 171.546875 L 62.621094 169.742188 L 62.925781 169.140625 L 63.234375 168.539062 L 63.542969 167.941406 L 63.851562 167.339844 L 64.15625 166.738281 L 65.390625 164.332031 L 65.695312 163.730469 L 66.003906 163.132812 L 66.621094 161.929688 L 66.925781 161.328125 L 68.160156 158.921875 L 68.464844 158.324219 L 69.390625 156.519531 L 69.695312 155.917969 L 70.3125 154.714844 L 70.621094 154.117188 L 70.929688 153.515625 L 71.234375 152.914062 L 72.46875 150.507812 L 72.773438 149.90625 L 73.082031 149.308594 L 73.699219 148.105469 L 74.003906 147.503906 L 75.238281 145.097656 L 75.542969 144.5 L 76.46875 142.695312 L 76.773438 142.09375 L 77.699219 140.289062 L 78.007812 139.691406 L 78.3125 139.089844 L 79.238281 137.285156 L 79.542969 136.683594 L 79.851562 136.082031 L 80.160156 135.484375 L 80.777344 134.28125 L 81.082031 133.679688 L 82.007812 131.875 L 82.3125 131.273438 L 82.621094 130.675781 L 83.546875 128.871094 L 83.851562 128.269531 L 84.777344 126.464844 L 85.082031 125.867188 L 86.316406 123.460938 L 86.621094 122.859375 L 86.929688 122.257812 L 87.238281 121.660156 L 87.855469 120.457031 L 88.160156 119.855469 L 89.085938 118.050781 L 89.390625 117.449219 L 89.699219 116.851562 L 90.625 115.046875 L 90.929688 114.445312 L 91.855469 112.640625 L 92.160156 112.042969 L 93.394531 109.636719 L 93.699219 109.035156 L 94.007812 108.433594 L 94.316406 107.835938 L 94.625 107.234375 L 94.929688 106.632812 L 96.164062 104.226562 L 96.46875 103.625 L 96.777344 103.027344 L 97.394531 101.824219 L 97.699219 101.222656 L 98.933594 98.816406 L 99.238281 98.21875 L 100.164062 96.414062 L 100.46875 95.8125 L 101.394531 94.007812 L 101.703125 93.410156 L 102.007812 92.808594 L 103.242188 90.402344 L 103.546875 89.800781 L 103.855469 89.203125 L 104.472656 88 L 104.777344 87.398438 L 106.011719 84.992188 L 106.316406 84.394531 L 107.242188 82.589844 L 107.546875 81.988281 L 108.472656 80.183594 L 108.78125 79.585938 L 109.085938 78.984375 L 110.011719 77.179688 L 110.316406 76.578125 L 110.625 75.976562 L 110.933594 75.378906 L 111.550781 74.175781 L 111.855469 73.574219 L 112.78125 71.769531 L 113.085938 71.167969 L 113.394531 70.570312 L 114.320312 68.765625 L 114.625 68.164062 L 115.550781 66.359375 L 115.855469 65.761719 L 117.089844 63.355469 L 117.394531 62.753906 L 117.703125 62.152344 L 118.011719 61.554688 L 118.320312 60.953125 L 118.625 60.351562 L 119.859375 57.945312 L 120.164062 57.34375 L 120.472656 56.746094 L 121.398438 54.941406 L 121.703125 54.339844 L 122.628906 52.535156 L 122.933594 51.9375 L 124.167969 49.53125 L 124.472656 48.929688 L 125.089844 47.726562 L 125.398438 47.128906 L 125.703125 46.527344 L 126.9375 44.121094 L 127.242188 43.519531 L 127.550781 42.921875 L 128.167969 41.71875 L 128.472656 41.117188 L 129.707031 38.710938 L 130.011719 38.113281 L 130.9375 36.308594 L 131.242188 35.707031 L 132.167969 33.902344 L 132.476562 33.304688 L 132.78125 32.703125 L 133.707031 30.898438 L 134.011719 30.296875 L 134.320312 29.695312 L 134.628906 29.097656 L 135.246094 27.894531 L 135.550781 27.292969 L 136.785156 24.886719 L 137.089844 24.289062 L 138.015625 22.484375 L 138.320312 21.882812 L 138.628906 21.882812 L 139.554688 23.6875 L 139.859375 24.289062 L 140.167969 24.886719 L 140.785156 26.089844 L 141.089844 26.691406 L 142.324219 29.097656 L 142.628906 29.695312 L 143.554688 31.5 L 143.859375 32.101562 L 144.476562 33.304688 L 144.785156 33.902344 L 145.09375 34.503906 L 145.398438 35.105469 L 146.324219 36.910156 L 146.628906 37.511719 L 146.9375 38.113281 L 147.246094 38.710938 L 147.863281 39.914062 L 148.167969 40.515625 L 149.09375 42.320312 L 149.398438 42.921875 L 149.707031 43.519531 L 150.632812 45.324219 L 150.9375 45.925781 L 151.554688 47.128906 L 151.863281 47.726562 L 152.171875 48.328125 L 152.476562 48.929688 L 153.402344 50.734375 L 153.707031 51.335938 L 154.015625 51.9375 L 154.324219 52.535156 L 154.941406 53.738281 L 155.246094 54.339844 L 156.171875 56.144531 L 156.476562 56.746094 L 156.785156 57.34375 L 157.710938 59.148438 L 158.015625 59.75 L 158.941406 61.554688 L 159.246094 62.152344 L 160.480469 64.558594 L 160.785156 65.160156 L 161.09375 65.761719 L 161.402344 66.359375 L 161.710938 66.960938 L 162.015625 67.5625 L 163.25 69.96875 L 163.554688 70.570312 L 163.863281 71.167969 L 164.480469 72.371094 L 164.785156 72.972656 L 166.019531 75.378906 L 166.324219 75.976562 L 167.25 77.78125 L 167.554688 78.382812 L 168.171875 79.585938 L 168.480469 80.183594 L 168.789062 80.785156 L 169.09375 81.386719 L 170.328125 83.792969 L 170.632812 84.394531 L 170.941406 84.992188 L 171.558594 86.195312 L 171.863281 86.796875 L 173.097656 89.203125 L 173.402344 89.800781 L 174.328125 91.605469 L 174.632812 92.207031 L 175.25 93.410156 L 175.558594 94.007812 L 175.867188 94.609375 L 176.171875 95.210938 L 177.097656 97.015625 L 177.402344 97.617188 L 177.710938 98.21875 L 178.019531 98.816406 L 178.636719 100.019531 L 178.941406 100.621094 L 179.867188 102.425781 L 180.171875 103.027344 L 180.480469 103.625 L 181.40625 105.429688 L 181.710938 106.03125 L 182.636719 107.835938 L 182.941406 108.433594 L 184.175781 110.839844 L 184.480469 111.441406 L 184.789062 112.042969 L 185.097656 112.640625 L 185.714844 113.84375 L 186.019531 114.445312 L 186.945312 116.25 L 187.25 116.851562 L 187.558594 117.449219 L 188.484375 119.253906 L 188.789062 119.855469 L 189.714844 121.660156 L 190.019531 122.257812 L 191.253906 124.664062 L 191.558594 125.265625 L 191.867188 125.867188 L 192.175781 126.464844 L 192.484375 127.066406 L 192.789062 127.667969 L 194.023438 130.074219 L 194.328125 130.675781 L 194.636719 131.273438 L 195.253906 132.476562 L 195.558594 133.078125 L 196.792969 135.484375 L 197.097656 136.082031 L 198.023438 137.886719 L 198.328125 138.488281 L 198.945312 139.691406 L 199.253906 140.289062 L 199.5625 140.890625 L 199.867188 141.492188 L 201.101562 143.898438 L 201.40625 144.5 L 201.714844 145.097656 L 202.332031 146.300781 L 202.636719 146.902344 L 203.871094 149.308594 L 204.175781 149.90625 L 205.101562 151.710938 L 205.40625 152.3125 L 206.332031 154.117188 L 206.640625 154.714844 L 206.945312 155.316406 L 207.871094 157.121094 L 208.175781 157.722656 L 208.484375 158.324219 L 208.792969 158.921875 L 209.410156 160.125 L 209.714844 160.726562 L 210.640625 162.53125 L 210.945312 163.132812 L 211.253906 163.730469 L 212.179688 165.535156 L 212.484375 166.136719 L 213.410156 167.941406 L 213.714844 168.539062 L 214.949219 170.945312 L 215.253906 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.492188"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.492188"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.492188"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.492188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.511719"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.511719"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.511719"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.511719"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.019531"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.019531"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.019531"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.019531"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.054688 L 54.019531 134.054688 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.5625 L 54.019531 96.5625 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.074219 L 54.019531 59.074219 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.582031 L 54.019531 21.582031 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 183.28125 L 61.695312 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 183.28125 L 100.085938 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 183.28125 L 138.476562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 183.28125 L 176.867188 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 183.28125 L 215.253906 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-1" x="23.335938" y="10.800781"/>
+ <use xlink:href="#glyph5-2" x="30.666016" y="10.800781"/>
+ <use xlink:href="#glyph5-3" x="35.335938" y="10.800781"/>
+ <use xlink:href="#glyph5-4" x="38.669922" y="10.800781"/>
+ <use xlink:href="#glyph5-5" x="45.34375" y="10.800781"/>
+ <use xlink:href="#glyph5-6" x="52.673828" y="10.800781"/>
+ <use xlink:href="#glyph5-7" x="60.003906" y="10.800781"/>
+ <use xlink:href="#glyph5-8" x="63.337891" y="10.800781"/>
+</g>
+<g clip-path="url(#clip20)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 216 L 474.664062 216 L 474.664062 0 L 237.332031 0 Z "/>
+</g>
+<g clip-path="url(#clip21)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 216 L 474.664062 216 L 474.664062 0 L 237.332031 0 Z "/>
+</g>
+<g clip-path="url(#clip22)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 179.027344 L 460.265625 179.027344 L 460.265625 14.398438 L 291.351562 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip23)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 154.882812 L 460.265625 154.882812 "/>
+</g>
+<g clip-path="url(#clip24)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 116.882812 L 460.265625 116.882812 "/>
+</g>
+<g clip-path="url(#clip25)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 78.882812 L 460.265625 78.882812 "/>
+</g>
+<g clip-path="url(#clip26)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 40.882812 L 460.265625 40.882812 "/>
+</g>
+<g clip-path="url(#clip27)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 179.027344 L 318.222656 14.398438 "/>
+</g>
+<g clip-path="url(#clip28)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 179.027344 L 356.613281 14.398438 "/>
+</g>
+<g clip-path="url(#clip29)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 179.027344 L 395.003906 14.398438 "/>
+</g>
+<g clip-path="url(#clip30)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 179.027344 L 433.394531 14.398438 "/>
+</g>
+<g clip-path="url(#clip31)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 173.882812 L 460.265625 173.882812 "/>
+</g>
+<g clip-path="url(#clip32)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 135.882812 L 460.265625 135.882812 "/>
+</g>
+<g clip-path="url(#clip33)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 97.882812 L 460.265625 97.882812 "/>
+</g>
+<g clip-path="url(#clip34)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 59.882812 L 460.265625 59.882812 "/>
+</g>
+<g clip-path="url(#clip35)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 21.882812 L 460.265625 21.882812 "/>
+</g>
+<g clip-path="url(#clip36)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 179.027344 L 299.03125 14.398438 "/>
+</g>
+<g clip-path="url(#clip37)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 179.027344 L 337.417969 14.398438 "/>
+</g>
+<g clip-path="url(#clip38)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 179.027344 L 375.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip39)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 179.027344 L 414.199219 14.398438 "/>
+</g>
+<g clip-path="url(#clip40)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 179.027344 L 452.589844 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 171.546875 L 299.335938 171.488281 L 299.644531 171.433594 L 299.953125 171.371094 L 300.261719 171.3125 L 300.566406 171.25 L 301.492188 171.050781 L 301.800781 170.980469 L 302.105469 170.90625 L 302.722656 170.757812 L 303.03125 170.679688 L 303.335938 170.597656 L 303.644531 170.515625 L 304.261719 170.34375 L 304.570312 170.25 L 304.875 170.15625 L 305.183594 170.0625 L 305.492188 169.964844 L 305.800781 169.863281 L 306.105469 169.757812 L 306.722656 169.539062 L 307.339844 169.304688 L 307.644531 169.183594 L 307.953125 169.058594 L 308.261719 168.929688 L 308.570312 168.796875 L 308.878906 168.660156 L 309.183594 168.515625 L 309.492188 168.371094 L 309.800781 168.222656 L 310.109375 168.066406 L 310.414062 167.90625 L 310.722656 167.742188 L 311.03125 167.574219 L 311.339844 167.398438 L 311.648438 167.214844 L 311.953125 167.03125 L 312.261719 166.839844 L 312.570312 166.640625 L 312.878906 166.433594 L 313.183594 166.222656 L 313.492188 166.007812 L 313.800781 165.78125 L 314.109375 165.550781 L 314.417969 165.308594 L 314.722656 165.0625 L 315.03125 164.808594 L 315.339844 164.542969 L 315.648438 164.273438 L 315.953125 163.992188 L 316.261719 163.699219 L 316.570312 163.402344 L 316.878906 163.09375 L 317.1875 162.773438 L 317.492188 162.445312 L 317.800781 162.101562 L 318.109375 161.75 L 318.417969 161.386719 L 318.722656 161.011719 L 319.03125 160.625 L 319.339844 160.226562 L 319.648438 159.8125 L 319.957031 159.386719 L 320.261719 158.945312 L 320.570312 158.492188 L 320.878906 158.019531 L 321.1875 157.535156 L 321.492188 157.035156 L 321.800781 156.515625 L 322.109375 155.984375 L 322.417969 155.429688 L 322.726562 154.859375 L 323.03125 154.273438 L 323.339844 153.664062 L 323.648438 153.039062 L 323.957031 152.390625 L 324.265625 151.722656 L 324.570312 151.035156 L 324.878906 150.324219 L 325.1875 149.59375 L 325.496094 148.835938 L 325.800781 148.054688 L 326.109375 147.253906 L 326.417969 146.425781 L 326.726562 145.570312 L 327.035156 144.691406 L 327.339844 143.785156 L 327.648438 142.851562 L 327.957031 141.890625 L 328.265625 140.902344 L 328.570312 139.882812 L 328.878906 138.839844 L 329.1875 137.761719 L 329.496094 136.65625 L 329.804688 135.519531 L 330.109375 134.355469 L 330.417969 133.15625 L 330.726562 131.929688 L 331.035156 130.667969 L 331.339844 129.378906 L 331.648438 128.054688 L 331.957031 126.699219 L 332.265625 125.316406 L 332.574219 123.898438 L 332.878906 122.449219 L 333.1875 120.972656 L 333.496094 119.460938 L 333.804688 117.921875 L 334.109375 116.351562 L 334.417969 114.753906 L 334.726562 113.128906 L 335.035156 111.476562 L 335.34375 109.800781 L 335.648438 108.097656 L 335.957031 106.367188 L 336.265625 104.617188 L 336.574219 102.847656 L 336.878906 101.058594 L 337.1875 99.25 L 337.496094 97.425781 L 337.804688 95.589844 L 338.113281 93.738281 L 338.417969 91.878906 L 338.726562 90.007812 L 339.34375 86.257812 L 339.648438 84.378906 L 339.957031 82.5 L 340.265625 80.625 L 340.574219 78.753906 L 340.882812 76.894531 L 341.1875 75.046875 L 341.496094 73.207031 L 341.804688 71.386719 L 342.113281 69.585938 L 342.421875 67.800781 L 342.726562 66.039062 L 343.035156 64.304688 L 343.34375 62.59375 L 343.652344 60.914062 L 343.957031 59.265625 L 344.265625 57.648438 L 344.574219 56.0625 L 344.882812 54.515625 L 345.191406 53.003906 L 345.496094 51.53125 L 345.804688 50.097656 L 346.113281 48.703125 L 346.421875 47.351562 L 346.726562 46.039062 L 347.035156 44.769531 L 347.34375 43.542969 L 347.652344 42.359375 L 347.960938 41.21875 L 348.265625 40.125 L 348.574219 39.070312 L 348.882812 38.054688 L 349.191406 37.085938 L 349.496094 36.15625 L 349.804688 35.269531 L 350.113281 34.425781 L 350.421875 33.617188 L 350.730469 32.847656 L 351.035156 32.117188 L 351.34375 31.425781 L 351.652344 30.769531 L 351.960938 30.144531 L 352.265625 29.558594 L 352.574219 29.003906 L 352.882812 28.480469 L 353.191406 27.984375 L 353.5 27.523438 L 353.804688 27.085938 L 354.113281 26.679688 L 354.421875 26.296875 L 354.730469 25.9375 L 355.035156 25.605469 L 355.34375 25.292969 L 355.652344 25.003906 L 355.960938 24.734375 L 356.269531 24.480469 L 356.574219 24.25 L 356.882812 24.035156 L 357.191406 23.835938 L 357.5 23.652344 L 357.808594 23.484375 L 358.113281 23.328125 L 358.421875 23.183594 L 358.730469 23.050781 L 359.039062 22.933594 L 359.34375 22.824219 L 359.652344 22.722656 L 359.960938 22.632812 L 360.269531 22.550781 L 360.578125 22.472656 L 360.882812 22.40625 L 361.191406 22.34375 L 361.5 22.289062 L 361.808594 22.238281 L 362.113281 22.195312 L 362.421875 22.15625 L 362.730469 22.121094 L 363.039062 22.089844 L 363.347656 22.0625 L 363.652344 22.035156 L 364.578125 21.976562 L 364.882812 21.964844 L 365.191406 21.949219 L 365.5 21.941406 L 365.808594 21.929688 L 366.117188 21.921875 L 366.421875 21.914062 L 367.347656 21.902344 L 367.652344 21.898438 L 368.269531 21.890625 L 368.578125 21.890625 L 368.886719 21.886719 L 369.808594 21.886719 L 370.117188 21.882812 L 381.503906 21.882812 L 381.808594 21.886719 L 382.734375 21.886719 L 383.039062 21.890625 L 383.347656 21.890625 L 384.273438 21.902344 L 384.578125 21.90625 L 385.195312 21.914062 L 385.503906 21.921875 L 385.808594 21.929688 L 386.117188 21.941406 L 386.425781 21.949219 L 386.734375 21.964844 L 387.042969 21.976562 L 387.347656 21.996094 L 387.964844 22.035156 L 388.273438 22.0625 L 388.578125 22.089844 L 388.886719 22.121094 L 389.195312 22.15625 L 389.503906 22.195312 L 389.8125 22.238281 L 390.117188 22.289062 L 390.425781 22.34375 L 390.734375 22.40625 L 391.042969 22.472656 L 391.351562 22.550781 L 391.65625 22.632812 L 391.964844 22.722656 L 392.273438 22.824219 L 392.582031 22.933594 L 392.886719 23.050781 L 393.195312 23.183594 L 393.503906 23.328125 L 393.8125 23.484375 L 394.121094 23.652344 L 394.425781 23.835938 L 394.734375 24.035156 L 395.042969 24.25 L 395.351562 24.480469 L 395.65625 24.734375 L 395.964844 25.003906 L 396.273438 25.292969 L 396.582031 25.605469 L 396.890625 25.9375 L 397.195312 26.296875 L 397.503906 26.679688 L 397.8125 27.085938 L 398.121094 27.523438 L 398.425781 27.984375 L 398.734375 28.480469 L 399.042969 29.003906 L 399.351562 29.558594 L 399.660156 30.144531 L 399.964844 30.769531 L 400.273438 31.425781 L 400.582031 32.117188 L 400.890625 32.847656 L 401.195312 33.617188 L 401.503906 34.425781 L 401.8125 35.269531 L 402.121094 36.15625 L 402.429688 37.085938 L 402.734375 38.054688 L 403.042969 39.070312 L 403.351562 40.125 L 403.660156 41.21875 L 403.964844 42.359375 L 404.273438 43.542969 L 404.582031 44.769531 L 404.890625 46.039062 L 405.199219 47.351562 L 405.503906 48.703125 L 405.8125 50.097656 L 406.121094 51.53125 L 406.429688 53.003906 L 406.738281 54.515625 L 407.042969 56.0625 L 407.351562 57.648438 L 407.660156 59.265625 L 407.96875 60.914062 L 408.273438 62.59375 L 408.582031 64.304688 L 408.890625 66.039062 L 409.199219 67.800781 L 409.507812 69.585938 L 409.8125 71.386719 L 410.121094 73.207031 L 410.429688 75.046875 L 410.738281 76.894531 L 411.042969 78.753906 L 411.351562 80.625 L 411.660156 82.5 L 412.277344 86.257812 L 412.582031 88.132812 L 412.890625 90.007812 L 413.199219 91.878906 L 413.507812 93.738281 L 413.8125 95.589844 L 414.121094 97.425781 L 414.429688 99.25 L 414.738281 101.058594 L 415.046875 102.847656 L 415.351562 104.617188 L 415.660156 106.367188 L 415.96875 108.097656 L 416.277344 109.800781 L 416.582031 111.476562 L 416.890625 113.128906 L 417.199219 114.753906 L 417.507812 116.351562 L 417.816406 117.921875 L 418.121094 119.460938 L 418.429688 120.972656 L 418.738281 122.449219 L 419.046875 123.898438 L 419.351562 125.316406 L 419.660156 126.699219 L 419.96875 128.054688 L 420.277344 129.378906 L 420.585938 130.667969 L 420.890625 131.929688 L 421.199219 133.15625 L 421.507812 134.355469 L 421.816406 135.519531 L 422.125 136.65625 L 422.429688 137.761719 L 422.738281 138.839844 L 423.046875 139.882812 L 423.355469 140.902344 L 423.660156 141.890625 L 423.96875 142.851562 L 424.277344 143.785156 L 424.585938 144.691406 L 424.894531 145.570312 L 425.199219 146.425781 L 425.507812 147.253906 L 425.816406 148.054688 L 426.125 148.835938 L 426.429688 149.59375 L 426.738281 150.324219 L 427.046875 151.035156 L 427.355469 151.722656 L 427.664062 152.390625 L 427.96875 153.039062 L 428.277344 153.664062 L 428.585938 154.273438 L 428.894531 154.859375 L 429.199219 155.429688 L 429.507812 155.984375 L 429.816406 156.515625 L 430.125 157.035156 L 430.433594 157.535156 L 430.738281 158.019531 L 431.046875 158.492188 L 431.355469 158.945312 L 431.664062 159.386719 L 431.96875 159.8125 L 432.277344 160.226562 L 432.585938 160.625 L 432.894531 161.011719 L 433.203125 161.386719 L 433.507812 161.75 L 433.816406 162.101562 L 434.125 162.445312 L 434.433594 162.773438 L 434.738281 163.09375 L 435.046875 163.402344 L 435.355469 163.699219 L 435.664062 163.992188 L 435.972656 164.273438 L 436.277344 164.542969 L 436.585938 164.808594 L 436.894531 165.0625 L 437.203125 165.308594 L 437.507812 165.550781 L 437.816406 165.78125 L 438.125 166.007812 L 438.433594 166.222656 L 438.742188 166.433594 L 439.046875 166.640625 L 439.355469 166.839844 L 439.664062 167.03125 L 440.28125 167.398438 L 440.585938 167.574219 L 440.894531 167.742188 L 441.203125 167.90625 L 441.511719 168.066406 L 441.816406 168.222656 L 442.125 168.371094 L 442.742188 168.660156 L 443.050781 168.796875 L 443.355469 168.929688 L 443.664062 169.058594 L 443.972656 169.183594 L 444.28125 169.304688 L 444.585938 169.421875 L 444.894531 169.539062 L 445.511719 169.757812 L 445.820312 169.863281 L 446.125 169.964844 L 446.433594 170.0625 L 447.050781 170.25 L 447.355469 170.34375 L 447.972656 170.515625 L 448.589844 170.679688 L 448.894531 170.757812 L 449.820312 170.980469 L 450.125 171.050781 L 451.050781 171.25 L 451.359375 171.3125 L 451.664062 171.371094 L 451.972656 171.433594 L 452.28125 171.488281 L 452.589844 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="177.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="177.320312"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="177.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="177.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="139.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="139.320312"/>
+ <use xlink:href="#glyph0-3" x="273.594788" y="139.320312"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="139.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="101.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="101.320312"/>
+ <use xlink:href="#glyph0-4" x="273.594788" y="101.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="101.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="63.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="63.320312"/>
+ <use xlink:href="#glyph0-5" x="273.594788" y="63.320312"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="63.320312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="265.59375" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 173.882812 L 291.351562 173.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 135.882812 L 291.351562 135.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 97.882812 L 291.351562 97.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 59.882812 L 291.351562 59.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 21.882812 L 291.351562 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 183.28125 L 299.03125 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 183.28125 L 337.417969 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 183.28125 L 375.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 183.28125 L 414.199219 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 183.28125 L 452.589844 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="258.992188" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="258.992188" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="258.992188" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="258.992188" y="90.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-9" x="248.335938" y="10.800781"/>
+ <use xlink:href="#glyph5-8" x="257.001953" y="10.800781"/>
+ <use xlink:href="#glyph5-7" x="263.675781" y="10.800781"/>
+ <use xlink:href="#glyph5-7" x="267.009766" y="10.800781"/>
+</g>
+<g clip-path="url(#clip41)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 474.667969 216 L 712 216 L 712 0 L 474.667969 0 Z "/>
+</g>
+<g clip-path="url(#clip42)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 216 L 712 216 L 712 0 L 474.667969 0 Z "/>
+</g>
+<g clip-path="url(#clip43)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 179.027344 L 697.597656 179.027344 L 697.597656 14.398438 L 528.683594 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip44)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 152.835938 L 697.601562 152.835938 "/>
+</g>
+<g clip-path="url(#clip45)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 115.421875 L 697.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip46)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 78.007812 L 697.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip47)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 40.589844 L 697.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip48)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 179.027344 L 555.558594 14.398438 "/>
+</g>
+<g clip-path="url(#clip49)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 179.027344 L 593.949219 14.398438 "/>
+</g>
+<g clip-path="url(#clip50)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 179.027344 L 632.335938 14.398438 "/>
+</g>
+<g clip-path="url(#clip51)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 179.027344 L 670.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip52)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 171.546875 L 697.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip53)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 134.128906 L 697.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip54)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 96.714844 L 697.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip55)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 59.296875 L 697.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip56)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 21.882812 L 697.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip57)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 179.027344 L 536.363281 14.398438 "/>
+</g>
+<g clip-path="url(#clip58)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 179.027344 L 574.753906 14.398438 "/>
+</g>
+<g clip-path="url(#clip59)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 179.027344 L 613.140625 14.398438 "/>
+</g>
+<g clip-path="url(#clip60)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 179.027344 L 651.53125 14.398438 "/>
+</g>
+<g clip-path="url(#clip61)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 179.027344 L 689.921875 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 536.363281 171.546875 L 536.671875 171.542969 L 536.976562 171.527344 L 537.285156 171.503906 L 537.59375 171.46875 L 537.902344 171.425781 L 538.210938 171.371094 L 538.515625 171.308594 L 538.824219 171.238281 L 539.132812 171.15625 L 539.441406 171.066406 L 539.746094 170.964844 L 540.054688 170.851562 L 540.363281 170.734375 L 540.671875 170.601562 L 540.980469 170.464844 L 541.285156 170.316406 L 541.59375 170.15625 L 541.902344 169.988281 L 542.210938 169.808594 L 542.515625 169.621094 L 542.824219 169.425781 L 543.132812 169.21875 L 543.441406 169.003906 L 543.75 168.777344 L 544.054688 168.539062 L 544.363281 168.296875 L 544.671875 168.039062 L 544.980469 167.777344 L 545.289062 167.503906 L 545.59375 167.21875 L 545.902344 166.925781 L 546.210938 166.621094 L 546.519531 166.308594 L 546.824219 165.988281 L 547.132812 165.65625 L 547.441406 165.3125 L 547.75 164.964844 L 548.058594 164.601562 L 548.363281 164.230469 L 548.671875 163.851562 L 548.980469 163.460938 L 549.289062 163.0625 L 549.59375 162.65625 L 549.902344 162.238281 L 550.210938 161.808594 L 550.519531 161.371094 L 550.828125 160.925781 L 551.132812 160.46875 L 551.441406 160 L 551.75 159.523438 L 552.058594 159.039062 L 552.363281 158.542969 L 552.671875 158.039062 L 552.980469 157.523438 L 553.289062 157 L 553.597656 156.464844 L 553.902344 155.921875 L 554.210938 155.371094 L 554.519531 154.808594 L 554.828125 154.234375 L 555.132812 153.652344 L 555.441406 153.0625 L 555.75 152.460938 L 556.058594 151.851562 L 556.367188 151.230469 L 556.671875 150.601562 L 556.980469 149.960938 L 557.289062 149.3125 L 557.597656 148.652344 L 557.902344 147.984375 L 558.210938 147.304688 L 558.519531 146.617188 L 558.828125 145.921875 L 559.136719 145.214844 L 559.441406 144.5 L 559.75 143.773438 L 560.058594 143.035156 L 560.367188 142.292969 L 560.671875 141.535156 L 560.980469 140.773438 L 561.289062 139.996094 L 561.597656 139.214844 L 561.90625 138.421875 L 562.210938 137.617188 L 562.519531 136.804688 L 562.828125 135.984375 L 563.136719 135.152344 L 563.445312 134.308594 L 563.75 133.457031 L 564.058594 132.597656 L 564.367188 131.726562 L 564.675781 130.847656 L 564.980469 129.957031 L 565.289062 129.058594 L 565.597656 128.148438 L 565.90625 127.230469 L 566.214844 126.304688 L 566.519531 125.367188 L 566.828125 124.417969 L 567.136719 123.460938 L 567.445312 122.496094 L 567.75 121.519531 L 568.058594 120.53125 L 568.367188 119.539062 L 568.675781 118.53125 L 568.984375 117.519531 L 569.289062 116.492188 L 569.597656 115.460938 L 569.90625 114.417969 L 570.214844 113.363281 L 570.519531 112.300781 L 570.828125 111.230469 L 571.136719 110.148438 L 571.445312 109.054688 L 571.753906 107.953125 L 572.058594 106.84375 L 572.367188 105.722656 L 572.675781 104.59375 L 572.984375 103.453125 L 573.289062 102.304688 L 573.597656 101.144531 L 573.90625 99.976562 L 574.214844 98.796875 L 574.523438 97.609375 L 574.828125 96.414062 L 575.136719 95.222656 L 575.445312 94.039062 L 575.753906 92.867188 L 576.058594 91.703125 L 576.367188 90.546875 L 576.675781 89.402344 L 576.984375 88.269531 L 577.292969 87.144531 L 577.597656 86.027344 L 577.90625 84.921875 L 578.214844 83.824219 L 578.523438 82.738281 L 578.832031 81.660156 L 579.136719 80.59375 L 579.445312 79.535156 L 579.753906 78.488281 L 580.0625 77.449219 L 580.367188 76.421875 L 580.675781 75.402344 L 580.984375 74.390625 L 581.292969 73.390625 L 581.601562 72.402344 L 581.90625 71.417969 L 582.214844 70.449219 L 582.523438 69.488281 L 582.832031 68.535156 L 583.136719 67.59375 L 583.445312 66.660156 L 583.753906 65.734375 L 584.0625 64.824219 L 584.371094 63.917969 L 584.675781 63.023438 L 584.984375 62.140625 L 585.292969 61.265625 L 585.601562 60.398438 L 585.90625 59.542969 L 586.214844 58.695312 L 586.523438 57.859375 L 586.832031 57.03125 L 587.140625 56.214844 L 587.445312 55.40625 L 587.753906 54.609375 L 588.0625 53.820312 L 588.371094 53.042969 L 588.675781 52.273438 L 588.984375 51.511719 L 589.292969 50.761719 L 589.601562 50.023438 L 589.910156 49.292969 L 590.214844 48.570312 L 590.523438 47.859375 L 590.832031 47.15625 L 591.140625 46.464844 L 591.445312 45.78125 L 591.753906 45.109375 L 592.0625 44.445312 L 592.371094 43.789062 L 592.679688 43.144531 L 592.984375 42.511719 L 593.292969 41.886719 L 593.601562 41.269531 L 593.910156 40.664062 L 594.21875 40.070312 L 594.523438 39.480469 L 594.832031 38.90625 L 595.140625 38.335938 L 595.449219 37.78125 L 595.753906 37.230469 L 596.0625 36.691406 L 596.371094 36.164062 L 596.679688 35.644531 L 596.988281 35.136719 L 597.292969 34.636719 L 597.601562 34.144531 L 597.910156 33.664062 L 598.21875 33.191406 L 598.523438 32.730469 L 598.832031 32.277344 L 599.140625 31.835938 L 599.449219 31.402344 L 599.757812 30.980469 L 600.0625 30.566406 L 600.371094 30.164062 L 600.679688 29.769531 L 600.988281 29.382812 L 601.292969 29.007812 L 601.601562 28.644531 L 601.910156 28.289062 L 602.21875 27.941406 L 602.527344 27.605469 L 602.832031 27.277344 L 603.140625 26.960938 L 603.449219 26.652344 L 603.757812 26.355469 L 604.0625 26.066406 L 604.371094 25.789062 L 604.679688 25.519531 L 604.988281 25.257812 L 605.296875 25.007812 L 605.601562 24.769531 L 605.910156 24.539062 L 606.21875 24.316406 L 606.527344 24.105469 L 606.832031 23.902344 L 607.140625 23.710938 L 607.449219 23.527344 L 607.757812 23.355469 L 608.066406 23.191406 L 608.371094 23.039062 L 608.679688 22.894531 L 608.988281 22.757812 L 609.296875 22.632812 L 609.601562 22.519531 L 609.910156 22.410156 L 610.21875 22.316406 L 610.527344 22.230469 L 610.835938 22.152344 L 611.140625 22.085938 L 611.449219 22.027344 L 611.757812 21.980469 L 612.066406 21.941406 L 612.375 21.910156 L 612.679688 21.894531 L 612.988281 21.882812 L 613.296875 21.882812 L 613.605469 21.894531 L 613.910156 21.910156 L 614.21875 21.941406 L 614.527344 21.980469 L 614.835938 22.027344 L 615.144531 22.085938 L 615.449219 22.152344 L 615.757812 22.230469 L 616.066406 22.316406 L 616.375 22.410156 L 616.679688 22.519531 L 616.988281 22.632812 L 617.296875 22.757812 L 617.605469 22.894531 L 617.914062 23.039062 L 618.21875 23.191406 L 618.527344 23.355469 L 618.835938 23.527344 L 619.144531 23.710938 L 619.449219 23.902344 L 619.757812 24.105469 L 620.066406 24.316406 L 620.375 24.539062 L 620.683594 24.769531 L 620.988281 25.007812 L 621.296875 25.257812 L 621.605469 25.519531 L 621.914062 25.789062 L 622.21875 26.066406 L 622.527344 26.355469 L 622.835938 26.652344 L 623.144531 26.960938 L 623.453125 27.277344 L 623.757812 27.605469 L 624.066406 27.941406 L 624.375 28.289062 L 624.683594 28.644531 L 624.988281 29.007812 L 625.296875 29.382812 L 625.605469 29.769531 L 625.914062 30.164062 L 626.222656 30.566406 L 626.527344 30.980469 L 626.835938 31.402344 L 627.144531 31.835938 L 627.453125 32.277344 L 627.761719 32.730469 L 628.066406 33.191406 L 628.375 33.664062 L 628.683594 34.144531 L 628.992188 34.636719 L 629.296875 35.136719 L 629.605469 35.644531 L 629.914062 36.164062 L 630.222656 36.691406 L 630.53125 37.230469 L 630.835938 37.78125 L 631.144531 38.335938 L 631.453125 38.90625 L 631.761719 39.480469 L 632.066406 40.070312 L 632.375 40.664062 L 632.683594 41.269531 L 632.992188 41.886719 L 633.300781 42.511719 L 633.605469 43.144531 L 633.914062 43.789062 L 634.222656 44.445312 L 634.53125 45.109375 L 634.835938 45.78125 L 635.144531 46.464844 L 635.453125 47.15625 L 635.761719 47.859375 L 636.070312 48.570312 L 636.375 49.292969 L 636.683594 50.023438 L 636.992188 50.761719 L 637.300781 51.511719 L 637.605469 52.273438 L 637.914062 53.042969 L 638.222656 53.820312 L 638.53125 54.609375 L 638.839844 55.40625 L 639.144531 56.214844 L 639.453125 57.03125 L 639.761719 57.859375 L 640.070312 58.695312 L 640.375 59.542969 L 640.683594 60.398438 L 640.992188 61.265625 L 641.300781 62.140625 L 641.609375 63.023438 L 641.914062 63.917969 L 642.222656 64.824219 L 642.53125 65.734375 L 642.839844 66.660156 L 643.148438 67.59375 L 643.453125 68.535156 L 643.761719 69.488281 L 644.070312 70.449219 L 644.378906 71.417969 L 644.683594 72.402344 L 644.992188 73.390625 L 645.300781 74.390625 L 645.609375 75.402344 L 645.917969 76.421875 L 646.222656 77.449219 L 646.53125 78.488281 L 646.839844 79.535156 L 647.148438 80.59375 L 647.453125 81.660156 L 647.761719 82.738281 L 648.070312 83.824219 L 648.378906 84.921875 L 648.6875 86.027344 L 648.992188 87.144531 L 649.300781 88.269531 L 649.609375 89.402344 L 649.917969 90.546875 L 650.222656 91.703125 L 650.53125 92.867188 L 650.839844 94.039062 L 651.148438 95.222656 L 651.457031 96.414062 L 651.761719 97.609375 L 652.070312 98.796875 L 652.378906 99.976562 L 652.6875 101.144531 L 652.992188 102.304688 L 653.300781 103.453125 L 653.609375 104.59375 L 653.917969 105.722656 L 654.226562 106.84375 L 654.53125 107.953125 L 654.839844 109.054688 L 655.148438 110.148438 L 655.457031 111.230469 L 655.761719 112.300781 L 656.070312 113.363281 L 656.378906 114.417969 L 656.6875 115.460938 L 656.996094 116.492188 L 657.300781 117.519531 L 657.609375 118.53125 L 657.917969 119.539062 L 658.226562 120.53125 L 658.53125 121.519531 L 658.839844 122.496094 L 659.148438 123.460938 L 659.457031 124.417969 L 659.765625 125.367188 L 660.070312 126.304688 L 660.378906 127.230469 L 660.6875 128.148438 L 660.996094 129.058594 L 661.304688 129.957031 L 661.609375 130.847656 L 661.917969 131.726562 L 662.226562 132.597656 L 662.535156 133.457031 L 662.839844 134.308594 L 663.148438 135.152344 L 663.457031 135.984375 L 663.765625 136.804688 L 664.074219 137.617188 L 664.378906 138.421875 L 664.6875 139.214844 L 664.996094 139.996094 L 665.304688 140.773438 L 665.609375 141.535156 L 665.917969 142.292969 L 666.226562 143.035156 L 666.535156 143.773438 L 666.84375 144.5 L 667.148438 145.214844 L 667.457031 145.921875 L 667.765625 146.617188 L 668.074219 147.304688 L 668.378906 147.984375 L 668.6875 148.652344 L 668.996094 149.3125 L 669.304688 149.960938 L 669.613281 150.601562 L 669.917969 151.230469 L 670.226562 151.851562 L 670.535156 152.460938 L 670.84375 153.0625 L 671.148438 153.652344 L 671.457031 154.234375 L 671.765625 154.808594 L 672.074219 155.371094 L 672.382812 155.921875 L 672.6875 156.464844 L 672.996094 157 L 673.304688 157.523438 L 673.613281 158.039062 L 673.917969 158.542969 L 674.226562 159.039062 L 674.535156 159.523438 L 674.84375 160 L 675.152344 160.46875 L 675.457031 160.925781 L 675.765625 161.371094 L 676.074219 161.808594 L 676.382812 162.238281 L 676.691406 162.65625 L 676.996094 163.0625 L 677.304688 163.460938 L 677.613281 163.851562 L 677.921875 164.230469 L 678.226562 164.601562 L 678.535156 164.964844 L 678.84375 165.3125 L 679.152344 165.65625 L 679.460938 165.988281 L 679.765625 166.308594 L 680.074219 166.621094 L 680.382812 166.925781 L 680.691406 167.21875 L 680.996094 167.503906 L 681.304688 167.777344 L 681.613281 168.039062 L 681.921875 168.296875 L 682.230469 168.539062 L 682.535156 168.777344 L 682.84375 169.003906 L 683.152344 169.21875 L 683.460938 169.425781 L 683.765625 169.621094 L 684.074219 169.808594 L 684.382812 169.988281 L 684.691406 170.15625 L 685 170.316406 L 685.304688 170.464844 L 685.613281 170.601562 L 685.921875 170.734375 L 686.230469 170.851562 L 686.535156 170.964844 L 686.84375 171.066406 L 687.152344 171.15625 L 687.460938 171.238281 L 687.769531 171.308594 L 688.074219 171.371094 L 688.382812 171.425781 L 688.691406 171.46875 L 689 171.503906 L 689.304688 171.527344 L 689.613281 171.542969 L 689.921875 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="510.926819" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="510.926819" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="510.926819" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="502.925781" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 171.546875 L 528.683594 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 134.128906 L 528.683594 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 96.714844 L 528.683594 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 59.296875 L 528.683594 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 21.882812 L 528.683594 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 183.28125 L 536.363281 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 183.28125 L 574.753906 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 183.28125 L 613.140625 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 183.28125 L 651.53125 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 183.28125 L 689.921875 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="496.324219" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.324219" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.324219" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.324219" y="90.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-10" x="498.34375" y="10.800781"/>
+ <use xlink:href="#glyph5-3" x="506.347656" y="10.800781"/>
+ <use xlink:href="#glyph5-11" x="509.681641" y="10.800781"/>
+ <use xlink:href="#glyph5-12" x="517.685547" y="10.800781"/>
+ <use xlink:href="#glyph5-4" x="525.015625" y="10.800781"/>
+ <use xlink:href="#glyph5-13" x="531.689453" y="10.800781"/>
+ <use xlink:href="#glyph5-8" x="539.019531" y="10.800781"/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 432 L 237.332031 432 L 237.332031 216 L 0 216 Z "/>
+<g clip-path="url(#clip62)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 432 L 237.332031 432 L 237.332031 216 L 0 216 Z "/>
+</g>
+<g clip-path="url(#clip63)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 395.027344 L 222.933594 395.027344 L 222.933594 230.398438 L 54.019531 230.398438 Z "/>
+</g>
+<g clip-path="url(#clip64)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 368.839844 L 222.933594 368.839844 "/>
+</g>
+<g clip-path="url(#clip65)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 331.421875 L 222.933594 331.421875 "/>
+</g>
+<g clip-path="url(#clip66)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 294.007812 L 222.933594 294.007812 "/>
+</g>
+<g clip-path="url(#clip67)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 256.589844 L 222.933594 256.589844 "/>
+</g>
+<g clip-path="url(#clip68)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 395.027344 L 80.890625 230.398438 "/>
+</g>
+<g clip-path="url(#clip69)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 395.027344 L 119.28125 230.398438 "/>
+</g>
+<g clip-path="url(#clip70)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 395.027344 L 157.671875 230.398438 "/>
+</g>
+<g clip-path="url(#clip71)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 395.027344 L 196.058594 230.398438 "/>
+</g>
+<g clip-path="url(#clip72)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 387.546875 L 222.933594 387.546875 "/>
+</g>
+<g clip-path="url(#clip73)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 350.128906 L 222.933594 350.128906 "/>
+</g>
+<g clip-path="url(#clip74)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 312.714844 L 222.933594 312.714844 "/>
+</g>
+<g clip-path="url(#clip75)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 275.296875 L 222.933594 275.296875 "/>
+</g>
+<g clip-path="url(#clip76)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 237.882812 L 222.933594 237.882812 "/>
+</g>
+<g clip-path="url(#clip77)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 395.027344 L 61.695312 230.398438 "/>
+</g>
+<g clip-path="url(#clip78)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 395.027344 L 100.085938 230.398438 "/>
+</g>
+<g clip-path="url(#clip79)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 395.027344 L 138.476562 230.398438 "/>
+</g>
+<g clip-path="url(#clip80)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 395.027344 L 176.867188 230.398438 "/>
+</g>
+<g clip-path="url(#clip81)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 395.027344 L 215.253906 230.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 387.546875 L 62.003906 386.347656 L 62.3125 385.144531 L 62.621094 383.945312 L 62.925781 382.746094 L 63.851562 379.148438 L 64.15625 377.949219 L 64.773438 375.550781 L 65.082031 374.347656 L 65.390625 373.148438 L 65.695312 371.949219 L 66.621094 368.351562 L 66.925781 367.152344 L 67.234375 365.953125 L 67.542969 364.75 L 68.160156 362.351562 L 68.464844 361.152344 L 69.390625 357.554688 L 69.695312 356.355469 L 70.003906 355.152344 L 70.929688 351.554688 L 71.234375 350.355469 L 72.160156 346.757812 L 72.46875 345.554688 L 72.773438 344.355469 L 73.699219 340.757812 L 74.003906 339.558594 L 74.621094 337.160156 L 74.929688 335.957031 L 75.238281 334.757812 L 75.542969 333.558594 L 76.46875 329.960938 L 76.773438 328.761719 L 77.082031 327.5625 L 77.390625 326.359375 L 78.007812 323.960938 L 78.3125 322.761719 L 79.238281 319.164062 L 79.542969 317.964844 L 79.851562 316.761719 L 80.777344 313.164062 L 81.082031 311.964844 L 82.007812 308.367188 L 82.3125 307.164062 L 83.546875 302.367188 L 83.851562 301.167969 L 84.46875 298.769531 L 84.777344 297.566406 L 85.082031 296.367188 L 86.316406 291.570312 L 86.621094 290.371094 L 86.929688 289.171875 L 87.238281 287.96875 L 87.855469 285.570312 L 88.160156 284.371094 L 89.085938 280.773438 L 89.390625 279.574219 L 89.699219 278.375 L 90.007812 277.171875 L 90.625 274.773438 L 90.929688 273.574219 L 91.855469 269.976562 L 92.160156 268.777344 L 92.46875 267.574219 L 93.394531 263.976562 L 93.699219 262.777344 L 94.625 259.179688 L 94.929688 257.976562 L 96.164062 253.179688 L 96.46875 251.980469 L 97.085938 249.582031 L 97.394531 248.378906 L 97.699219 247.179688 L 98.933594 242.382812 L 99.238281 241.183594 L 99.546875 239.984375 L 99.855469 238.78125 L 100.164062 237.882812 L 176.789062 237.882812 L 177.097656 238.78125 L 177.402344 239.984375 L 178.636719 244.78125 L 178.941406 245.980469 L 179.558594 248.378906 L 179.867188 249.582031 L 180.171875 250.78125 L 181.40625 255.578125 L 181.710938 256.777344 L 182.019531 257.976562 L 182.328125 259.179688 L 182.636719 260.378906 L 182.941406 261.578125 L 184.175781 266.375 L 184.480469 267.574219 L 184.789062 268.777344 L 185.714844 272.375 L 186.019531 273.574219 L 186.945312 277.171875 L 187.25 278.375 L 188.484375 283.171875 L 188.789062 284.371094 L 189.714844 287.96875 L 190.019531 289.171875 L 191.253906 293.96875 L 191.558594 295.167969 L 192.175781 297.566406 L 192.484375 298.769531 L 192.789062 299.96875 L 194.023438 304.765625 L 194.328125 305.964844 L 194.636719 307.164062 L 194.945312 308.367188 L 195.253906 309.566406 L 195.558594 310.765625 L 196.792969 315.5625 L 197.097656 316.761719 L 197.40625 317.964844 L 198.023438 320.363281 L 198.328125 321.5625 L 199.5625 326.359375 L 199.867188 327.5625 L 201.101562 332.359375 L 201.40625 333.558594 L 202.023438 335.957031 L 202.332031 337.160156 L 202.636719 338.359375 L 203.871094 343.15625 L 204.175781 344.355469 L 204.484375 345.554688 L 204.792969 346.757812 L 205.101562 347.957031 L 205.40625 349.15625 L 206.640625 353.953125 L 206.945312 355.152344 L 207.253906 356.355469 L 207.871094 358.753906 L 208.175781 359.953125 L 209.410156 364.75 L 209.714844 365.953125 L 210.640625 369.550781 L 210.945312 370.75 L 211.871094 374.347656 L 212.179688 375.550781 L 212.484375 376.75 L 213.410156 380.347656 L 213.714844 381.546875 L 214.640625 385.144531 L 214.949219 386.347656 L 215.253906 387.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="390.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="390.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="390.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="390.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="353.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="353.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="353.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="353.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="316.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="316.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="316.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="316.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="278.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="278.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="278.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="278.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="241.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="241.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="241.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="241.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 387.546875 L 54.019531 387.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 350.128906 L 54.019531 350.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 312.714844 L 54.019531 312.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 275.296875 L 54.019531 275.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 237.882812 L 54.019531 237.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 399.28125 L 61.695312 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 399.28125 L 100.085938 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 399.28125 L 138.476562 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 399.28125 L 176.867188 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 399.28125 L 215.253906 395.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="408.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="408.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="408.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="421.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="324.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="317.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="312.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="306.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-1" x="28.335938" y="226.800781"/>
+ <use xlink:href="#glyph5-2" x="35.666016" y="226.800781"/>
+ <use xlink:href="#glyph5-4" x="40.335938" y="226.800781"/>
+ <use xlink:href="#glyph5-13" x="47.009766" y="226.800781"/>
+ <use xlink:href="#glyph5-8" x="54.339844" y="226.800781"/>
+ <use xlink:href="#glyph5-14" x="61.013672" y="226.800781"/>
+ <use xlink:href="#glyph5-15" x="67.013672" y="226.800781"/>
+ <use xlink:href="#glyph5-3" x="74.34375" y="226.800781"/>
+ <use xlink:href="#glyph5-16" x="77.677734" y="226.800781"/>
+</g>
+<g clip-path="url(#clip82)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 432 L 474.664062 432 L 474.664062 216 L 237.332031 216 Z "/>
+</g>
+<g clip-path="url(#clip83)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 432 L 474.664062 432 L 474.664062 216 L 237.332031 216 Z "/>
+</g>
+<g clip-path="url(#clip84)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 395.027344 L 460.265625 395.027344 L 460.265625 230.398438 L 291.351562 230.398438 Z "/>
+</g>
+<g clip-path="url(#clip85)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 368.835938 L 460.265625 368.835938 "/>
+</g>
+<g clip-path="url(#clip86)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 331.421875 L 460.265625 331.421875 "/>
+</g>
+<g clip-path="url(#clip87)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 294.003906 L 460.265625 294.003906 "/>
+</g>
+<g clip-path="url(#clip88)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 256.589844 L 460.265625 256.589844 "/>
+</g>
+<g clip-path="url(#clip89)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 395.027344 L 318.222656 230.398438 "/>
+</g>
+<g clip-path="url(#clip90)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 395.027344 L 356.613281 230.398438 "/>
+</g>
+<g clip-path="url(#clip91)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 395.027344 L 395.003906 230.398438 "/>
+</g>
+<g clip-path="url(#clip92)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 395.027344 L 433.394531 230.398438 "/>
+</g>
+<g clip-path="url(#clip93)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 387.546875 L 460.265625 387.546875 "/>
+</g>
+<g clip-path="url(#clip94)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 350.128906 L 460.265625 350.128906 "/>
+</g>
+<g clip-path="url(#clip95)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 312.714844 L 460.265625 312.714844 "/>
+</g>
+<g clip-path="url(#clip96)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 275.296875 L 460.265625 275.296875 "/>
+</g>
+<g clip-path="url(#clip97)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 237.882812 L 460.265625 237.882812 "/>
+</g>
+<g clip-path="url(#clip98)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 395.027344 L 299.03125 230.398438 "/>
+</g>
+<g clip-path="url(#clip99)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 395.027344 L 337.417969 230.398438 "/>
+</g>
+<g clip-path="url(#clip100)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 395.027344 L 375.808594 230.398438 "/>
+</g>
+<g clip-path="url(#clip101)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 395.027344 L 414.199219 230.398438 "/>
+</g>
+<g clip-path="url(#clip102)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 395.027344 L 452.589844 230.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 387.546875 L 299.335938 387.539062 L 299.644531 387.523438 L 299.953125 387.492188 L 300.261719 387.449219 L 300.566406 387.398438 L 300.875 387.332031 L 301.183594 387.253906 L 301.492188 387.167969 L 301.800781 387.066406 L 302.105469 386.953125 L 302.414062 386.828125 L 302.722656 386.691406 L 303.03125 386.546875 L 303.335938 386.386719 L 303.644531 386.214844 L 303.953125 386.03125 L 304.261719 385.839844 L 304.570312 385.632812 L 304.875 385.414062 L 305.183594 385.183594 L 305.492188 384.945312 L 305.800781 384.691406 L 306.105469 384.429688 L 306.414062 384.15625 L 306.722656 383.867188 L 307.03125 383.570312 L 307.339844 383.261719 L 307.644531 382.941406 L 307.953125 382.613281 L 308.261719 382.269531 L 308.570312 381.917969 L 308.878906 381.554688 L 309.183594 381.179688 L 309.492188 380.792969 L 309.800781 380.394531 L 310.109375 379.988281 L 310.414062 379.570312 L 310.722656 379.140625 L 311.03125 378.703125 L 311.339844 378.253906 L 311.648438 377.792969 L 311.953125 377.324219 L 312.261719 376.84375 L 312.570312 376.351562 L 312.878906 375.851562 L 313.183594 375.339844 L 313.492188 374.820312 L 313.800781 374.289062 L 314.109375 373.75 L 314.417969 373.199219 L 314.722656 372.640625 L 315.03125 372.070312 L 315.339844 371.492188 L 315.648438 370.902344 L 315.953125 370.308594 L 316.261719 369.699219 L 316.570312 369.085938 L 316.878906 368.460938 L 317.1875 367.828125 L 317.492188 367.1875 L 317.800781 366.535156 L 318.109375 365.878906 L 318.417969 365.210938 L 318.722656 364.535156 L 319.03125 363.851562 L 319.339844 363.160156 L 319.648438 362.457031 L 319.957031 361.75 L 320.261719 361.035156 L 320.570312 360.3125 L 320.878906 359.582031 L 321.1875 358.84375 L 321.492188 358.097656 L 321.800781 357.34375 L 322.109375 356.585938 L 322.417969 355.816406 L 322.726562 355.042969 L 323.03125 354.265625 L 323.339844 353.476562 L 323.648438 352.683594 L 323.957031 351.882812 L 324.265625 351.078125 L 324.570312 350.265625 L 324.878906 349.449219 L 325.1875 348.625 L 325.496094 347.792969 L 325.800781 346.960938 L 326.417969 345.273438 L 326.726562 344.421875 L 327.035156 343.566406 L 327.339844 342.707031 L 327.648438 341.839844 L 327.957031 340.96875 L 328.265625 340.09375 L 328.570312 339.214844 L 328.878906 338.332031 L 329.1875 337.445312 L 329.496094 336.554688 L 329.804688 335.660156 L 330.109375 334.761719 L 330.417969 333.859375 L 330.726562 332.953125 L 331.035156 332.042969 L 331.339844 331.132812 L 331.648438 330.21875 L 331.957031 329.300781 L 332.574219 327.457031 L 332.878906 326.53125 L 333.1875 325.605469 L 333.804688 323.746094 L 334.109375 322.8125 L 334.417969 321.878906 L 335.34375 319.066406 L 335.648438 318.128906 L 336.574219 315.304688 L 336.878906 314.363281 L 337.1875 313.421875 L 337.496094 312.476562 L 338.113281 310.59375 L 338.417969 309.652344 L 339.035156 307.769531 L 339.34375 306.832031 L 339.648438 305.890625 L 339.957031 304.953125 L 340.265625 304.019531 L 340.574219 303.082031 L 340.882812 302.148438 L 341.1875 301.21875 L 341.496094 300.285156 L 342.421875 297.507812 L 342.726562 296.585938 L 343.035156 295.667969 L 343.652344 293.839844 L 343.957031 292.929688 L 344.574219 291.117188 L 345.191406 289.320312 L 345.496094 288.425781 L 346.113281 286.652344 L 346.421875 285.773438 L 346.726562 284.894531 L 347.035156 284.023438 L 347.34375 283.15625 L 347.652344 282.292969 L 347.960938 281.433594 L 348.265625 280.578125 L 348.574219 279.730469 L 348.882812 278.886719 L 349.191406 278.050781 L 349.496094 277.21875 L 349.804688 276.390625 L 350.113281 275.570312 L 350.421875 274.753906 L 350.730469 273.945312 L 351.035156 273.144531 L 351.34375 272.347656 L 351.652344 271.554688 L 351.960938 270.773438 L 352.265625 269.996094 L 352.574219 269.226562 L 352.882812 268.460938 L 353.191406 267.707031 L 353.5 266.957031 L 353.804688 266.214844 L 354.113281 265.480469 L 354.421875 264.753906 L 354.730469 264.035156 L 355.035156 263.320312 L 355.34375 262.617188 L 355.652344 261.921875 L 355.960938 261.234375 L 356.269531 260.554688 L 356.574219 259.882812 L 356.882812 259.21875 L 357.191406 258.566406 L 357.5 257.917969 L 357.808594 257.28125 L 358.113281 256.652344 L 358.421875 256.035156 L 358.730469 255.421875 L 359.039062 254.820312 L 359.34375 254.230469 L 359.652344 253.644531 L 359.960938 253.070312 L 360.269531 252.507812 L 360.578125 251.953125 L 360.882812 251.40625 L 361.191406 250.871094 L 361.5 250.347656 L 361.808594 249.832031 L 362.113281 249.324219 L 362.421875 248.828125 L 362.730469 248.34375 L 363.039062 247.867188 L 363.347656 247.402344 L 363.652344 246.949219 L 363.960938 246.503906 L 364.269531 246.070312 L 364.578125 245.648438 L 364.882812 245.234375 L 365.191406 244.832031 L 365.5 244.441406 L 365.808594 244.0625 L 366.117188 243.691406 L 366.421875 243.332031 L 366.730469 242.984375 L 367.039062 242.648438 L 367.347656 242.324219 L 367.652344 242.007812 L 367.960938 241.707031 L 368.269531 241.414062 L 368.578125 241.132812 L 368.886719 240.863281 L 369.191406 240.605469 L 369.5 240.359375 L 369.808594 240.125 L 370.117188 239.902344 L 370.421875 239.691406 L 370.730469 239.492188 L 371.039062 239.300781 L 371.347656 239.125 L 371.65625 238.960938 L 371.960938 238.808594 L 372.269531 238.664062 L 372.578125 238.535156 L 372.886719 238.417969 L 373.195312 238.308594 L 373.5 238.214844 L 373.808594 238.132812 L 374.117188 238.0625 L 374.425781 238 L 374.730469 237.953125 L 375.039062 237.917969 L 375.347656 237.894531 L 375.65625 237.882812 L 375.964844 237.882812 L 376.269531 237.894531 L 376.578125 237.917969 L 376.886719 237.953125 L 377.195312 238 L 377.5 238.0625 L 377.808594 238.132812 L 378.117188 238.214844 L 378.425781 238.308594 L 378.734375 238.417969 L 379.039062 238.535156 L 379.347656 238.664062 L 379.65625 238.808594 L 379.964844 238.960938 L 380.269531 239.125 L 380.578125 239.300781 L 380.886719 239.492188 L 381.195312 239.691406 L 381.503906 239.902344 L 381.808594 240.125 L 382.117188 240.359375 L 382.425781 240.605469 L 382.734375 240.863281 L 383.039062 241.132812 L 383.347656 241.414062 L 383.65625 241.707031 L 383.964844 242.007812 L 384.273438 242.324219 L 384.578125 242.648438 L 384.886719 242.984375 L 385.195312 243.332031 L 385.503906 243.691406 L 385.808594 244.0625 L 386.117188 244.441406 L 386.425781 244.832031 L 386.734375 245.234375 L 387.042969 245.648438 L 387.347656 246.070312 L 387.65625 246.503906 L 387.964844 246.949219 L 388.273438 247.402344 L 388.578125 247.867188 L 388.886719 248.34375 L 389.195312 248.828125 L 389.503906 249.324219 L 389.8125 249.832031 L 390.117188 250.347656 L 390.425781 250.871094 L 390.734375 251.40625 L 391.042969 251.953125 L 391.351562 252.507812 L 391.65625 253.070312 L 391.964844 253.644531 L 392.273438 254.230469 L 392.582031 254.820312 L 392.886719 255.421875 L 393.195312 256.035156 L 393.503906 256.652344 L 393.8125 257.28125 L 394.121094 257.917969 L 394.425781 258.566406 L 394.734375 259.21875 L 395.042969 259.882812 L 395.351562 260.554688 L 395.65625 261.234375 L 395.964844 261.921875 L 396.273438 262.617188 L 396.582031 263.320312 L 396.890625 264.035156 L 397.195312 264.753906 L 397.503906 265.480469 L 397.8125 266.214844 L 398.121094 266.957031 L 398.425781 267.707031 L 398.734375 268.460938 L 399.042969 269.226562 L 399.351562 269.996094 L 399.660156 270.773438 L 399.964844 271.554688 L 400.273438 272.347656 L 400.582031 273.144531 L 400.890625 273.945312 L 401.195312 274.753906 L 401.503906 275.570312 L 401.8125 276.390625 L 402.121094 277.21875 L 402.429688 278.050781 L 402.734375 278.886719 L 403.042969 279.730469 L 403.351562 280.578125 L 403.660156 281.433594 L 403.964844 282.292969 L 404.273438 283.15625 L 404.582031 284.023438 L 404.890625 284.894531 L 405.199219 285.773438 L 405.503906 286.652344 L 406.121094 288.425781 L 406.429688 289.320312 L 406.738281 290.21875 L 407.042969 291.117188 L 407.660156 292.929688 L 407.96875 293.839844 L 408.273438 294.753906 L 408.582031 295.667969 L 408.890625 296.585938 L 409.199219 297.507812 L 409.507812 298.433594 L 409.8125 299.359375 L 410.121094 300.285156 L 410.429688 301.21875 L 410.738281 302.148438 L 411.042969 303.082031 L 411.351562 304.019531 L 411.660156 304.953125 L 411.96875 305.890625 L 412.277344 306.832031 L 412.582031 307.769531 L 413.507812 310.59375 L 413.8125 311.535156 L 414.121094 312.476562 L 414.429688 313.421875 L 415.046875 315.304688 L 415.351562 316.246094 L 415.96875 318.128906 L 416.277344 319.066406 L 416.582031 320.003906 L 417.199219 321.878906 L 417.816406 323.746094 L 418.121094 324.675781 L 418.429688 325.605469 L 419.046875 327.457031 L 419.351562 328.378906 L 419.660156 329.300781 L 419.96875 330.21875 L 420.277344 331.132812 L 420.585938 332.042969 L 420.890625 332.953125 L 421.199219 333.859375 L 421.507812 334.761719 L 421.816406 335.660156 L 422.125 336.554688 L 422.429688 337.445312 L 422.738281 338.332031 L 423.046875 339.214844 L 423.355469 340.09375 L 423.660156 340.96875 L 423.96875 341.839844 L 424.277344 342.707031 L 424.585938 343.566406 L 424.894531 344.421875 L 425.199219 345.273438 L 425.816406 346.960938 L 426.125 347.792969 L 426.429688 348.625 L 426.738281 349.449219 L 427.046875 350.265625 L 427.355469 351.078125 L 427.664062 351.882812 L 427.96875 352.683594 L 428.277344 353.476562 L 428.585938 354.265625 L 428.894531 355.042969 L 429.199219 355.816406 L 429.507812 356.585938 L 429.816406 357.34375 L 430.125 358.097656 L 430.433594 358.84375 L 430.738281 359.582031 L 431.046875 360.3125 L 431.355469 361.035156 L 431.664062 361.75 L 431.96875 362.457031 L 432.277344 363.160156 L 432.585938 363.851562 L 432.894531 364.535156 L 433.203125 365.210938 L 433.507812 365.878906 L 433.816406 366.535156 L 434.125 367.1875 L 434.433594 367.828125 L 434.738281 368.460938 L 435.046875 369.085938 L 435.355469 369.699219 L 435.664062 370.308594 L 435.972656 370.902344 L 436.277344 371.492188 L 436.585938 372.070312 L 436.894531 372.640625 L 437.203125 373.199219 L 437.507812 373.75 L 437.816406 374.289062 L 438.125 374.820312 L 438.433594 375.339844 L 438.742188 375.851562 L 439.046875 376.351562 L 439.355469 376.84375 L 439.664062 377.324219 L 439.972656 377.792969 L 440.28125 378.253906 L 440.585938 378.703125 L 440.894531 379.140625 L 441.203125 379.570312 L 441.511719 379.988281 L 441.816406 380.394531 L 442.125 380.792969 L 442.433594 381.179688 L 442.742188 381.554688 L 443.050781 381.917969 L 443.355469 382.269531 L 443.664062 382.613281 L 443.972656 382.941406 L 444.28125 383.261719 L 444.585938 383.570312 L 444.894531 383.867188 L 445.203125 384.15625 L 445.511719 384.429688 L 445.820312 384.691406 L 446.125 384.945312 L 446.433594 385.183594 L 446.742188 385.414062 L 447.050781 385.632812 L 447.355469 385.839844 L 447.664062 386.03125 L 447.972656 386.214844 L 448.28125 386.386719 L 448.589844 386.546875 L 448.894531 386.691406 L 449.203125 386.828125 L 449.511719 386.953125 L 449.820312 387.066406 L 450.125 387.167969 L 450.433594 387.253906 L 450.742188 387.332031 L 451.050781 387.398438 L 451.359375 387.449219 L 451.664062 387.492188 L 451.972656 387.523438 L 452.28125 387.539062 L 452.589844 387.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="390.984375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="390.984375"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="390.984375"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="390.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="353.566406"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="353.566406"/>
+ <use xlink:href="#glyph0-3" x="273.594788" y="353.566406"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="353.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="316.152344"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="316.152344"/>
+ <use xlink:href="#glyph0-4" x="273.594788" y="316.152344"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="316.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="278.734375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="278.734375"/>
+ <use xlink:href="#glyph0-5" x="273.594788" y="278.734375"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="278.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="265.59375" y="241.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="241.320312"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="241.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="241.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 387.546875 L 291.351562 387.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 350.128906 L 291.351562 350.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 312.714844 L 291.351562 312.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 275.296875 L 291.351562 275.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 237.882812 L 291.351562 237.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 399.28125 L 299.03125 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 399.28125 L 337.417969 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 399.28125 L 375.808594 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 399.28125 L 414.199219 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 399.28125 L 452.589844 395.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="408.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="408.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="408.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="421.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="258.992188" y="324.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="258.992188" y="317.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="258.992188" y="312.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="258.992188" y="306.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-17" x="257.335938" y="226.800781"/>
+ <use xlink:href="#glyph5-15" x="266.001953" y="226.800781"/>
+ <use xlink:href="#glyph5-18" x="273.332031" y="226.800781"/>
+ <use xlink:href="#glyph5-3" x="280.005859" y="226.800781"/>
+ <use xlink:href="#glyph5-5" x="283.339844" y="226.800781"/>
+ <use xlink:href="#glyph5-8" x="290.669922" y="226.800781"/>
+</g>
+<g clip-path="url(#clip103)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 474.667969 432 L 712 432 L 712 216 L 474.667969 216 Z "/>
+</g>
+<g clip-path="url(#clip104)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 432 L 712 432 L 712 216 L 474.667969 216 Z "/>
+</g>
+<g clip-path="url(#clip105)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 395.027344 L 697.597656 395.027344 L 697.597656 230.398438 L 528.683594 230.398438 Z "/>
+</g>
+<g clip-path="url(#clip106)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 369.476562 L 697.601562 369.476562 "/>
+</g>
+<g clip-path="url(#clip107)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 331.292969 L 697.601562 331.292969 "/>
+</g>
+<g clip-path="url(#clip108)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 293.113281 L 697.601562 293.113281 "/>
+</g>
+<g clip-path="url(#clip109)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 254.929688 L 697.601562 254.929688 "/>
+</g>
+<g clip-path="url(#clip110)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 395.027344 L 555.558594 230.398438 "/>
+</g>
+<g clip-path="url(#clip111)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 395.027344 L 593.949219 230.398438 "/>
+</g>
+<g clip-path="url(#clip112)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 395.027344 L 632.335938 230.398438 "/>
+</g>
+<g clip-path="url(#clip113)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 395.027344 L 670.726562 230.398438 "/>
+</g>
+<g clip-path="url(#clip114)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 388.566406 L 697.601562 388.566406 "/>
+</g>
+<g clip-path="url(#clip115)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 350.386719 L 697.601562 350.386719 "/>
+</g>
+<g clip-path="url(#clip116)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 312.203125 L 697.601562 312.203125 "/>
+</g>
+<g clip-path="url(#clip117)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 274.019531 L 697.601562 274.019531 "/>
+</g>
+<g clip-path="url(#clip118)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 235.839844 L 697.601562 235.839844 "/>
+</g>
+<g clip-path="url(#clip119)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 395.027344 L 536.363281 230.398438 "/>
+</g>
+<g clip-path="url(#clip120)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 395.027344 L 574.753906 230.398438 "/>
+</g>
+<g clip-path="url(#clip121)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 395.027344 L 613.140625 230.398438 "/>
+</g>
+<g clip-path="url(#clip122)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 395.027344 L 651.53125 230.398438 "/>
+</g>
+<g clip-path="url(#clip123)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 395.027344 L 689.921875 230.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 536.363281 387.546875 L 536.671875 387.503906 L 536.976562 387.460938 L 537.285156 387.417969 L 537.59375 387.371094 L 538.210938 387.269531 L 538.515625 387.21875 L 538.824219 387.164062 L 539.441406 387.046875 L 539.746094 386.984375 L 540.054688 386.921875 L 540.363281 386.855469 L 540.980469 386.714844 L 541.285156 386.636719 L 541.59375 386.5625 L 541.902344 386.480469 L 542.210938 386.394531 L 542.515625 386.308594 L 542.824219 386.21875 L 543.441406 386.023438 L 543.75 385.921875 L 544.054688 385.816406 L 544.363281 385.707031 L 544.980469 385.472656 L 545.289062 385.347656 L 545.59375 385.21875 L 545.902344 385.085938 L 546.210938 384.945312 L 546.519531 384.800781 L 546.824219 384.652344 L 547.132812 384.496094 L 547.441406 384.332031 L 547.75 384.164062 L 548.058594 383.988281 L 548.363281 383.808594 L 548.671875 383.621094 L 548.980469 383.425781 L 549.289062 383.222656 L 549.59375 383.011719 L 549.902344 382.792969 L 550.210938 382.566406 L 550.519531 382.332031 L 550.828125 382.085938 L 551.132812 381.832031 L 551.441406 381.570312 L 551.75 381.296875 L 552.058594 381.015625 L 552.363281 380.722656 L 552.671875 380.417969 L 552.980469 380.101562 L 553.289062 379.777344 L 553.597656 379.4375 L 553.902344 379.089844 L 554.210938 378.726562 L 554.519531 378.351562 L 554.828125 377.960938 L 555.132812 377.558594 L 555.441406 377.144531 L 555.75 376.710938 L 556.058594 376.265625 L 556.367188 375.804688 L 556.671875 375.328125 L 556.980469 374.835938 L 557.289062 374.328125 L 557.597656 373.800781 L 557.902344 373.257812 L 558.210938 372.695312 L 558.519531 372.117188 L 558.828125 371.519531 L 559.136719 370.902344 L 559.441406 370.265625 L 559.75 369.609375 L 560.058594 368.933594 L 560.367188 368.238281 L 560.671875 367.523438 L 560.980469 366.785156 L 561.289062 366.027344 L 561.597656 365.246094 L 561.90625 364.441406 L 562.210938 363.617188 L 562.519531 362.769531 L 562.828125 361.898438 L 563.136719 361.003906 L 563.445312 360.085938 L 563.75 359.144531 L 564.058594 358.183594 L 564.367188 357.195312 L 564.675781 356.183594 L 564.980469 355.148438 L 565.289062 354.089844 L 565.597656 353.007812 L 565.90625 351.90625 L 566.214844 350.777344 L 566.519531 349.625 L 566.828125 348.449219 L 567.136719 347.253906 L 567.445312 346.035156 L 567.75 344.792969 L 568.058594 343.53125 L 568.367188 342.25 L 568.675781 340.945312 L 568.984375 339.621094 L 569.289062 338.28125 L 569.597656 336.917969 L 569.90625 335.539062 L 570.214844 334.144531 L 570.519531 332.734375 L 570.828125 331.304688 L 571.136719 329.863281 L 571.445312 328.410156 L 571.753906 326.941406 L 572.058594 325.464844 L 572.367188 323.972656 L 572.675781 322.476562 L 572.984375 320.96875 L 573.289062 319.457031 L 573.597656 317.9375 L 573.90625 316.414062 L 574.523438 313.359375 L 574.828125 311.828125 L 575.136719 310.296875 L 575.445312 308.769531 L 575.753906 307.246094 L 576.058594 305.722656 L 576.367188 304.207031 L 576.675781 302.695312 L 576.984375 301.195312 L 577.292969 299.703125 L 577.597656 298.21875 L 577.90625 296.746094 L 578.214844 295.285156 L 578.523438 293.835938 L 578.832031 292.402344 L 579.136719 290.980469 L 579.445312 289.578125 L 579.753906 288.191406 L 580.0625 286.820312 L 580.367188 285.46875 L 580.675781 284.136719 L 580.984375 282.824219 L 581.292969 281.53125 L 581.601562 280.261719 L 581.90625 279.007812 L 582.214844 277.78125 L 582.523438 276.574219 L 582.832031 275.386719 L 583.136719 274.226562 L 583.445312 273.085938 L 583.753906 271.972656 L 584.0625 270.878906 L 584.371094 269.808594 L 584.675781 268.765625 L 584.984375 267.742188 L 585.292969 266.742188 L 585.601562 265.769531 L 585.90625 264.820312 L 586.214844 263.890625 L 586.523438 262.988281 L 586.832031 262.105469 L 587.140625 261.246094 L 587.445312 260.414062 L 587.753906 259.601562 L 588.0625 258.808594 L 588.371094 258.039062 L 588.675781 257.292969 L 588.984375 256.566406 L 589.292969 255.863281 L 589.601562 255.179688 L 589.910156 254.515625 L 590.214844 253.871094 L 590.523438 253.25 L 590.832031 252.644531 L 591.140625 252.058594 L 591.445312 251.488281 L 591.753906 250.941406 L 592.0625 250.40625 L 592.371094 249.894531 L 592.679688 249.394531 L 592.984375 248.914062 L 593.292969 248.445312 L 593.601562 247.996094 L 593.910156 247.5625 L 594.21875 247.140625 L 594.523438 246.734375 L 594.832031 246.34375 L 595.140625 245.964844 L 595.449219 245.601562 L 595.753906 245.25 L 596.0625 244.910156 L 596.371094 244.582031 L 596.679688 244.265625 L 596.988281 243.960938 L 597.292969 243.667969 L 597.601562 243.386719 L 597.910156 243.113281 L 598.21875 242.851562 L 598.523438 242.597656 L 598.832031 242.355469 L 599.140625 242.125 L 599.449219 241.898438 L 599.757812 241.683594 L 600.0625 241.476562 L 600.371094 241.277344 L 600.679688 241.085938 L 600.988281 240.902344 L 601.292969 240.726562 L 601.601562 240.558594 L 601.910156 240.394531 L 602.21875 240.238281 L 602.527344 240.089844 L 602.832031 239.949219 L 603.140625 239.8125 L 603.449219 239.679688 L 603.757812 239.558594 L 604.0625 239.4375 L 604.371094 239.324219 L 604.679688 239.214844 L 604.988281 239.113281 L 605.296875 239.015625 L 605.601562 238.921875 L 605.910156 238.832031 L 606.527344 238.667969 L 606.832031 238.59375 L 607.140625 238.523438 L 607.449219 238.457031 L 607.757812 238.394531 L 608.066406 238.335938 L 608.371094 238.28125 L 608.679688 238.230469 L 608.988281 238.183594 L 609.296875 238.140625 L 609.601562 238.097656 L 609.910156 238.0625 L 610.527344 238 L 610.835938 237.972656 L 611.140625 237.949219 L 611.449219 237.929688 L 611.757812 237.914062 L 612.066406 237.902344 L 612.375 237.894531 L 612.679688 237.886719 L 612.988281 237.882812 L 613.296875 237.882812 L 613.605469 237.886719 L 613.910156 237.894531 L 614.21875 237.902344 L 614.527344 237.914062 L 614.835938 237.929688 L 615.144531 237.949219 L 615.449219 237.972656 L 615.757812 238 L 616.375 238.0625 L 616.679688 238.097656 L 617.296875 238.183594 L 617.605469 238.230469 L 617.914062 238.28125 L 618.21875 238.335938 L 618.527344 238.394531 L 618.835938 238.457031 L 619.144531 238.523438 L 619.449219 238.59375 L 619.757812 238.667969 L 620.375 238.832031 L 620.683594 238.921875 L 620.988281 239.015625 L 621.296875 239.113281 L 621.605469 239.214844 L 621.914062 239.324219 L 622.21875 239.4375 L 622.835938 239.679688 L 623.144531 239.8125 L 623.453125 239.949219 L 623.757812 240.089844 L 624.066406 240.238281 L 624.375 240.394531 L 624.683594 240.558594 L 624.988281 240.726562 L 625.296875 240.902344 L 625.605469 241.085938 L 625.914062 241.277344 L 626.222656 241.476562 L 626.527344 241.683594 L 626.835938 241.898438 L 627.144531 242.125 L 627.453125 242.355469 L 627.761719 242.597656 L 628.066406 242.851562 L 628.375 243.113281 L 628.683594 243.386719 L 628.992188 243.667969 L 629.296875 243.960938 L 629.605469 244.265625 L 629.914062 244.582031 L 630.222656 244.910156 L 630.53125 245.25 L 630.835938 245.601562 L 631.144531 245.964844 L 631.453125 246.34375 L 631.761719 246.734375 L 632.066406 247.140625 L 632.375 247.5625 L 632.683594 247.996094 L 632.992188 248.445312 L 633.300781 248.914062 L 633.605469 249.394531 L 633.914062 249.894531 L 634.222656 250.40625 L 634.53125 250.941406 L 634.835938 251.488281 L 635.144531 252.058594 L 635.453125 252.644531 L 635.761719 253.25 L 636.070312 253.871094 L 636.375 254.515625 L 636.683594 255.179688 L 636.992188 255.863281 L 637.300781 256.566406 L 637.605469 257.292969 L 637.914062 258.039062 L 638.222656 258.808594 L 638.53125 259.601562 L 638.839844 260.414062 L 639.144531 261.246094 L 639.453125 262.105469 L 639.761719 262.988281 L 640.070312 263.890625 L 640.375 264.820312 L 640.683594 265.769531 L 640.992188 266.742188 L 641.300781 267.742188 L 641.609375 268.765625 L 641.914062 269.808594 L 642.222656 270.878906 L 642.53125 271.972656 L 642.839844 273.085938 L 643.148438 274.226562 L 643.453125 275.386719 L 643.761719 276.574219 L 644.070312 277.78125 L 644.378906 279.007812 L 644.683594 280.261719 L 644.992188 281.53125 L 645.300781 282.824219 L 645.609375 284.136719 L 645.917969 285.46875 L 646.222656 286.820312 L 646.53125 288.191406 L 646.839844 289.578125 L 647.148438 290.980469 L 647.453125 292.402344 L 647.761719 293.835938 L 648.070312 295.285156 L 648.378906 296.746094 L 648.6875 298.21875 L 648.992188 299.703125 L 649.300781 301.195312 L 649.609375 302.695312 L 649.917969 304.207031 L 650.222656 305.722656 L 650.839844 308.769531 L 651.148438 310.296875 L 651.457031 311.828125 L 651.761719 313.359375 L 652.378906 316.414062 L 652.6875 317.9375 L 652.992188 319.457031 L 653.300781 320.96875 L 653.609375 322.476562 L 653.917969 323.972656 L 654.226562 325.464844 L 654.53125 326.941406 L 654.839844 328.410156 L 655.148438 329.863281 L 655.457031 331.304688 L 655.761719 332.734375 L 656.070312 334.144531 L 656.378906 335.539062 L 656.6875 336.917969 L 656.996094 338.28125 L 657.300781 339.621094 L 657.609375 340.945312 L 657.917969 342.25 L 658.226562 343.53125 L 658.53125 344.792969 L 658.839844 346.035156 L 659.148438 347.253906 L 659.457031 348.449219 L 659.765625 349.625 L 660.070312 350.777344 L 660.378906 351.90625 L 660.6875 353.007812 L 660.996094 354.089844 L 661.304688 355.148438 L 661.609375 356.183594 L 661.917969 357.195312 L 662.226562 358.183594 L 662.535156 359.144531 L 662.839844 360.085938 L 663.148438 361.003906 L 663.457031 361.898438 L 663.765625 362.769531 L 664.074219 363.617188 L 664.378906 364.441406 L 664.6875 365.246094 L 664.996094 366.027344 L 665.304688 366.785156 L 665.609375 367.523438 L 665.917969 368.238281 L 666.226562 368.933594 L 666.535156 369.609375 L 666.84375 370.265625 L 667.148438 370.902344 L 667.457031 371.519531 L 667.765625 372.117188 L 668.074219 372.695312 L 668.378906 373.257812 L 668.6875 373.800781 L 668.996094 374.328125 L 669.304688 374.835938 L 669.613281 375.328125 L 669.917969 375.804688 L 670.226562 376.265625 L 670.535156 376.710938 L 670.84375 377.144531 L 671.148438 377.558594 L 671.457031 377.960938 L 671.765625 378.351562 L 672.074219 378.726562 L 672.382812 379.089844 L 672.6875 379.4375 L 672.996094 379.777344 L 673.304688 380.101562 L 673.613281 380.417969 L 673.917969 380.722656 L 674.226562 381.015625 L 674.535156 381.296875 L 674.84375 381.570312 L 675.152344 381.832031 L 675.457031 382.085938 L 675.765625 382.332031 L 676.074219 382.566406 L 676.382812 382.792969 L 676.691406 383.011719 L 676.996094 383.222656 L 677.304688 383.425781 L 677.613281 383.621094 L 677.921875 383.808594 L 678.226562 383.988281 L 678.535156 384.164062 L 678.84375 384.332031 L 679.152344 384.496094 L 679.460938 384.652344 L 679.765625 384.800781 L 680.074219 384.945312 L 680.382812 385.085938 L 680.691406 385.21875 L 680.996094 385.347656 L 681.304688 385.472656 L 681.921875 385.707031 L 682.230469 385.816406 L 682.535156 385.921875 L 682.84375 386.023438 L 683.460938 386.21875 L 683.765625 386.308594 L 684.382812 386.480469 L 684.691406 386.5625 L 685 386.636719 L 685.304688 386.714844 L 685.921875 386.855469 L 686.230469 386.921875 L 686.535156 386.984375 L 686.84375 387.046875 L 687.460938 387.164062 L 687.769531 387.21875 L 688.074219 387.269531 L 688.691406 387.371094 L 689 387.417969 L 689.304688 387.460938 L 689.921875 387.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="392.003906"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="392.003906"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="392.003906"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="392.003906"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="353.824219"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="353.824219"/>
+ <use xlink:href="#glyph0-3" x="510.926819" y="353.824219"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="353.824219"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="315.640625"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="315.640625"/>
+ <use xlink:href="#glyph0-4" x="510.926819" y="315.640625"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="315.640625"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="277.457031"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="277.457031"/>
+ <use xlink:href="#glyph0-5" x="510.926819" y="277.457031"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="277.457031"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="502.925781" y="239.277344"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="239.277344"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="239.277344"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="239.277344"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 388.566406 L 528.683594 388.566406 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 350.386719 L 528.683594 350.386719 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 312.203125 L 528.683594 312.203125 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 274.019531 L 528.683594 274.019531 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 235.839844 L 528.683594 235.839844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 399.28125 L 536.363281 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 399.28125 L 574.753906 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 399.28125 L 613.140625 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 399.28125 L 651.53125 395.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 399.28125 L 689.921875 395.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="408.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="408.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="408.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="408.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="408.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="408.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="408.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="421.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="496.324219" y="324.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.324219" y="317.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.324219" y="312.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.324219" y="306.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-11" x="527.675781" y="226.800781"/>
+ <use xlink:href="#glyph5-3" x="535.679688" y="226.800781"/>
+ <use xlink:href="#glyph5-6" x="539.013672" y="226.800781"/>
+ <use xlink:href="#glyph5-19" x="546.34375" y="226.800781"/>
+ <use xlink:href="#glyph5-15" x="557.013672" y="226.800781"/>
+ <use xlink:href="#glyph5-3" x="564.34375" y="226.800781"/>
+ <use xlink:href="#glyph5-16" x="567.677734" y="226.800781"/>
+ <use xlink:href="#glyph5-20" x="575.007812" y="226.800781"/>
+ <use xlink:href="#glyph5-3" x="583.673828" y="226.800781"/>
+ <use xlink:href="#glyph5-21" x="587.007812" y="226.800781"/>
+ <use xlink:href="#glyph5-21" x="591.003906" y="226.800781"/>
+ <use xlink:href="#glyph5-8" x="595" y="226.800781"/>
+ <use xlink:href="#glyph5-2" x="601.673828" y="226.800781"/>
+ <use xlink:href="#glyph5-8" x="606.34375" y="226.800781"/>
+ <use xlink:href="#glyph5-5" x="613.017578" y="226.800781"/>
+ <use xlink:href="#glyph5-22" x="620.347656" y="226.800781"/>
+ <use xlink:href="#glyph5-8" x="627.021484" y="226.800781"/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 648 L 237.332031 648 L 237.332031 432 L 0 432 Z "/>
+<g clip-path="url(#clip124)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 648 L 237.332031 648 L 237.332031 432 L 0 432 Z "/>
+</g>
+<g clip-path="url(#clip125)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 611.027344 L 222.933594 611.027344 L 222.933594 446.398438 L 54.019531 446.398438 Z "/>
+</g>
+<g clip-path="url(#clip126)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 584.839844 L 222.933594 584.839844 "/>
+</g>
+<g clip-path="url(#clip127)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 547.421875 L 222.933594 547.421875 "/>
+</g>
+<g clip-path="url(#clip128)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 510.007812 L 222.933594 510.007812 "/>
+</g>
+<g clip-path="url(#clip129)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 472.589844 L 222.933594 472.589844 "/>
+</g>
+<g clip-path="url(#clip130)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 611.027344 L 80.890625 446.398438 "/>
+</g>
+<g clip-path="url(#clip131)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 611.027344 L 119.28125 446.398438 "/>
+</g>
+<g clip-path="url(#clip132)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 611.027344 L 157.671875 446.398438 "/>
+</g>
+<g clip-path="url(#clip133)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 611.027344 L 196.058594 446.398438 "/>
+</g>
+<g clip-path="url(#clip134)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 603.546875 L 222.933594 603.546875 "/>
+</g>
+<g clip-path="url(#clip135)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 566.128906 L 222.933594 566.128906 "/>
+</g>
+<g clip-path="url(#clip136)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 528.714844 L 222.933594 528.714844 "/>
+</g>
+<g clip-path="url(#clip137)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 491.296875 L 222.933594 491.296875 "/>
+</g>
+<g clip-path="url(#clip138)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 453.882812 L 222.933594 453.882812 "/>
+</g>
+<g clip-path="url(#clip139)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 611.027344 L 61.695312 446.398438 "/>
+</g>
+<g clip-path="url(#clip140)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 611.027344 L 100.085938 446.398438 "/>
+</g>
+<g clip-path="url(#clip141)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 611.027344 L 138.476562 446.398438 "/>
+</g>
+<g clip-path="url(#clip142)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 611.027344 L 176.867188 446.398438 "/>
+</g>
+<g clip-path="url(#clip143)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 611.027344 L 215.253906 446.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 603.546875 L 99.855469 603.546875 L 100.164062 453.882812 L 176.789062 453.882812 L 177.097656 603.546875 L 215.253906 603.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="606.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="606.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="606.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="606.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="569.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="569.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="569.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="569.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="532.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="532.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="532.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="532.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="494.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="494.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="494.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="494.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="457.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="457.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="457.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="457.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 603.546875 L 54.019531 603.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 566.128906 L 54.019531 566.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 528.714844 L 54.019531 528.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 491.296875 L 54.019531 491.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 453.882812 L 54.019531 453.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 615.28125 L 61.695312 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 615.28125 L 100.085938 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 615.28125 L 138.476562 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 615.28125 L 176.867188 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 615.28125 L 215.253906 611.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="624.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="624.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="624.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="637.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="540.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="533.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="528.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="522.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-23" x="28.675781" y="442.800781"/>
+ <use xlink:href="#glyph5-8" x="37.341797" y="442.800781"/>
+ <use xlink:href="#glyph5-22" x="44.015625" y="442.800781"/>
+ <use xlink:href="#glyph5-24" x="50.689453" y="442.800781"/>
+ <use xlink:href="#glyph5-4" x="54.685547" y="442.800781"/>
+ <use xlink:href="#glyph5-5" x="61.359375" y="442.800781"/>
+ <use xlink:href="#glyph5-6" x="68.689453" y="442.800781"/>
+ <use xlink:href="#glyph5-7" x="76.019531" y="442.800781"/>
+ <use xlink:href="#glyph5-8" x="79.353516" y="442.800781"/>
+</g>
+<g clip-path="url(#clip144)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 648 L 474.664062 648 L 474.664062 432 L 237.332031 432 Z "/>
+</g>
+<g clip-path="url(#clip145)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 648 L 474.664062 648 L 474.664062 432 L 237.332031 432 Z "/>
+</g>
+<g clip-path="url(#clip146)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 611.027344 L 460.265625 611.027344 L 460.265625 446.398438 L 291.351562 446.398438 Z "/>
+</g>
+<g clip-path="url(#clip147)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 590.855469 L 460.265625 590.855469 "/>
+</g>
+<g clip-path="url(#clip148)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 551.71875 L 460.265625 551.71875 "/>
+</g>
+<g clip-path="url(#clip149)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 512.585938 L 460.265625 512.585938 "/>
+</g>
+<g clip-path="url(#clip150)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 473.449219 L 460.265625 473.449219 "/>
+</g>
+<g clip-path="url(#clip151)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 611.027344 L 318.222656 446.398438 "/>
+</g>
+<g clip-path="url(#clip152)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 611.027344 L 356.613281 446.398438 "/>
+</g>
+<g clip-path="url(#clip153)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 611.027344 L 395.003906 446.398438 "/>
+</g>
+<g clip-path="url(#clip154)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 611.027344 L 433.394531 446.398438 "/>
+</g>
+<g clip-path="url(#clip155)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 610.425781 L 460.265625 610.425781 "/>
+</g>
+<g clip-path="url(#clip156)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 571.289062 L 460.265625 571.289062 "/>
+</g>
+<g clip-path="url(#clip157)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 532.152344 L 460.265625 532.152344 "/>
+</g>
+<g clip-path="url(#clip158)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 493.015625 L 460.265625 493.015625 "/>
+</g>
+<g clip-path="url(#clip159)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 453.882812 L 460.265625 453.882812 "/>
+</g>
+<g clip-path="url(#clip160)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 611.027344 L 299.03125 446.398438 "/>
+</g>
+<g clip-path="url(#clip161)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 611.027344 L 337.417969 446.398438 "/>
+</g>
+<g clip-path="url(#clip162)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 611.027344 L 375.808594 446.398438 "/>
+</g>
+<g clip-path="url(#clip163)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 611.027344 L 414.199219 446.398438 "/>
+</g>
+<g clip-path="url(#clip164)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 611.027344 L 452.589844 446.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 603.546875 L 299.335938 603.371094 L 299.644531 603.195312 L 300.261719 602.828125 L 300.566406 602.636719 L 300.875 602.445312 L 301.492188 602.046875 L 301.800781 601.839844 L 302.105469 601.632812 L 302.414062 601.417969 L 303.03125 600.980469 L 303.335938 600.753906 L 303.953125 600.285156 L 304.261719 600.046875 L 304.570312 599.800781 L 304.875 599.550781 L 305.183594 599.296875 L 305.492188 599.039062 L 305.800781 598.777344 L 306.105469 598.507812 L 306.414062 598.234375 L 306.722656 597.957031 L 307.03125 597.671875 L 307.339844 597.382812 L 307.644531 597.089844 L 307.953125 596.789062 L 308.261719 596.484375 L 308.570312 596.175781 L 308.878906 595.859375 L 309.183594 595.539062 L 309.492188 595.214844 L 309.800781 594.882812 L 310.109375 594.542969 L 310.414062 594.199219 L 310.722656 593.851562 L 311.03125 593.496094 L 311.339844 593.136719 L 311.648438 592.769531 L 311.953125 592.398438 L 312.261719 592.019531 L 312.570312 591.632812 L 312.878906 591.242188 L 313.183594 590.847656 L 313.800781 590.035156 L 314.109375 589.617188 L 314.417969 589.195312 L 314.722656 588.765625 L 315.03125 588.332031 L 315.339844 587.890625 L 315.648438 587.441406 L 315.953125 586.988281 L 316.261719 586.527344 L 316.570312 586.058594 L 316.878906 585.585938 L 317.1875 585.105469 L 317.492188 584.617188 L 317.800781 584.125 L 318.109375 583.621094 L 318.417969 583.113281 L 318.722656 582.597656 L 319.03125 582.078125 L 319.339844 581.550781 L 319.648438 581.015625 L 319.957031 580.472656 L 320.261719 579.921875 L 320.570312 579.367188 L 320.878906 578.804688 L 321.1875 578.234375 L 321.492188 577.65625 L 321.800781 577.070312 L 322.109375 576.480469 L 322.417969 575.882812 L 322.726562 575.277344 L 323.03125 574.664062 L 323.339844 574.046875 L 323.648438 573.417969 L 323.957031 572.785156 L 324.265625 572.144531 L 324.570312 571.5 L 324.878906 570.84375 L 325.1875 570.183594 L 325.496094 569.515625 L 325.800781 568.839844 L 326.109375 568.15625 L 326.417969 567.46875 L 326.726562 566.773438 L 327.035156 566.070312 L 327.339844 565.363281 L 327.648438 564.644531 L 327.957031 563.921875 L 328.265625 563.195312 L 328.570312 562.457031 L 328.878906 561.714844 L 329.1875 560.964844 L 329.496094 560.210938 L 329.804688 559.449219 L 330.109375 558.679688 L 330.417969 557.90625 L 330.726562 557.125 L 331.035156 556.339844 L 331.339844 555.546875 L 331.648438 554.746094 L 331.957031 553.941406 L 332.265625 553.128906 L 332.574219 552.3125 L 332.878906 551.488281 L 333.1875 550.660156 L 333.496094 549.828125 L 333.804688 548.988281 L 334.109375 548.144531 L 334.417969 547.292969 L 334.726562 546.4375 L 335.035156 545.578125 L 335.34375 544.714844 L 335.648438 543.84375 L 335.957031 542.96875 L 336.265625 542.089844 L 336.574219 541.207031 L 336.878906 540.316406 L 337.1875 539.425781 L 337.804688 537.628906 L 338.113281 536.722656 L 338.417969 535.816406 L 339.035156 533.988281 L 339.34375 533.070312 L 339.648438 532.148438 L 339.957031 531.222656 L 340.574219 529.363281 L 340.882812 528.429688 L 341.1875 527.496094 L 341.496094 526.558594 L 342.421875 523.734375 L 342.726562 522.789062 L 343.035156 521.839844 L 343.34375 520.894531 L 343.652344 519.945312 L 343.957031 518.996094 L 344.265625 518.042969 L 344.574219 517.09375 L 344.882812 516.140625 L 345.191406 515.191406 L 345.496094 514.238281 L 345.804688 513.289062 L 346.113281 512.335938 L 346.421875 511.386719 L 346.726562 510.4375 L 347.035156 509.492188 L 347.34375 508.542969 L 347.960938 506.652344 L 348.265625 505.710938 L 349.191406 502.898438 L 349.496094 501.96875 L 350.113281 500.109375 L 350.421875 499.1875 L 350.730469 498.269531 L 351.035156 497.351562 L 351.34375 496.441406 L 351.960938 494.628906 L 352.265625 493.730469 L 352.574219 492.835938 L 352.882812 491.949219 L 353.191406 491.066406 L 353.5 490.1875 L 353.804688 489.316406 L 354.113281 488.449219 L 354.421875 487.589844 L 354.730469 486.734375 L 355.035156 485.886719 L 355.34375 485.046875 L 355.652344 484.210938 L 355.960938 483.386719 L 356.269531 482.566406 L 356.574219 481.757812 L 356.882812 480.953125 L 357.191406 480.15625 L 357.5 479.371094 L 357.808594 478.589844 L 358.113281 477.820312 L 358.421875 477.0625 L 358.730469 476.308594 L 359.039062 475.566406 L 359.34375 474.832031 L 359.652344 474.109375 L 359.960938 473.394531 L 360.269531 472.691406 L 360.578125 472 L 360.882812 471.316406 L 361.191406 470.644531 L 361.5 469.984375 L 361.808594 469.332031 L 362.113281 468.695312 L 362.421875 468.066406 L 362.730469 467.449219 L 363.039062 466.847656 L 363.347656 466.253906 L 363.652344 465.675781 L 363.960938 465.105469 L 364.269531 464.550781 L 364.578125 464.007812 L 364.882812 463.476562 L 365.191406 462.960938 L 365.5 462.457031 L 365.808594 461.964844 L 366.117188 461.488281 L 366.421875 461.023438 L 366.730469 460.574219 L 367.039062 460.136719 L 367.347656 459.710938 L 367.652344 459.304688 L 367.960938 458.910156 L 368.269531 458.527344 L 368.578125 458.160156 L 368.886719 457.808594 L 369.191406 457.472656 L 369.5 457.148438 L 369.808594 456.839844 L 370.117188 456.546875 L 370.421875 456.269531 L 370.730469 456.007812 L 371.039062 455.757812 L 371.347656 455.523438 L 371.65625 455.308594 L 371.960938 455.105469 L 372.269531 454.917969 L 372.578125 454.746094 L 372.886719 454.589844 L 373.195312 454.449219 L 373.5 454.324219 L 373.808594 454.210938 L 374.117188 454.117188 L 374.425781 454.039062 L 374.730469 453.976562 L 375.039062 453.929688 L 375.347656 453.898438 L 375.65625 453.882812 L 375.964844 453.882812 L 376.269531 453.898438 L 376.578125 453.929688 L 376.886719 453.976562 L 377.195312 454.039062 L 377.5 454.117188 L 377.808594 454.210938 L 378.117188 454.324219 L 378.425781 454.449219 L 378.734375 454.589844 L 379.039062 454.746094 L 379.347656 454.917969 L 379.65625 455.105469 L 379.964844 455.308594 L 380.269531 455.523438 L 380.578125 455.757812 L 380.886719 456.007812 L 381.195312 456.269531 L 381.503906 456.546875 L 381.808594 456.839844 L 382.117188 457.148438 L 382.425781 457.472656 L 382.734375 457.808594 L 383.039062 458.160156 L 383.347656 458.527344 L 383.65625 458.910156 L 383.964844 459.304688 L 384.273438 459.710938 L 384.578125 460.136719 L 384.886719 460.574219 L 385.195312 461.023438 L 385.503906 461.488281 L 385.808594 461.964844 L 386.117188 462.457031 L 386.425781 462.960938 L 386.734375 463.476562 L 387.042969 464.007812 L 387.347656 464.550781 L 387.65625 465.105469 L 387.964844 465.675781 L 388.273438 466.253906 L 388.578125 466.847656 L 388.886719 467.449219 L 389.195312 468.066406 L 389.503906 468.695312 L 389.8125 469.332031 L 390.117188 469.984375 L 390.425781 470.644531 L 390.734375 471.316406 L 391.042969 472 L 391.351562 472.691406 L 391.65625 473.394531 L 391.964844 474.109375 L 392.273438 474.832031 L 392.582031 475.566406 L 392.886719 476.308594 L 393.195312 477.0625 L 393.503906 477.820312 L 393.8125 478.589844 L 394.121094 479.371094 L 394.425781 480.15625 L 394.734375 480.953125 L 395.042969 481.757812 L 395.351562 482.566406 L 395.65625 483.386719 L 395.964844 484.210938 L 396.273438 485.046875 L 396.582031 485.886719 L 396.890625 486.734375 L 397.195312 487.589844 L 397.503906 488.449219 L 397.8125 489.316406 L 398.121094 490.1875 L 398.425781 491.066406 L 398.734375 491.949219 L 399.042969 492.835938 L 399.351562 493.730469 L 399.660156 494.628906 L 399.964844 495.535156 L 400.273438 496.441406 L 400.582031 497.351562 L 400.890625 498.269531 L 401.195312 499.1875 L 401.503906 500.109375 L 402.429688 502.898438 L 402.734375 503.835938 L 403.351562 505.710938 L 403.660156 506.652344 L 403.964844 507.597656 L 404.273438 508.542969 L 404.582031 509.492188 L 404.890625 510.4375 L 405.199219 511.386719 L 405.503906 512.335938 L 405.8125 513.289062 L 406.121094 514.238281 L 406.429688 515.191406 L 406.738281 516.140625 L 407.042969 517.09375 L 407.351562 518.042969 L 407.660156 518.996094 L 407.96875 519.945312 L 408.273438 520.894531 L 408.582031 521.839844 L 408.890625 522.789062 L 409.199219 523.734375 L 409.507812 524.675781 L 409.8125 525.617188 L 410.121094 526.558594 L 410.429688 527.496094 L 410.738281 528.429688 L 411.042969 529.363281 L 411.660156 531.222656 L 411.96875 532.148438 L 412.277344 533.070312 L 412.582031 533.988281 L 413.199219 535.816406 L 413.507812 536.722656 L 413.8125 537.628906 L 414.429688 539.425781 L 415.046875 541.207031 L 415.351562 542.089844 L 415.660156 542.96875 L 415.96875 543.84375 L 416.277344 544.714844 L 416.582031 545.578125 L 416.890625 546.4375 L 417.199219 547.292969 L 417.507812 548.144531 L 417.816406 548.988281 L 418.121094 549.828125 L 418.429688 550.660156 L 418.738281 551.488281 L 419.046875 552.3125 L 419.351562 553.128906 L 419.660156 553.941406 L 419.96875 554.746094 L 420.277344 555.546875 L 420.585938 556.339844 L 420.890625 557.125 L 421.199219 557.90625 L 421.507812 558.679688 L 421.816406 559.449219 L 422.125 560.210938 L 422.429688 560.964844 L 422.738281 561.714844 L 423.046875 562.457031 L 423.355469 563.195312 L 423.660156 563.921875 L 423.96875 564.644531 L 424.277344 565.363281 L 424.585938 566.070312 L 424.894531 566.773438 L 425.199219 567.46875 L 425.507812 568.15625 L 425.816406 568.839844 L 426.125 569.515625 L 426.429688 570.183594 L 426.738281 570.84375 L 427.046875 571.5 L 427.355469 572.144531 L 427.664062 572.785156 L 427.96875 573.417969 L 428.277344 574.046875 L 428.585938 574.664062 L 428.894531 575.277344 L 429.199219 575.882812 L 429.507812 576.480469 L 429.816406 577.070312 L 430.125 577.65625 L 430.433594 578.234375 L 430.738281 578.804688 L 431.046875 579.367188 L 431.355469 579.921875 L 431.664062 580.472656 L 431.96875 581.015625 L 432.277344 581.550781 L 432.585938 582.078125 L 432.894531 582.597656 L 433.203125 583.113281 L 433.507812 583.621094 L 433.816406 584.125 L 434.125 584.617188 L 434.433594 585.105469 L 434.738281 585.585938 L 435.046875 586.058594 L 435.355469 586.527344 L 435.664062 586.988281 L 435.972656 587.441406 L 436.277344 587.890625 L 436.585938 588.332031 L 436.894531 588.765625 L 437.203125 589.195312 L 437.507812 589.617188 L 437.816406 590.035156 L 438.433594 590.847656 L 438.742188 591.242188 L 439.046875 591.632812 L 439.355469 592.019531 L 439.664062 592.398438 L 439.972656 592.769531 L 440.28125 593.136719 L 440.585938 593.496094 L 440.894531 593.851562 L 441.203125 594.199219 L 441.511719 594.542969 L 441.816406 594.882812 L 442.125 595.214844 L 442.433594 595.539062 L 442.742188 595.859375 L 443.050781 596.175781 L 443.355469 596.484375 L 443.664062 596.789062 L 443.972656 597.089844 L 444.28125 597.382812 L 444.585938 597.671875 L 444.894531 597.957031 L 445.203125 598.234375 L 445.511719 598.507812 L 445.820312 598.777344 L 446.125 599.039062 L 446.433594 599.296875 L 446.742188 599.550781 L 447.050781 599.800781 L 447.355469 600.046875 L 447.664062 600.285156 L 448.28125 600.753906 L 448.589844 600.980469 L 448.894531 601.199219 L 449.203125 601.417969 L 449.511719 601.632812 L 449.820312 601.839844 L 450.125 602.046875 L 450.742188 602.445312 L 451.359375 602.828125 L 451.664062 603.011719 L 451.972656 603.195312 L 452.589844 603.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="613.863281"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="613.863281"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="613.863281"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="613.863281"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="574.726562"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="574.726562"/>
+ <use xlink:href="#glyph0-3" x="273.594788" y="574.726562"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="574.726562"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="535.589844"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="535.589844"/>
+ <use xlink:href="#glyph0-4" x="273.594788" y="535.589844"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="535.589844"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="496.453125"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="496.453125"/>
+ <use xlink:href="#glyph0-5" x="273.594788" y="496.453125"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="496.453125"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="265.59375" y="457.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="457.320312"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="457.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="457.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 610.425781 L 291.351562 610.425781 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 571.289062 L 291.351562 571.289062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 532.152344 L 291.351562 532.152344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 493.015625 L 291.351562 493.015625 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 453.882812 L 291.351562 453.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 615.28125 L 299.03125 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 615.28125 L 337.417969 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 615.28125 L 375.808594 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 615.28125 L 414.199219 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 615.28125 L 452.589844 611.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="624.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="624.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="624.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="637.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="258.992188" y="540.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="258.992188" y="533.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="258.992188" y="528.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="258.992188" y="522.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-25" x="264.34375" y="442.800781"/>
+ <use xlink:href="#glyph5-4" x="273.677734" y="442.800781"/>
+ <use xlink:href="#glyph5-26" x="280.351562" y="442.800781"/>
+ <use xlink:href="#glyph5-18" x="287.681641" y="442.800781"/>
+ <use xlink:href="#glyph5-18" x="294.355469" y="442.800781"/>
+ <use xlink:href="#glyph5-3" x="301.029297" y="442.800781"/>
+ <use xlink:href="#glyph5-4" x="304.363281" y="442.800781"/>
+ <use xlink:href="#glyph5-5" x="311.037109" y="442.800781"/>
+</g>
+<g clip-path="url(#clip165)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 474.667969 648 L 712 648 L 712 432 L 474.667969 432 Z "/>
+</g>
+<g clip-path="url(#clip166)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 648 L 712 648 L 712 432 L 474.667969 432 Z "/>
+</g>
+<g clip-path="url(#clip167)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 611.027344 L 697.597656 611.027344 L 697.597656 446.398438 L 528.683594 446.398438 Z "/>
+</g>
+<g clip-path="url(#clip168)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 598.894531 L 697.601562 598.894531 "/>
+</g>
+<g clip-path="url(#clip169)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 560.433594 L 697.601562 560.433594 "/>
+</g>
+<g clip-path="url(#clip170)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 521.96875 L 697.601562 521.96875 "/>
+</g>
+<g clip-path="url(#clip171)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 483.503906 L 697.601562 483.503906 "/>
+</g>
+<g clip-path="url(#clip172)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 611.027344 L 555.558594 446.398438 "/>
+</g>
+<g clip-path="url(#clip173)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 611.027344 L 593.949219 446.398438 "/>
+</g>
+<g clip-path="url(#clip174)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 611.027344 L 632.335938 446.398438 "/>
+</g>
+<g clip-path="url(#clip175)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 611.027344 L 670.726562 446.398438 "/>
+</g>
+<g clip-path="url(#clip176)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 579.664062 L 697.601562 579.664062 "/>
+</g>
+<g clip-path="url(#clip177)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 541.199219 L 697.601562 541.199219 "/>
+</g>
+<g clip-path="url(#clip178)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 502.738281 L 697.601562 502.738281 "/>
+</g>
+<g clip-path="url(#clip179)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 464.273438 L 697.601562 464.273438 "/>
+</g>
+<g clip-path="url(#clip180)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 611.027344 L 536.363281 446.398438 "/>
+</g>
+<g clip-path="url(#clip181)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 611.027344 L 574.753906 446.398438 "/>
+</g>
+<g clip-path="url(#clip182)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 611.027344 L 613.140625 446.398438 "/>
+</g>
+<g clip-path="url(#clip183)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 611.027344 L 651.53125 446.398438 "/>
+</g>
+<g clip-path="url(#clip184)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 611.027344 L 689.921875 446.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 536.363281 603.546875 L 536.671875 603.273438 L 536.976562 602.996094 L 537.285156 602.714844 L 537.59375 602.429688 L 538.210938 601.84375 L 538.515625 601.539062 L 538.824219 601.234375 L 539.132812 600.925781 L 539.441406 600.609375 L 539.746094 600.285156 L 540.054688 599.960938 L 540.363281 599.628906 L 540.671875 599.289062 L 540.980469 598.945312 L 541.285156 598.597656 L 541.59375 598.246094 L 542.210938 597.519531 L 542.515625 597.148438 L 542.824219 596.769531 L 543.132812 596.386719 L 543.441406 596 L 543.75 595.605469 L 544.054688 595.203125 L 544.363281 594.796875 L 544.671875 594.382812 L 544.980469 593.960938 L 545.289062 593.535156 L 545.59375 593.105469 L 545.902344 592.664062 L 546.210938 592.21875 L 546.519531 591.769531 L 546.824219 591.308594 L 547.132812 590.84375 L 547.441406 590.371094 L 547.75 589.894531 L 548.058594 589.40625 L 548.363281 588.914062 L 548.671875 588.417969 L 548.980469 587.910156 L 549.289062 587.398438 L 549.59375 586.878906 L 549.902344 586.351562 L 550.210938 585.816406 L 550.519531 585.273438 L 550.828125 584.726562 L 551.132812 584.171875 L 551.441406 583.609375 L 551.75 583.039062 L 552.058594 582.460938 L 552.363281 581.875 L 552.671875 581.285156 L 552.980469 580.6875 L 553.289062 580.078125 L 553.597656 579.464844 L 553.902344 578.84375 L 554.210938 578.214844 L 554.519531 577.582031 L 554.828125 576.9375 L 555.132812 576.285156 L 555.441406 575.628906 L 555.75 574.964844 L 556.058594 574.292969 L 556.367188 573.613281 L 556.671875 572.925781 L 556.980469 572.230469 L 557.289062 571.527344 L 557.597656 570.820312 L 557.902344 570.105469 L 558.210938 569.382812 L 558.519531 568.652344 L 558.828125 567.914062 L 559.136719 567.171875 L 559.441406 566.417969 L 559.75 565.660156 L 560.058594 564.898438 L 560.367188 564.125 L 560.671875 563.347656 L 560.980469 562.5625 L 561.289062 561.773438 L 561.597656 560.976562 L 561.90625 560.171875 L 562.210938 559.359375 L 562.519531 558.542969 L 562.828125 557.722656 L 563.136719 556.894531 L 563.445312 556.058594 L 563.75 555.21875 L 564.058594 554.375 L 564.367188 553.523438 L 564.675781 552.667969 L 564.980469 551.804688 L 565.289062 550.9375 L 565.597656 550.066406 L 566.214844 548.308594 L 566.519531 547.421875 L 566.828125 546.53125 L 567.136719 545.636719 L 567.445312 544.738281 L 567.75 543.832031 L 568.058594 542.925781 L 568.367188 542.015625 L 568.984375 540.1875 L 569.289062 539.265625 L 569.597656 538.34375 L 569.90625 537.414062 L 570.214844 536.488281 L 570.519531 535.554688 L 571.136719 533.6875 L 571.753906 531.8125 L 572.058594 530.871094 L 572.675781 528.988281 L 572.984375 528.042969 L 573.289062 527.101562 L 574.523438 523.320312 L 574.828125 522.375 L 575.136719 521.433594 L 575.445312 520.488281 L 575.753906 519.546875 L 576.058594 518.605469 L 576.984375 515.792969 L 577.292969 514.859375 L 577.597656 513.925781 L 577.90625 512.996094 L 578.523438 511.144531 L 578.832031 510.226562 L 579.136719 509.308594 L 579.445312 508.390625 L 579.753906 507.480469 L 580.0625 506.574219 L 580.367188 505.671875 L 580.675781 504.769531 L 580.984375 503.875 L 581.292969 502.984375 L 581.601562 502.101562 L 581.90625 501.21875 L 582.214844 500.34375 L 582.523438 499.472656 L 582.832031 498.605469 L 583.136719 497.746094 L 583.753906 496.042969 L 584.0625 495.203125 L 584.371094 494.367188 L 584.675781 493.535156 L 584.984375 492.710938 L 585.292969 491.894531 L 585.601562 491.085938 L 585.90625 490.28125 L 586.214844 489.484375 L 586.523438 488.695312 L 586.832031 487.914062 L 587.140625 487.140625 L 587.445312 486.371094 L 587.753906 485.613281 L 588.0625 484.859375 L 588.371094 484.117188 L 588.675781 483.378906 L 588.984375 482.652344 L 589.292969 481.929688 L 589.601562 481.21875 L 589.910156 480.515625 L 590.214844 479.820312 L 590.523438 479.132812 L 590.832031 478.453125 L 591.140625 477.78125 L 591.445312 477.121094 L 591.753906 476.46875 L 592.0625 475.824219 L 592.371094 475.191406 L 592.679688 474.5625 L 592.984375 473.945312 L 593.292969 473.335938 L 593.601562 472.738281 L 593.910156 472.148438 L 594.21875 471.566406 L 594.523438 470.996094 L 594.832031 470.433594 L 595.140625 469.878906 L 595.449219 469.335938 L 595.753906 468.800781 L 596.0625 468.273438 L 596.371094 467.757812 L 596.679688 467.25 L 596.988281 466.753906 L 597.292969 466.265625 L 597.601562 465.785156 L 597.910156 465.316406 L 598.21875 464.855469 L 598.523438 464.40625 L 598.832031 463.964844 L 599.140625 463.535156 L 599.449219 463.113281 L 599.757812 462.699219 L 600.0625 462.296875 L 600.371094 461.902344 L 600.679688 461.519531 L 600.988281 461.144531 L 601.292969 460.78125 L 601.601562 460.425781 L 601.910156 460.078125 L 602.21875 459.742188 L 602.527344 459.414062 L 602.832031 459.097656 L 603.140625 458.789062 L 603.449219 458.492188 L 603.757812 458.203125 L 604.0625 457.921875 L 604.371094 457.652344 L 604.679688 457.390625 L 604.988281 457.140625 L 605.296875 456.898438 L 605.601562 456.664062 L 605.910156 456.441406 L 606.21875 456.230469 L 606.527344 456.023438 L 606.832031 455.828125 L 607.140625 455.644531 L 607.449219 455.46875 L 607.757812 455.300781 L 608.066406 455.144531 L 608.371094 454.996094 L 608.679688 454.855469 L 608.988281 454.726562 L 609.296875 454.605469 L 609.601562 454.492188 L 609.910156 454.390625 L 610.21875 454.300781 L 610.527344 454.214844 L 610.835938 454.140625 L 611.140625 454.078125 L 611.449219 454.023438 L 611.757812 453.976562 L 612.066406 453.9375 L 612.375 453.910156 L 612.679688 453.890625 L 612.988281 453.882812 L 613.296875 453.882812 L 613.605469 453.890625 L 613.910156 453.910156 L 614.21875 453.9375 L 614.527344 453.976562 L 614.835938 454.023438 L 615.144531 454.078125 L 615.449219 454.140625 L 615.757812 454.214844 L 616.066406 454.300781 L 616.375 454.390625 L 616.679688 454.492188 L 616.988281 454.605469 L 617.296875 454.726562 L 617.605469 454.855469 L 617.914062 454.996094 L 618.21875 455.144531 L 618.527344 455.300781 L 618.835938 455.46875 L 619.144531 455.644531 L 619.449219 455.828125 L 619.757812 456.023438 L 620.066406 456.230469 L 620.375 456.441406 L 620.683594 456.664062 L 620.988281 456.898438 L 621.296875 457.140625 L 621.605469 457.390625 L 621.914062 457.652344 L 622.21875 457.921875 L 622.527344 458.203125 L 622.835938 458.492188 L 623.144531 458.789062 L 623.453125 459.097656 L 623.757812 459.414062 L 624.066406 459.742188 L 624.375 460.078125 L 624.683594 460.425781 L 624.988281 460.78125 L 625.296875 461.144531 L 625.605469 461.519531 L 625.914062 461.902344 L 626.222656 462.296875 L 626.527344 462.699219 L 626.835938 463.113281 L 627.144531 463.535156 L 627.453125 463.964844 L 627.761719 464.40625 L 628.066406 464.855469 L 628.375 465.316406 L 628.683594 465.785156 L 628.992188 466.265625 L 629.296875 466.753906 L 629.605469 467.25 L 629.914062 467.757812 L 630.222656 468.273438 L 630.53125 468.800781 L 630.835938 469.335938 L 631.144531 469.878906 L 631.453125 470.433594 L 631.761719 470.996094 L 632.066406 471.566406 L 632.375 472.148438 L 632.683594 472.738281 L 632.992188 473.335938 L 633.300781 473.945312 L 633.605469 474.5625 L 633.914062 475.191406 L 634.222656 475.824219 L 634.53125 476.46875 L 634.835938 477.121094 L 635.144531 477.78125 L 635.453125 478.453125 L 635.761719 479.132812 L 636.070312 479.820312 L 636.375 480.515625 L 636.683594 481.21875 L 636.992188 481.929688 L 637.300781 482.652344 L 637.605469 483.378906 L 637.914062 484.117188 L 638.222656 484.859375 L 638.53125 485.613281 L 638.839844 486.371094 L 639.144531 487.140625 L 639.453125 487.914062 L 639.761719 488.695312 L 640.070312 489.484375 L 640.375 490.28125 L 640.683594 491.085938 L 640.992188 491.894531 L 641.300781 492.710938 L 641.609375 493.535156 L 641.914062 494.367188 L 642.222656 495.203125 L 642.53125 496.042969 L 643.148438 497.746094 L 643.453125 498.605469 L 643.761719 499.472656 L 644.070312 500.34375 L 644.378906 501.21875 L 644.683594 502.101562 L 644.992188 502.984375 L 645.300781 503.875 L 645.609375 504.769531 L 645.917969 505.671875 L 646.222656 506.574219 L 646.53125 507.480469 L 646.839844 508.390625 L 647.148438 509.308594 L 647.453125 510.226562 L 647.761719 511.144531 L 648.378906 512.996094 L 648.6875 513.925781 L 648.992188 514.859375 L 649.300781 515.792969 L 649.917969 517.667969 L 650.222656 518.605469 L 650.839844 520.488281 L 651.148438 521.433594 L 651.457031 522.375 L 651.761719 523.320312 L 652.6875 526.15625 L 652.992188 527.101562 L 653.300781 528.042969 L 653.609375 528.988281 L 654.226562 530.871094 L 654.53125 531.8125 L 655.148438 533.6875 L 655.457031 534.621094 L 655.761719 535.554688 L 656.070312 536.488281 L 656.378906 537.414062 L 656.6875 538.34375 L 656.996094 539.265625 L 657.300781 540.1875 L 657.917969 542.015625 L 658.226562 542.925781 L 658.53125 543.832031 L 658.839844 544.738281 L 659.148438 545.636719 L 659.457031 546.53125 L 659.765625 547.421875 L 660.070312 548.308594 L 660.6875 550.066406 L 660.996094 550.9375 L 661.304688 551.804688 L 661.609375 552.667969 L 661.917969 553.523438 L 662.226562 554.375 L 662.535156 555.21875 L 662.839844 556.058594 L 663.148438 556.894531 L 663.457031 557.722656 L 663.765625 558.542969 L 664.074219 559.359375 L 664.378906 560.171875 L 664.6875 560.976562 L 664.996094 561.773438 L 665.304688 562.5625 L 665.609375 563.347656 L 665.917969 564.125 L 666.226562 564.898438 L 666.535156 565.660156 L 666.84375 566.417969 L 667.148438 567.171875 L 667.457031 567.914062 L 667.765625 568.652344 L 668.074219 569.382812 L 668.378906 570.105469 L 668.6875 570.820312 L 668.996094 571.527344 L 669.304688 572.230469 L 669.613281 572.925781 L 669.917969 573.613281 L 670.226562 574.292969 L 670.535156 574.964844 L 670.84375 575.628906 L 671.148438 576.285156 L 671.457031 576.9375 L 671.765625 577.582031 L 672.074219 578.214844 L 672.382812 578.84375 L 672.6875 579.464844 L 672.996094 580.078125 L 673.304688 580.6875 L 673.613281 581.285156 L 673.917969 581.875 L 674.226562 582.460938 L 674.535156 583.039062 L 674.84375 583.609375 L 675.152344 584.171875 L 675.457031 584.726562 L 675.765625 585.273438 L 676.074219 585.816406 L 676.382812 586.351562 L 676.691406 586.878906 L 676.996094 587.398438 L 677.304688 587.910156 L 677.613281 588.417969 L 677.921875 588.914062 L 678.226562 589.40625 L 678.535156 589.894531 L 678.84375 590.371094 L 679.152344 590.84375 L 679.460938 591.308594 L 679.765625 591.769531 L 680.074219 592.21875 L 680.382812 592.664062 L 680.691406 593.105469 L 680.996094 593.535156 L 681.304688 593.960938 L 681.613281 594.382812 L 681.921875 594.796875 L 682.230469 595.203125 L 682.535156 595.605469 L 682.84375 596 L 683.152344 596.386719 L 683.460938 596.769531 L 683.765625 597.148438 L 684.074219 597.519531 L 684.691406 598.246094 L 685 598.597656 L 685.304688 598.945312 L 685.613281 599.289062 L 685.921875 599.628906 L 686.230469 599.960938 L 686.535156 600.285156 L 686.84375 600.609375 L 687.152344 600.925781 L 687.460938 601.234375 L 687.769531 601.539062 L 688.074219 601.84375 L 688.691406 602.429688 L 689 602.714844 L 689.304688 602.996094 L 689.613281 603.273438 L 689.921875 603.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="508.261719" y="583.101562"/>
+ <use xlink:href="#glyph0-2" x="513.597305" y="583.101562"/>
+ <use xlink:href="#glyph0-3" x="516.262756" y="583.101562"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="508.261719" y="544.636719"/>
+ <use xlink:href="#glyph0-2" x="513.597305" y="544.636719"/>
+ <use xlink:href="#glyph0-7" x="516.262756" y="544.636719"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="508.261719" y="506.175781"/>
+ <use xlink:href="#glyph0-2" x="513.597305" y="506.175781"/>
+ <use xlink:href="#glyph0-8" x="516.262756" y="506.175781"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="508.261719" y="467.710938"/>
+ <use xlink:href="#glyph0-2" x="513.597305" y="467.710938"/>
+ <use xlink:href="#glyph0-9" x="516.262756" y="467.710938"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 579.664062 L 528.683594 579.664062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 541.199219 L 528.683594 541.199219 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 502.738281 L 528.683594 502.738281 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 464.273438 L 528.683594 464.273438 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 615.28125 L 536.363281 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 615.28125 L 574.753906 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 615.28125 L 613.140625 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 615.28125 L 651.53125 611.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 615.28125 L 689.921875 611.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="624.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="624.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="624.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="624.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="624.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="624.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="624.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="637.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="496.324219" y="540.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.324219" y="533.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.324219" y="528.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.324219" y="522.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-11" x="521" y="442.800781"/>
+ <use xlink:href="#glyph5-3" x="529.003906" y="442.800781"/>
+ <use xlink:href="#glyph5-6" x="532.337891" y="442.800781"/>
+ <use xlink:href="#glyph5-19" x="539.667969" y="442.800781"/>
+ <use xlink:href="#glyph5-15" x="550.337891" y="442.800781"/>
+ <use xlink:href="#glyph5-3" x="557.667969" y="442.800781"/>
+ <use xlink:href="#glyph5-16" x="561.001953" y="442.800781"/>
+ <use xlink:href="#glyph5-10" x="568.332031" y="442.800781"/>
+ <use xlink:href="#glyph5-2" x="576.335938" y="442.800781"/>
+ <use xlink:href="#glyph5-15" x="581.005859" y="442.800781"/>
+ <use xlink:href="#glyph5-16" x="588.335938" y="442.800781"/>
+ <use xlink:href="#glyph5-26" x="595.666016" y="442.800781"/>
+ <use xlink:href="#glyph5-22" x="602.996094" y="442.800781"/>
+ <use xlink:href="#glyph5-24" x="609.669922" y="442.800781"/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 864 L 237.332031 864 L 237.332031 648 L 0 648 Z "/>
+<g clip-path="url(#clip185)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 864 L 237.332031 864 L 237.332031 648 L 0 648 Z "/>
+</g>
+<g clip-path="url(#clip186)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 827.027344 L 222.933594 827.027344 L 222.933594 662.398438 L 54.019531 662.398438 Z "/>
+</g>
+<g clip-path="url(#clip187)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 800.515625 L 222.933594 800.515625 "/>
+</g>
+<g clip-path="url(#clip188)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 762.449219 L 222.933594 762.449219 "/>
+</g>
+<g clip-path="url(#clip189)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 724.386719 L 222.933594 724.386719 "/>
+</g>
+<g clip-path="url(#clip190)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 686.320312 L 222.933594 686.320312 "/>
+</g>
+<g clip-path="url(#clip191)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 827.027344 L 80.890625 662.398438 "/>
+</g>
+<g clip-path="url(#clip192)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 827.027344 L 119.28125 662.398438 "/>
+</g>
+<g clip-path="url(#clip193)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 827.027344 L 157.671875 662.398438 "/>
+</g>
+<g clip-path="url(#clip194)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 827.027344 L 196.058594 662.398438 "/>
+</g>
+<g clip-path="url(#clip195)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 819.546875 L 222.933594 819.546875 "/>
+</g>
+<g clip-path="url(#clip196)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 781.480469 L 222.933594 781.480469 "/>
+</g>
+<g clip-path="url(#clip197)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 743.417969 L 222.933594 743.417969 "/>
+</g>
+<g clip-path="url(#clip198)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 705.355469 L 222.933594 705.355469 "/>
+</g>
+<g clip-path="url(#clip199)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 667.289062 L 222.933594 667.289062 "/>
+</g>
+<g clip-path="url(#clip200)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 827.027344 L 61.695312 662.398438 "/>
+</g>
+<g clip-path="url(#clip201)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 827.027344 L 100.085938 662.398438 "/>
+</g>
+<g clip-path="url(#clip202)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 827.027344 L 138.476562 662.398438 "/>
+</g>
+<g clip-path="url(#clip203)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 827.027344 L 176.867188 662.398438 "/>
+</g>
+<g clip-path="url(#clip204)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 827.027344 L 215.253906 662.398438 "/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 65.417969 819.546875 C 65.417969 824.507812 57.976562 824.507812 57.976562 819.546875 C 57.976562 814.585938 65.417969 814.585938 65.417969 819.546875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 68.1875 808.5625 C 68.1875 813.523438 60.746094 813.523438 60.746094 808.5625 C 60.746094 803.601562 68.1875 803.601562 68.1875 808.5625 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 71.261719 796.355469 C 71.261719 801.316406 63.824219 801.316406 63.824219 796.355469 C 63.824219 791.394531 71.261719 791.394531 71.261719 796.355469 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 74.339844 784.152344 C 74.339844 789.113281 66.898438 789.113281 66.898438 784.152344 C 66.898438 779.191406 74.339844 779.191406 74.339844 784.152344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 77.417969 771.945312 C 77.417969 776.90625 69.976562 776.90625 69.976562 771.945312 C 69.976562 766.984375 77.417969 766.984375 77.417969 771.945312 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 80.496094 759.742188 C 80.496094 764.703125 73.054688 764.703125 73.054688 759.742188 C 73.054688 754.78125 80.496094 754.78125 80.496094 759.742188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 83.574219 747.535156 C 83.574219 752.496094 76.132812 752.496094 76.132812 747.535156 C 76.132812 742.578125 83.574219 742.578125 83.574219 747.535156 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 86.648438 735.332031 C 86.648438 740.292969 79.210938 740.292969 79.210938 735.332031 C 79.210938 730.371094 86.648438 730.371094 86.648438 735.332031 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 89.726562 723.128906 C 89.726562 728.085938 82.285156 728.085938 82.285156 723.128906 C 82.285156 718.167969 89.726562 718.167969 89.726562 723.128906 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 92.804688 710.921875 C 92.804688 715.882812 85.363281 715.882812 85.363281 710.921875 C 85.363281 705.960938 92.804688 705.960938 92.804688 710.921875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 95.882812 698.71875 C 95.882812 703.679688 88.441406 703.679688 88.441406 698.71875 C 88.441406 693.757812 95.882812 693.757812 95.882812 698.71875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 98.960938 686.511719 C 98.960938 691.472656 91.519531 691.472656 91.519531 686.511719 C 91.519531 681.550781 98.960938 681.550781 98.960938 686.511719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 102.035156 674.308594 C 102.035156 679.269531 94.597656 679.269531 94.597656 674.308594 C 94.597656 669.347656 102.035156 669.347656 102.035156 674.308594 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 105.113281 669.882812 C 105.113281 674.84375 97.671875 674.84375 97.671875 669.882812 C 97.671875 664.921875 105.113281 664.921875 105.113281 669.882812 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 108.191406 675.984375 C 108.191406 680.945312 100.75 680.945312 100.75 675.984375 C 100.75 671.023438 108.191406 671.023438 108.191406 675.984375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 111.269531 682.089844 C 111.269531 687.046875 103.828125 687.046875 103.828125 682.089844 C 103.828125 677.128906 111.269531 677.128906 111.269531 682.089844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 114.347656 688.191406 C 114.347656 693.152344 106.90625 693.152344 106.90625 688.191406 C 106.90625 683.230469 114.347656 683.230469 114.347656 688.191406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 117.421875 694.292969 C 117.421875 699.253906 109.984375 699.253906 109.984375 694.292969 C 109.984375 689.332031 117.421875 689.332031 117.421875 694.292969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 120.5 700.394531 C 120.5 705.355469 113.058594 705.355469 113.058594 700.394531 C 113.058594 695.433594 120.5 695.433594 120.5 700.394531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 123.578125 706.496094 C 123.578125 711.457031 116.136719 711.457031 116.136719 706.496094 C 116.136719 701.539062 123.578125 701.539062 123.578125 706.496094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 126.65625 712.601562 C 126.65625 717.5625 119.214844 717.5625 119.214844 712.601562 C 119.214844 707.640625 126.65625 707.640625 126.65625 712.601562 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 129.734375 718.703125 C 129.734375 723.664062 122.292969 723.664062 122.292969 718.703125 C 122.292969 713.742188 129.734375 713.742188 129.734375 718.703125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 132.808594 724.804688 C 132.808594 729.765625 125.371094 729.765625 125.371094 724.804688 C 125.371094 719.84375 132.808594 719.84375 132.808594 724.804688 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 135.886719 730.90625 C 135.886719 735.867188 128.445312 735.867188 128.445312 730.90625 C 128.445312 725.945312 135.886719 725.945312 135.886719 730.90625 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 138.964844 737.011719 C 138.964844 741.972656 131.523438 741.972656 131.523438 737.011719 C 131.523438 732.050781 138.964844 732.050781 138.964844 737.011719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 142.042969 743.113281 C 142.042969 748.074219 134.601562 748.074219 134.601562 743.113281 C 134.601562 738.152344 142.042969 738.152344 142.042969 743.113281 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 145.121094 737.621094 C 145.121094 742.582031 137.679688 742.582031 137.679688 737.621094 C 137.679688 732.660156 145.121094 732.660156 145.121094 737.621094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 148.195312 731.519531 C 148.195312 736.480469 140.757812 736.480469 140.757812 731.519531 C 140.757812 726.558594 148.195312 726.558594 148.195312 731.519531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 151.273438 725.414062 C 151.273438 730.375 143.832031 730.375 143.832031 725.414062 C 143.832031 720.453125 151.273438 720.453125 151.273438 725.414062 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 154.351562 719.3125 C 154.351562 724.273438 146.910156 724.273438 146.910156 719.3125 C 146.910156 714.351562 154.351562 714.351562 154.351562 719.3125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 157.429688 713.210938 C 157.429688 718.171875 149.988281 718.171875 149.988281 713.210938 C 149.988281 708.25 157.429688 708.25 157.429688 713.210938 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 160.507812 707.109375 C 160.507812 712.070312 153.066406 712.070312 153.066406 707.109375 C 153.066406 702.148438 160.507812 702.148438 160.507812 707.109375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 163.582031 701.003906 C 163.582031 705.964844 156.144531 705.964844 156.144531 701.003906 C 156.144531 696.046875 163.582031 696.046875 163.582031 701.003906 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 166.660156 694.902344 C 166.660156 699.863281 159.21875 699.863281 159.21875 694.902344 C 159.21875 689.941406 166.660156 689.941406 166.660156 694.902344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 169.738281 688.800781 C 169.738281 693.761719 162.296875 693.761719 162.296875 688.800781 C 162.296875 683.839844 169.738281 683.839844 169.738281 688.800781 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 172.816406 682.699219 C 172.816406 687.660156 165.375 687.660156 165.375 682.699219 C 165.375 677.738281 172.816406 677.738281 172.816406 682.699219 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 175.894531 676.597656 C 175.894531 681.554688 168.453125 681.554688 168.453125 676.597656 C 168.453125 671.636719 175.894531 671.636719 175.894531 676.597656 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 178.96875 670.492188 C 178.96875 675.453125 171.53125 675.453125 171.53125 670.492188 C 171.53125 665.53125 178.96875 665.53125 178.96875 670.492188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 182.046875 673.085938 C 182.046875 678.046875 174.605469 678.046875 174.605469 673.085938 C 174.605469 668.125 182.046875 668.125 182.046875 673.085938 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 185.125 685.292969 C 185.125 690.253906 177.683594 690.253906 177.683594 685.292969 C 177.683594 680.332031 185.125 680.332031 185.125 685.292969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 188.203125 697.496094 C 188.203125 702.457031 180.761719 702.457031 180.761719 697.496094 C 180.761719 692.535156 188.203125 692.535156 188.203125 697.496094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 191.28125 709.703125 C 191.28125 714.664062 183.839844 714.664062 183.839844 709.703125 C 183.839844 704.742188 191.28125 704.742188 191.28125 709.703125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 194.355469 721.90625 C 194.355469 726.867188 186.917969 726.867188 186.917969 721.90625 C 186.917969 716.945312 194.355469 716.945312 194.355469 721.90625 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 197.433594 734.113281 C 197.433594 739.070312 189.992188 739.070312 189.992188 734.113281 C 189.992188 729.152344 197.433594 729.152344 197.433594 734.113281 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 200.511719 746.316406 C 200.511719 751.277344 193.070312 751.277344 193.070312 746.316406 C 193.070312 741.355469 200.511719 741.355469 200.511719 746.316406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 203.589844 758.519531 C 203.589844 763.480469 196.148438 763.480469 196.148438 758.519531 C 196.148438 753.5625 203.589844 753.5625 203.589844 758.519531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 206.667969 770.726562 C 206.667969 775.6875 199.226562 775.6875 199.226562 770.726562 C 199.226562 765.765625 206.667969 765.765625 206.667969 770.726562 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 209.742188 782.929688 C 209.742188 787.890625 202.304688 787.890625 202.304688 782.929688 C 202.304688 777.96875 209.742188 777.96875 209.742188 782.929688 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 212.820312 795.136719 C 212.820312 800.097656 205.378906 800.097656 205.378906 795.136719 C 205.378906 790.175781 212.820312 790.175781 212.820312 795.136719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 215.898438 807.339844 C 215.898438 812.300781 208.457031 812.300781 208.457031 807.339844 C 208.457031 802.378906 215.898438 802.378906 215.898438 807.339844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 218.976562 819.546875 C 218.976562 824.507812 211.535156 824.507812 211.535156 819.546875 C 211.535156 814.585938 218.976562 814.585938 218.976562 819.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="822.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="822.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="822.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="822.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="784.917969"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="784.917969"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="784.917969"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="784.917969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="746.855469"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="746.855469"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="746.855469"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="746.855469"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="708.792969"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="708.792969"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="708.792969"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="708.792969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="670.726562"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="670.726562"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="670.726562"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="670.726562"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 819.546875 L 54.019531 819.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 781.480469 L 54.019531 781.480469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 743.417969 L 54.019531 743.417969 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 705.355469 L 54.019531 705.355469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 667.289062 L 54.019531 667.289062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 831.28125 L 61.695312 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 831.28125 L 100.085938 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 831.28125 L 138.476562 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 831.28125 L 176.867188 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 831.28125 L 215.253906 827.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="840.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="840.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="840.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="853.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="756.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="749.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="744.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="738.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-20" x="23.679688" y="658.800781"/>
+ <use xlink:href="#glyph5-3" x="32.345703" y="658.800781"/>
+ <use xlink:href="#glyph5-18" x="35.679688" y="658.800781"/>
+ <use xlink:href="#glyph5-22" x="42.353516" y="658.800781"/>
+ <use xlink:href="#glyph5-2" x="49.027344" y="658.800781"/>
+ <use xlink:href="#glyph5-8" x="53.697266" y="658.800781"/>
+ <use xlink:href="#glyph5-24" x="60.371094" y="658.800781"/>
+ <use xlink:href="#glyph5-8" x="64.367188" y="658.800781"/>
+</g>
+<g clip-path="url(#clip205)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 864 L 474.664062 864 L 474.664062 648 L 237.332031 648 Z "/>
+</g>
+<g clip-path="url(#clip206)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 864 L 474.664062 864 L 474.664062 648 L 237.332031 648 Z "/>
+</g>
+<g clip-path="url(#clip207)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 827.027344 L 460.265625 827.027344 L 460.265625 662.398438 L 291.351562 662.398438 Z "/>
+</g>
+<g clip-path="url(#clip208)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 802.214844 L 460.265625 802.214844 "/>
+</g>
+<g clip-path="url(#clip209)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 763.226562 L 460.265625 763.226562 "/>
+</g>
+<g clip-path="url(#clip210)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 724.234375 L 460.265625 724.234375 "/>
+</g>
+<g clip-path="url(#clip211)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 685.242188 L 460.265625 685.242188 "/>
+</g>
+<g clip-path="url(#clip212)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 827.027344 L 318.222656 662.398438 "/>
+</g>
+<g clip-path="url(#clip213)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 827.027344 L 356.613281 662.398438 "/>
+</g>
+<g clip-path="url(#clip214)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 827.027344 L 395.003906 662.398438 "/>
+</g>
+<g clip-path="url(#clip215)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 827.027344 L 433.394531 662.398438 "/>
+</g>
+<g clip-path="url(#clip216)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 821.710938 L 460.265625 821.710938 "/>
+</g>
+<g clip-path="url(#clip217)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 782.71875 L 460.265625 782.71875 "/>
+</g>
+<g clip-path="url(#clip218)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 743.730469 L 460.265625 743.730469 "/>
+</g>
+<g clip-path="url(#clip219)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 704.738281 L 460.265625 704.738281 "/>
+</g>
+<g clip-path="url(#clip220)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 665.746094 L 460.265625 665.746094 "/>
+</g>
+<g clip-path="url(#clip221)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 827.027344 L 299.03125 662.398438 "/>
+</g>
+<g clip-path="url(#clip222)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 827.027344 L 337.417969 662.398438 "/>
+</g>
+<g clip-path="url(#clip223)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 827.027344 L 375.808594 662.398438 "/>
+</g>
+<g clip-path="url(#clip224)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 827.027344 L 414.199219 662.398438 "/>
+</g>
+<g clip-path="url(#clip225)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 827.027344 L 452.589844 662.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 819.546875 L 299.335938 819.480469 L 299.644531 819.414062 L 299.953125 819.34375 L 300.261719 819.269531 L 300.566406 819.199219 L 300.875 819.121094 L 301.183594 819.046875 L 301.800781 818.882812 L 302.105469 818.800781 L 302.722656 818.628906 L 303.03125 818.539062 L 303.335938 818.445312 L 303.644531 818.351562 L 303.953125 818.253906 L 304.570312 818.050781 L 304.875 817.945312 L 305.183594 817.839844 L 305.492188 817.730469 L 305.800781 817.617188 L 306.105469 817.5 L 306.414062 817.382812 L 306.722656 817.261719 L 307.339844 817.011719 L 307.644531 816.878906 L 307.953125 816.746094 L 308.570312 816.472656 L 308.878906 816.328125 L 309.183594 816.183594 L 309.800781 815.878906 L 310.109375 815.722656 L 310.414062 815.5625 L 310.722656 815.398438 L 311.03125 815.230469 L 311.648438 814.886719 L 311.953125 814.707031 L 312.261719 814.523438 L 312.570312 814.335938 L 312.878906 814.144531 L 313.183594 813.949219 L 313.492188 813.75 L 313.800781 813.546875 L 314.417969 813.125 L 314.722656 812.90625 L 315.03125 812.683594 L 315.339844 812.457031 L 315.648438 812.226562 L 315.953125 811.992188 L 316.261719 811.75 L 316.570312 811.503906 L 316.878906 811.253906 L 317.1875 810.996094 L 317.492188 810.734375 L 317.800781 810.46875 L 318.109375 810.199219 L 318.417969 809.921875 L 318.722656 809.636719 L 319.03125 809.351562 L 319.648438 808.757812 L 319.957031 808.453125 L 320.261719 808.140625 L 320.570312 807.824219 L 320.878906 807.5 L 321.1875 807.171875 L 321.492188 806.835938 L 321.800781 806.496094 L 322.109375 806.148438 L 322.417969 805.792969 L 322.726562 805.433594 L 323.03125 805.066406 L 323.339844 804.695312 L 323.648438 804.316406 L 323.957031 803.929688 L 324.265625 803.535156 L 324.570312 803.132812 L 324.878906 802.726562 L 325.1875 802.3125 L 325.496094 801.890625 L 325.800781 801.464844 L 326.109375 801.027344 L 326.417969 800.585938 L 326.726562 800.136719 L 327.035156 799.679688 L 327.339844 799.214844 L 327.648438 798.742188 L 327.957031 798.261719 L 328.265625 797.773438 L 328.570312 797.28125 L 328.878906 796.777344 L 329.1875 796.265625 L 329.496094 795.746094 L 329.804688 795.222656 L 330.109375 794.6875 L 330.417969 794.144531 L 330.726562 793.59375 L 331.035156 793.035156 L 331.339844 792.46875 L 331.648438 791.894531 L 331.957031 791.3125 L 332.265625 790.71875 L 332.574219 790.121094 L 333.1875 788.894531 L 333.496094 788.269531 L 333.804688 787.636719 L 334.109375 786.996094 L 334.417969 786.34375 L 334.726562 785.683594 L 335.035156 785.019531 L 335.34375 784.339844 L 335.648438 783.65625 L 335.957031 782.960938 L 336.265625 782.261719 L 336.574219 781.550781 L 336.878906 780.828125 L 337.1875 780.101562 L 337.496094 779.363281 L 337.804688 778.617188 L 338.113281 777.863281 L 338.417969 777.101562 L 338.726562 776.328125 L 339.035156 775.546875 L 339.34375 774.757812 L 339.648438 773.960938 L 339.957031 773.152344 L 340.265625 772.335938 L 340.574219 771.511719 L 340.882812 770.679688 L 341.1875 769.839844 L 341.496094 768.988281 L 341.804688 768.128906 L 342.113281 767.261719 L 342.421875 766.386719 L 342.726562 765.503906 L 343.035156 764.609375 L 343.34375 763.710938 L 343.652344 762.800781 L 343.957031 761.882812 L 344.265625 760.957031 L 344.574219 760.023438 L 344.882812 759.082031 L 345.191406 758.132812 L 345.496094 757.175781 L 345.804688 756.210938 L 346.113281 755.238281 L 346.421875 754.253906 L 346.726562 753.265625 L 347.035156 752.269531 L 347.34375 751.265625 L 347.652344 750.257812 L 347.960938 749.238281 L 348.265625 748.214844 L 348.574219 747.179688 L 348.882812 746.140625 L 349.191406 745.097656 L 349.496094 744.042969 L 349.804688 742.984375 L 350.113281 741.917969 L 350.421875 740.847656 L 350.730469 739.769531 L 351.035156 738.683594 L 351.34375 737.59375 L 351.652344 736.5 L 351.960938 735.398438 L 352.265625 734.292969 L 352.574219 733.179688 L 352.882812 732.0625 L 353.191406 730.941406 L 353.5 729.8125 L 353.804688 728.679688 L 354.113281 727.546875 L 354.421875 726.40625 L 354.730469 725.261719 L 355.035156 724.113281 L 355.34375 722.960938 L 355.652344 721.804688 L 355.960938 720.644531 L 356.269531 719.480469 L 356.574219 718.316406 L 356.882812 717.148438 L 357.5 714.804688 L 357.808594 713.628906 L 358.113281 712.453125 L 358.730469 710.09375 L 359.039062 708.910156 L 359.34375 707.726562 L 360.578125 702.992188 L 360.882812 701.816406 L 361.191406 700.65625 L 361.5 699.507812 L 361.808594 698.375 L 362.113281 697.253906 L 362.421875 696.152344 L 362.730469 695.0625 L 363.039062 693.988281 L 363.347656 692.933594 L 363.652344 691.894531 L 363.960938 690.875 L 364.269531 689.871094 L 364.578125 688.886719 L 364.882812 687.925781 L 365.191406 686.980469 L 365.5 686.058594 L 365.808594 685.15625 L 366.117188 684.277344 L 366.421875 683.417969 L 366.730469 682.582031 L 367.039062 681.769531 L 367.347656 680.980469 L 367.652344 680.214844 L 367.960938 679.476562 L 368.269531 678.757812 L 368.578125 678.070312 L 368.886719 677.402344 L 369.191406 676.765625 L 369.5 676.152344 L 369.808594 675.566406 L 370.117188 675.007812 L 370.421875 674.476562 L 370.730469 673.972656 L 371.039062 673.496094 L 371.347656 673.050781 L 371.65625 672.632812 L 371.960938 672.242188 L 372.269531 671.882812 L 372.578125 671.550781 L 372.886719 671.25 L 373.195312 670.976562 L 373.5 670.734375 L 373.808594 670.523438 L 374.117188 670.339844 L 374.425781 670.1875 L 374.730469 670.066406 L 375.039062 669.972656 L 375.347656 669.914062 L 375.65625 669.882812 L 375.964844 669.882812 L 376.269531 669.914062 L 376.578125 669.972656 L 376.886719 670.066406 L 377.195312 670.1875 L 377.5 670.339844 L 377.808594 670.523438 L 378.117188 670.734375 L 378.425781 670.976562 L 378.734375 671.25 L 379.039062 671.550781 L 379.347656 671.882812 L 379.65625 672.242188 L 379.964844 672.632812 L 380.269531 673.050781 L 380.578125 673.496094 L 380.886719 673.972656 L 381.195312 674.476562 L 381.503906 675.007812 L 381.808594 675.566406 L 382.117188 676.152344 L 382.425781 676.765625 L 382.734375 677.402344 L 383.039062 678.070312 L 383.347656 678.757812 L 383.65625 679.476562 L 383.964844 680.214844 L 384.273438 680.980469 L 384.578125 681.769531 L 384.886719 682.582031 L 385.195312 683.417969 L 385.503906 684.277344 L 385.808594 685.15625 L 386.117188 686.058594 L 386.425781 686.980469 L 386.734375 687.925781 L 387.042969 688.886719 L 387.347656 689.871094 L 387.65625 690.875 L 387.964844 691.894531 L 388.273438 692.933594 L 388.578125 693.988281 L 388.886719 695.0625 L 389.195312 696.152344 L 389.503906 697.253906 L 389.8125 698.375 L 390.117188 699.507812 L 390.425781 700.65625 L 390.734375 701.816406 L 391.042969 702.992188 L 391.351562 704.175781 L 391.65625 705.359375 L 392.582031 708.910156 L 392.886719 710.09375 L 393.503906 712.453125 L 394.121094 714.804688 L 394.425781 715.976562 L 394.734375 717.148438 L 395.042969 718.316406 L 395.351562 719.480469 L 395.65625 720.644531 L 395.964844 721.804688 L 396.273438 722.960938 L 396.582031 724.113281 L 396.890625 725.261719 L 397.195312 726.40625 L 397.503906 727.546875 L 398.121094 729.8125 L 398.425781 730.941406 L 398.734375 732.0625 L 399.042969 733.179688 L 399.351562 734.292969 L 399.660156 735.398438 L 399.964844 736.5 L 400.273438 737.59375 L 400.582031 738.683594 L 400.890625 739.769531 L 401.195312 740.847656 L 401.503906 741.917969 L 401.8125 742.984375 L 402.121094 744.042969 L 402.429688 745.097656 L 402.734375 746.140625 L 403.042969 747.179688 L 403.351562 748.214844 L 403.660156 749.238281 L 403.964844 750.257812 L 404.273438 751.265625 L 404.582031 752.269531 L 404.890625 753.265625 L 405.199219 754.253906 L 405.503906 755.238281 L 405.8125 756.210938 L 406.121094 757.175781 L 406.429688 758.132812 L 406.738281 759.082031 L 407.042969 760.023438 L 407.351562 760.957031 L 407.660156 761.882812 L 407.96875 762.800781 L 408.273438 763.710938 L 408.582031 764.609375 L 408.890625 765.503906 L 409.199219 766.386719 L 409.507812 767.261719 L 409.8125 768.128906 L 410.121094 768.988281 L 410.429688 769.839844 L 410.738281 770.679688 L 411.042969 771.511719 L 411.351562 772.335938 L 411.660156 773.152344 L 411.96875 773.960938 L 412.277344 774.757812 L 412.582031 775.546875 L 412.890625 776.328125 L 413.199219 777.101562 L 413.507812 777.863281 L 413.8125 778.617188 L 414.121094 779.363281 L 414.429688 780.101562 L 414.738281 780.828125 L 415.046875 781.550781 L 415.351562 782.261719 L 415.660156 782.960938 L 415.96875 783.65625 L 416.277344 784.339844 L 416.582031 785.019531 L 416.890625 785.683594 L 417.199219 786.34375 L 417.507812 786.996094 L 417.816406 787.636719 L 418.121094 788.269531 L 418.429688 788.894531 L 418.738281 789.511719 L 419.046875 790.121094 L 419.351562 790.71875 L 419.660156 791.3125 L 419.96875 791.894531 L 420.277344 792.46875 L 420.585938 793.035156 L 420.890625 793.59375 L 421.199219 794.144531 L 421.507812 794.6875 L 421.816406 795.222656 L 422.125 795.746094 L 422.429688 796.265625 L 422.738281 796.777344 L 423.046875 797.28125 L 423.355469 797.773438 L 423.660156 798.261719 L 423.96875 798.742188 L 424.277344 799.214844 L 424.585938 799.679688 L 424.894531 800.136719 L 425.199219 800.585938 L 425.507812 801.027344 L 425.816406 801.464844 L 426.125 801.890625 L 426.429688 802.3125 L 426.738281 802.726562 L 427.046875 803.132812 L 427.355469 803.535156 L 427.664062 803.929688 L 427.96875 804.316406 L 428.277344 804.695312 L 428.585938 805.066406 L 428.894531 805.433594 L 429.199219 805.792969 L 429.507812 806.148438 L 429.816406 806.496094 L 430.125 806.835938 L 430.433594 807.171875 L 430.738281 807.5 L 431.046875 807.824219 L 431.355469 808.140625 L 431.664062 808.453125 L 431.96875 808.757812 L 432.585938 809.351562 L 433.203125 809.921875 L 433.507812 810.199219 L 433.816406 810.46875 L 434.125 810.734375 L 434.433594 810.996094 L 434.738281 811.253906 L 435.046875 811.503906 L 435.355469 811.75 L 435.664062 811.992188 L 435.972656 812.226562 L 436.277344 812.457031 L 436.585938 812.683594 L 436.894531 812.90625 L 437.203125 813.125 L 437.507812 813.335938 L 437.816406 813.546875 L 438.125 813.75 L 438.433594 813.949219 L 438.742188 814.144531 L 439.046875 814.335938 L 439.355469 814.523438 L 439.664062 814.707031 L 439.972656 814.886719 L 440.28125 815.058594 L 440.585938 815.230469 L 440.894531 815.398438 L 441.203125 815.5625 L 441.511719 815.722656 L 441.816406 815.878906 L 442.433594 816.183594 L 443.050781 816.472656 L 443.355469 816.609375 L 443.664062 816.746094 L 444.28125 817.011719 L 444.585938 817.136719 L 444.894531 817.261719 L 445.203125 817.382812 L 445.820312 817.617188 L 446.125 817.730469 L 446.433594 817.839844 L 447.050781 818.050781 L 447.355469 818.152344 L 447.664062 818.253906 L 447.972656 818.351562 L 448.589844 818.539062 L 448.894531 818.628906 L 449.511719 818.800781 L 449.820312 818.882812 L 450.125 818.964844 L 450.433594 819.046875 L 450.742188 819.121094 L 451.050781 819.199219 L 451.359375 819.269531 L 451.664062 819.34375 L 451.972656 819.414062 L 452.589844 819.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="270.929688" y="825.148438"/>
+ <use xlink:href="#glyph0-2" x="276.265274" y="825.148438"/>
+ <use xlink:href="#glyph0-1" x="278.930725" y="825.148438"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="270.929688" y="786.15625"/>
+ <use xlink:href="#glyph0-2" x="276.265274" y="786.15625"/>
+ <use xlink:href="#glyph0-3" x="278.930725" y="786.15625"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="270.929688" y="747.167969"/>
+ <use xlink:href="#glyph0-2" x="276.265274" y="747.167969"/>
+ <use xlink:href="#glyph0-7" x="278.930725" y="747.167969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="270.929688" y="708.175781"/>
+ <use xlink:href="#glyph0-2" x="276.265274" y="708.175781"/>
+ <use xlink:href="#glyph0-8" x="278.930725" y="708.175781"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="270.929688" y="669.183594"/>
+ <use xlink:href="#glyph0-2" x="276.265274" y="669.183594"/>
+ <use xlink:href="#glyph0-9" x="278.930725" y="669.183594"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 821.710938 L 291.351562 821.710938 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 782.71875 L 291.351562 782.71875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 743.730469 L 291.351562 743.730469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 704.738281 L 291.351562 704.738281 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 665.746094 L 291.351562 665.746094 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 831.28125 L 299.03125 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 831.28125 L 337.417969 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 831.28125 L 375.808594 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 831.28125 L 414.199219 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 831.28125 L 452.589844 827.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="840.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="840.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="840.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="853.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="258.992188" y="756.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="258.992188" y="749.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="258.992188" y="744.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="258.992188" y="738.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-25" x="287.011719" y="658.800781"/>
+ <use xlink:href="#glyph5-4" x="296.345703" y="658.800781"/>
+ <use xlink:href="#glyph5-26" x="303.019531" y="658.800781"/>
+ <use xlink:href="#glyph5-18" x="310.349609" y="658.800781"/>
+ <use xlink:href="#glyph5-18" x="317.023438" y="658.800781"/>
+ <use xlink:href="#glyph5-3" x="323.697266" y="658.800781"/>
+ <use xlink:href="#glyph5-4" x="327.03125" y="658.800781"/>
+ <use xlink:href="#glyph5-5" x="333.705078" y="658.800781"/>
+ <use xlink:href="#glyph5-10" x="341.035156" y="658.800781"/>
+ <use xlink:href="#glyph5-2" x="349.039062" y="658.800781"/>
+ <use xlink:href="#glyph5-15" x="353.708984" y="658.800781"/>
+ <use xlink:href="#glyph5-16" x="361.039062" y="658.800781"/>
+ <use xlink:href="#glyph5-26" x="368.369141" y="658.800781"/>
+ <use xlink:href="#glyph5-22" x="375.699219" y="658.800781"/>
+ <use xlink:href="#glyph5-24" x="382.373047" y="658.800781"/>
+</g>
+<g clip-path="url(#clip226)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 474.667969 864 L 712 864 L 712 648 L 474.667969 648 Z "/>
+</g>
+<g clip-path="url(#clip227)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 864 L 712 864 L 712 648 L 474.667969 648 Z "/>
+</g>
+<g clip-path="url(#clip228)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 827.027344 L 697.597656 827.027344 L 697.597656 662.398438 L 528.683594 662.398438 Z "/>
+</g>
+<g clip-path="url(#clip229)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 801.546875 L 697.601562 801.546875 "/>
+</g>
+<g clip-path="url(#clip230)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 763.496094 L 697.601562 763.496094 "/>
+</g>
+<g clip-path="url(#clip231)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 725.441406 L 697.601562 725.441406 "/>
+</g>
+<g clip-path="url(#clip232)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 687.390625 L 697.601562 687.390625 "/>
+</g>
+<g clip-path="url(#clip233)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 827.027344 L 555.558594 662.398438 "/>
+</g>
+<g clip-path="url(#clip234)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 827.027344 L 593.949219 662.398438 "/>
+</g>
+<g clip-path="url(#clip235)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 827.027344 L 632.335938 662.398438 "/>
+</g>
+<g clip-path="url(#clip236)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 827.027344 L 670.726562 662.398438 "/>
+</g>
+<g clip-path="url(#clip237)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 820.570312 L 697.601562 820.570312 "/>
+</g>
+<g clip-path="url(#clip238)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 782.519531 L 697.601562 782.519531 "/>
+</g>
+<g clip-path="url(#clip239)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 744.46875 L 697.601562 744.46875 "/>
+</g>
+<g clip-path="url(#clip240)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 706.417969 L 697.601562 706.417969 "/>
+</g>
+<g clip-path="url(#clip241)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 668.367188 L 697.601562 668.367188 "/>
+</g>
+<g clip-path="url(#clip242)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 827.027344 L 536.363281 662.398438 "/>
+</g>
+<g clip-path="url(#clip243)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 827.027344 L 574.753906 662.398438 "/>
+</g>
+<g clip-path="url(#clip244)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 827.027344 L 613.140625 662.398438 "/>
+</g>
+<g clip-path="url(#clip245)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 827.027344 L 651.53125 662.398438 "/>
+</g>
+<g clip-path="url(#clip246)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 827.027344 L 689.921875 662.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 536.363281 819.546875 L 536.671875 819.523438 L 536.976562 819.503906 L 537.285156 819.480469 L 537.59375 819.460938 L 538.210938 819.414062 L 538.515625 819.390625 L 539.132812 819.34375 L 539.441406 819.316406 L 539.746094 819.292969 L 540.054688 819.265625 L 540.363281 819.242188 L 540.980469 819.1875 L 541.285156 819.15625 L 541.902344 819.101562 L 542.210938 819.070312 L 542.515625 819.039062 L 543.75 818.914062 L 544.054688 818.878906 L 545.289062 818.738281 L 545.59375 818.699219 L 545.902344 818.664062 L 546.519531 818.585938 L 546.824219 818.542969 L 547.132812 818.503906 L 548.058594 818.375 L 548.363281 818.332031 L 549.289062 818.191406 L 549.59375 818.144531 L 550.828125 817.941406 L 551.132812 817.886719 L 552.058594 817.722656 L 552.363281 817.664062 L 552.980469 817.546875 L 553.597656 817.421875 L 553.902344 817.359375 L 554.828125 817.160156 L 555.132812 817.089844 L 555.441406 817.019531 L 555.75 816.945312 L 556.058594 816.875 L 556.367188 816.796875 L 556.671875 816.722656 L 557.289062 816.566406 L 557.597656 816.484375 L 557.902344 816.402344 L 558.519531 816.230469 L 558.828125 816.140625 L 559.136719 816.054688 L 559.441406 815.960938 L 560.058594 815.773438 L 560.367188 815.675781 L 560.671875 815.578125 L 560.980469 815.476562 L 561.90625 815.160156 L 562.210938 815.050781 L 562.828125 814.824219 L 563.445312 814.589844 L 563.75 814.46875 L 564.367188 814.21875 L 564.675781 814.089844 L 564.980469 813.957031 L 565.289062 813.824219 L 565.90625 813.550781 L 566.214844 813.40625 L 566.519531 813.261719 L 567.136719 812.964844 L 567.445312 812.808594 L 567.75 812.652344 L 568.058594 812.492188 L 568.367188 812.328125 L 568.984375 811.992188 L 569.289062 811.816406 L 569.597656 811.640625 L 569.90625 811.460938 L 570.214844 811.273438 L 570.519531 811.085938 L 570.828125 810.894531 L 571.136719 810.699219 L 571.445312 810.5 L 571.753906 810.296875 L 572.058594 810.085938 L 572.367188 809.875 L 572.675781 809.660156 L 572.984375 809.4375 L 573.289062 809.210938 L 573.597656 808.980469 L 573.90625 808.746094 L 574.214844 808.507812 L 574.523438 808.265625 L 574.828125 808.015625 L 575.136719 807.761719 L 575.753906 807.238281 L 576.058594 806.96875 L 576.367188 806.691406 L 576.675781 806.410156 L 576.984375 806.125 L 577.292969 805.832031 L 577.597656 805.53125 L 577.90625 805.230469 L 578.214844 804.917969 L 578.523438 804.601562 L 578.832031 804.277344 L 579.136719 803.949219 L 579.445312 803.613281 L 579.753906 803.269531 L 580.0625 802.917969 L 580.367188 802.5625 L 580.675781 802.195312 L 580.984375 801.824219 L 581.292969 801.445312 L 581.601562 801.058594 L 581.90625 800.664062 L 582.214844 800.257812 L 582.523438 799.847656 L 582.832031 799.429688 L 583.136719 799 L 583.445312 798.5625 L 583.753906 798.117188 L 584.0625 797.664062 L 584.371094 797.199219 L 584.675781 796.726562 L 584.984375 796.246094 L 585.292969 795.753906 L 585.601562 795.25 L 585.90625 794.738281 L 586.214844 794.214844 L 586.523438 793.679688 L 586.832031 793.136719 L 587.140625 792.582031 L 587.445312 792.015625 L 587.753906 791.4375 L 588.0625 790.847656 L 588.371094 790.246094 L 588.675781 789.632812 L 588.984375 789.003906 L 589.292969 788.367188 L 589.601562 787.714844 L 589.910156 787.050781 L 590.214844 786.371094 L 590.523438 785.679688 L 590.832031 784.972656 L 591.140625 784.25 L 591.445312 783.515625 L 591.753906 782.765625 L 592.0625 782 L 592.371094 781.21875 L 592.679688 780.421875 L 592.984375 779.609375 L 593.292969 778.78125 L 593.601562 777.9375 L 593.910156 777.074219 L 594.21875 776.191406 L 594.523438 775.292969 L 594.832031 774.378906 L 595.140625 773.441406 L 595.449219 772.488281 L 595.753906 771.515625 L 596.0625 770.523438 L 596.371094 769.507812 L 596.679688 768.476562 L 596.988281 767.421875 L 597.292969 766.34375 L 597.601562 765.246094 L 597.910156 764.128906 L 598.21875 762.984375 L 598.523438 761.820312 L 598.832031 760.628906 L 599.140625 759.417969 L 599.449219 758.179688 L 599.757812 756.914062 L 600.0625 755.628906 L 600.371094 754.3125 L 600.679688 752.972656 L 600.988281 751.601562 L 601.292969 750.207031 L 601.601562 748.78125 L 601.910156 747.328125 L 602.21875 745.847656 L 602.527344 744.335938 L 602.832031 742.789062 L 603.140625 741.214844 L 603.449219 739.609375 L 603.757812 737.972656 L 604.0625 736.300781 L 604.371094 734.59375 L 604.679688 732.851562 L 604.988281 731.078125 L 605.296875 729.265625 L 605.601562 727.417969 L 605.910156 725.53125 L 606.21875 723.609375 L 606.527344 721.644531 L 606.832031 719.644531 L 607.140625 717.601562 L 607.449219 715.515625 L 607.757812 713.390625 L 608.066406 711.21875 L 608.371094 709.007812 L 608.679688 706.746094 L 608.988281 704.445312 L 609.296875 702.09375 L 609.601562 699.695312 L 609.910156 697.246094 L 610.21875 694.75 L 610.527344 692.203125 L 610.835938 689.605469 L 611.140625 686.953125 L 611.449219 684.25 L 611.757812 681.492188 L 612.066406 678.675781 L 612.375 675.804688 L 612.679688 672.871094 L 612.988281 669.882812 L 613.296875 669.882812 L 613.605469 672.871094 L 613.910156 675.804688 L 614.21875 678.675781 L 614.527344 681.492188 L 614.835938 684.25 L 615.144531 686.953125 L 615.449219 689.605469 L 615.757812 692.203125 L 616.066406 694.75 L 616.375 697.246094 L 616.679688 699.695312 L 616.988281 702.09375 L 617.296875 704.445312 L 617.605469 706.746094 L 617.914062 709.007812 L 618.21875 711.21875 L 618.527344 713.390625 L 618.835938 715.515625 L 619.144531 717.601562 L 619.449219 719.644531 L 619.757812 721.644531 L 620.066406 723.609375 L 620.375 725.53125 L 620.683594 727.417969 L 620.988281 729.265625 L 621.296875 731.078125 L 621.605469 732.851562 L 621.914062 734.59375 L 622.21875 736.300781 L 622.527344 737.972656 L 622.835938 739.609375 L 623.144531 741.214844 L 623.453125 742.789062 L 623.757812 744.335938 L 624.066406 745.847656 L 624.375 747.328125 L 624.683594 748.78125 L 624.988281 750.207031 L 625.296875 751.601562 L 625.605469 752.972656 L 625.914062 754.3125 L 626.222656 755.628906 L 626.527344 756.914062 L 626.835938 758.179688 L 627.144531 759.417969 L 627.453125 760.628906 L 627.761719 761.820312 L 628.066406 762.984375 L 628.375 764.128906 L 628.683594 765.246094 L 628.992188 766.34375 L 629.296875 767.421875 L 629.605469 768.476562 L 629.914062 769.507812 L 630.222656 770.523438 L 630.53125 771.515625 L 630.835938 772.488281 L 631.144531 773.441406 L 631.453125 774.378906 L 631.761719 775.292969 L 632.066406 776.191406 L 632.375 777.074219 L 632.683594 777.9375 L 632.992188 778.78125 L 633.300781 779.609375 L 633.605469 780.421875 L 633.914062 781.21875 L 634.222656 782 L 634.53125 782.765625 L 634.835938 783.515625 L 635.144531 784.25 L 635.453125 784.972656 L 635.761719 785.679688 L 636.070312 786.371094 L 636.375 787.050781 L 636.683594 787.714844 L 636.992188 788.367188 L 637.300781 789.003906 L 637.605469 789.632812 L 637.914062 790.246094 L 638.222656 790.847656 L 638.53125 791.4375 L 638.839844 792.015625 L 639.144531 792.582031 L 639.453125 793.136719 L 639.761719 793.679688 L 640.070312 794.214844 L 640.375 794.738281 L 640.683594 795.25 L 640.992188 795.753906 L 641.300781 796.246094 L 641.609375 796.726562 L 641.914062 797.199219 L 642.222656 797.664062 L 642.53125 798.117188 L 642.839844 798.5625 L 643.148438 799 L 643.453125 799.429688 L 643.761719 799.847656 L 644.070312 800.257812 L 644.378906 800.664062 L 644.683594 801.058594 L 644.992188 801.445312 L 645.300781 801.824219 L 645.609375 802.195312 L 645.917969 802.5625 L 646.222656 802.917969 L 646.53125 803.269531 L 646.839844 803.613281 L 647.148438 803.949219 L 647.453125 804.277344 L 647.761719 804.601562 L 648.070312 804.917969 L 648.378906 805.230469 L 648.6875 805.53125 L 648.992188 805.832031 L 649.300781 806.125 L 649.609375 806.410156 L 649.917969 806.691406 L 650.222656 806.96875 L 650.53125 807.238281 L 651.148438 807.761719 L 651.457031 808.015625 L 651.761719 808.265625 L 652.070312 808.507812 L 652.378906 808.746094 L 652.6875 808.980469 L 652.992188 809.210938 L 653.300781 809.4375 L 653.609375 809.660156 L 653.917969 809.875 L 654.226562 810.085938 L 654.53125 810.296875 L 654.839844 810.5 L 655.148438 810.699219 L 655.457031 810.894531 L 655.761719 811.085938 L 656.378906 811.460938 L 656.6875 811.640625 L 656.996094 811.816406 L 657.300781 811.992188 L 657.917969 812.328125 L 658.226562 812.492188 L 658.53125 812.652344 L 659.148438 812.964844 L 659.765625 813.261719 L 660.070312 813.40625 L 660.378906 813.550781 L 660.996094 813.824219 L 661.304688 813.957031 L 661.609375 814.089844 L 661.917969 814.21875 L 662.535156 814.46875 L 662.839844 814.589844 L 663.457031 814.824219 L 664.074219 815.050781 L 664.378906 815.160156 L 665.304688 815.476562 L 665.609375 815.578125 L 666.226562 815.773438 L 666.84375 815.960938 L 667.148438 816.054688 L 667.457031 816.140625 L 667.765625 816.230469 L 668.074219 816.316406 L 668.378906 816.402344 L 668.996094 816.566406 L 669.613281 816.722656 L 669.917969 816.796875 L 670.226562 816.875 L 670.535156 816.945312 L 670.84375 817.019531 L 671.148438 817.089844 L 671.457031 817.160156 L 672.382812 817.359375 L 672.6875 817.421875 L 673.304688 817.546875 L 673.613281 817.605469 L 673.917969 817.664062 L 674.226562 817.722656 L 675.152344 817.886719 L 675.457031 817.941406 L 676.691406 818.144531 L 676.996094 818.191406 L 677.921875 818.332031 L 678.226562 818.375 L 679.152344 818.503906 L 679.460938 818.542969 L 679.765625 818.585938 L 680.382812 818.664062 L 680.691406 818.699219 L 680.996094 818.738281 L 682.230469 818.878906 L 682.535156 818.914062 L 683.460938 819.007812 L 683.765625 819.039062 L 684.382812 819.101562 L 685 819.15625 L 685.304688 819.1875 L 685.921875 819.242188 L 686.230469 819.265625 L 686.535156 819.292969 L 686.84375 819.316406 L 687.152344 819.34375 L 687.769531 819.390625 L 688.074219 819.414062 L 688.691406 819.460938 L 689 819.480469 L 689.304688 819.503906 L 689.613281 819.523438 L 689.921875 819.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="824.007812"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="824.007812"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="824.007812"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="824.007812"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="785.957031"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="785.957031"/>
+ <use xlink:href="#glyph0-3" x="510.926819" y="785.957031"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="785.957031"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="747.90625"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="747.90625"/>
+ <use xlink:href="#glyph0-4" x="510.926819" y="747.90625"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="747.90625"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="709.855469"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="709.855469"/>
+ <use xlink:href="#glyph0-5" x="510.926819" y="709.855469"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="709.855469"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="502.925781" y="671.804688"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="671.804688"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="671.804688"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="671.804688"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 820.570312 L 528.683594 820.570312 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 782.519531 L 528.683594 782.519531 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 744.46875 L 528.683594 744.46875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 706.417969 L 528.683594 706.417969 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 668.367188 L 528.683594 668.367188 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 831.28125 L 536.363281 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 831.28125 L 574.753906 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 831.28125 L 613.140625 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 831.28125 L 651.53125 827.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 831.28125 L 689.921875 827.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="840.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="840.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="840.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="840.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="840.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="840.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="840.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="853.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="496.324219" y="756.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.324219" y="749.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.324219" y="744.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.324219" y="738.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-11" x="490.675781" y="658.800781"/>
+ <use xlink:href="#glyph5-13" x="498.679688" y="658.800781"/>
+ <use xlink:href="#glyph5-3" x="506.009766" y="658.800781"/>
+ <use xlink:href="#glyph5-27" x="509.34375" y="658.800781"/>
+ <use xlink:href="#glyph5-8" x="516.017578" y="658.800781"/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 1080 L 237.332031 1080 L 237.332031 864 L 0 864 Z "/>
+<g clip-path="url(#clip247)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 1080 L 237.332031 1080 L 237.332031 864 L 0 864 Z "/>
+</g>
+<g clip-path="url(#clip248)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 1043.027344 L 222.933594 1043.027344 L 222.933594 878.398438 L 54.019531 878.398438 Z "/>
+</g>
+<g clip-path="url(#clip249)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1016.839844 L 222.933594 1016.839844 "/>
+</g>
+<g clip-path="url(#clip250)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 979.421875 L 222.933594 979.421875 "/>
+</g>
+<g clip-path="url(#clip251)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 942.007812 L 222.933594 942.007812 "/>
+</g>
+<g clip-path="url(#clip252)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 904.589844 L 222.933594 904.589844 "/>
+</g>
+<g clip-path="url(#clip253)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 1043.027344 L 80.890625 878.398438 "/>
+</g>
+<g clip-path="url(#clip254)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 1043.027344 L 119.28125 878.398438 "/>
+</g>
+<g clip-path="url(#clip255)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 1043.027344 L 157.671875 878.398438 "/>
+</g>
+<g clip-path="url(#clip256)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 1043.027344 L 196.058594 878.398438 "/>
+</g>
+<g clip-path="url(#clip257)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1035.546875 L 222.933594 1035.546875 "/>
+</g>
+<g clip-path="url(#clip258)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 998.128906 L 222.933594 998.128906 "/>
+</g>
+<g clip-path="url(#clip259)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 960.714844 L 222.933594 960.714844 "/>
+</g>
+<g clip-path="url(#clip260)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 923.296875 L 222.933594 923.296875 "/>
+</g>
+<g clip-path="url(#clip261)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 885.882812 L 222.933594 885.882812 "/>
+</g>
+<g clip-path="url(#clip262)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 1043.027344 L 61.695312 878.398438 "/>
+</g>
+<g clip-path="url(#clip263)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 1043.027344 L 100.085938 878.398438 "/>
+</g>
+<g clip-path="url(#clip264)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 1043.027344 L 138.476562 878.398438 "/>
+</g>
+<g clip-path="url(#clip265)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 1043.027344 L 176.867188 878.398438 "/>
+</g>
+<g clip-path="url(#clip266)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 1043.027344 L 215.253906 878.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 1035.546875 L 176.789062 1035.546875 L 177.097656 885.882812 L 215.253906 885.882812 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 885.882812 L 99.855469 885.882812 L 100.164062 1035.546875 L 215.253906 1035.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="1038.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1038.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="1038.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="1038.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="1001.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1001.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="1001.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="1001.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="964.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="964.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="964.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="964.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="926.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="926.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="926.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="926.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="889.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="889.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="889.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="889.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1035.546875 L 54.019531 1035.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 998.128906 L 54.019531 998.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 960.714844 L 54.019531 960.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 923.296875 L 54.019531 923.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 885.882812 L 54.019531 885.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 1047.28125 L 61.695312 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 1047.28125 L 100.085938 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 1047.28125 L 138.476562 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 1047.28125 L 176.867188 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 1047.28125 L 215.253906 1043.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="1056.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="1056.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="1056.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="1069.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="972.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="965.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="960.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="954.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-9" x="18.671875" y="874.800781"/>
+ <use xlink:href="#glyph5-3" x="27.337891" y="874.800781"/>
+ <use xlink:href="#glyph5-5" x="30.671875" y="874.800781"/>
+ <use xlink:href="#glyph5-4" x="38.001953" y="874.800781"/>
+ <use xlink:href="#glyph5-2" x="44.675781" y="874.800781"/>
+ <use xlink:href="#glyph5-28" x="49.345703" y="874.800781"/>
+</g>
+<g clip-path="url(#clip267)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 1080 L 474.664062 1080 L 474.664062 864 L 237.332031 864 Z "/>
+</g>
+<g clip-path="url(#clip268)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 1080 L 474.664062 1080 L 474.664062 864 L 237.332031 864 Z "/>
+</g>
+<g clip-path="url(#clip269)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 1043.027344 L 460.265625 1043.027344 L 460.265625 878.398438 L 291.351562 878.398438 Z "/>
+</g>
+<g clip-path="url(#clip270)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1016.839844 L 460.265625 1016.839844 "/>
+</g>
+<g clip-path="url(#clip271)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 979.421875 L 460.265625 979.421875 "/>
+</g>
+<g clip-path="url(#clip272)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 942.007812 L 460.265625 942.007812 "/>
+</g>
+<g clip-path="url(#clip273)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 904.589844 L 460.265625 904.589844 "/>
+</g>
+<g clip-path="url(#clip274)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 1043.027344 L 318.222656 878.398438 "/>
+</g>
+<g clip-path="url(#clip275)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 1043.027344 L 356.613281 878.398438 "/>
+</g>
+<g clip-path="url(#clip276)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 1043.027344 L 395.003906 878.398438 "/>
+</g>
+<g clip-path="url(#clip277)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 1043.027344 L 433.394531 878.398438 "/>
+</g>
+<g clip-path="url(#clip278)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1035.546875 L 460.265625 1035.546875 "/>
+</g>
+<g clip-path="url(#clip279)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 998.128906 L 460.265625 998.128906 "/>
+</g>
+<g clip-path="url(#clip280)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 960.714844 L 460.265625 960.714844 "/>
+</g>
+<g clip-path="url(#clip281)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 923.296875 L 460.265625 923.296875 "/>
+</g>
+<g clip-path="url(#clip282)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 885.882812 L 460.265625 885.882812 "/>
+</g>
+<g clip-path="url(#clip283)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 1043.027344 L 299.03125 878.398438 "/>
+</g>
+<g clip-path="url(#clip284)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 1043.027344 L 337.417969 878.398438 "/>
+</g>
+<g clip-path="url(#clip285)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 1043.027344 L 375.808594 878.398438 "/>
+</g>
+<g clip-path="url(#clip286)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 1043.027344 L 414.199219 878.398438 "/>
+</g>
+<g clip-path="url(#clip287)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 1043.027344 L 452.589844 878.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 1035.546875 L 329.496094 1035.546875 L 329.804688 1035.445312 L 330.109375 1034.945312 L 331.035156 1033.445312 L 331.339844 1032.945312 L 332.574219 1030.945312 L 332.878906 1030.445312 L 333.1875 1029.949219 L 333.804688 1028.949219 L 334.109375 1028.449219 L 335.34375 1026.449219 L 335.648438 1025.949219 L 336.574219 1024.449219 L 336.878906 1023.949219 L 338.113281 1021.949219 L 338.417969 1021.449219 L 339.34375 1019.949219 L 339.648438 1019.449219 L 340.882812 1017.449219 L 341.1875 1016.949219 L 342.421875 1014.949219 L 342.726562 1014.449219 L 343.035156 1013.953125 L 343.652344 1012.953125 L 343.957031 1012.453125 L 345.191406 1010.453125 L 345.496094 1009.953125 L 346.421875 1008.453125 L 346.726562 1007.953125 L 347.960938 1005.953125 L 348.265625 1005.453125 L 349.191406 1003.953125 L 349.496094 1003.453125 L 350.730469 1001.453125 L 351.035156 1000.953125 L 351.960938 999.453125 L 352.265625 998.953125 L 352.574219 998.457031 L 353.5 996.957031 L 353.804688 996.457031 L 354.730469 994.957031 L 355.035156 994.457031 L 356.269531 992.457031 L 356.574219 991.957031 L 357.808594 989.957031 L 358.113281 989.457031 L 359.039062 987.957031 L 359.34375 987.457031 L 360.578125 985.457031 L 360.882812 984.957031 L 361.808594 983.457031 L 362.113281 982.957031 L 362.421875 982.460938 L 363.347656 980.960938 L 363.652344 980.460938 L 364.578125 978.960938 L 364.882812 978.460938 L 366.117188 976.460938 L 366.421875 975.960938 L 367.347656 974.460938 L 367.652344 973.960938 L 368.886719 971.960938 L 369.191406 971.460938 L 370.117188 969.960938 L 370.421875 969.460938 L 371.65625 967.460938 L 371.960938 966.964844 L 373.195312 964.964844 L 373.5 964.464844 L 374.425781 962.964844 L 374.730469 962.464844 L 375.964844 960.464844 L 376.269531 959.964844 L 377.195312 958.464844 L 377.5 957.964844 L 378.734375 955.964844 L 379.039062 955.464844 L 379.964844 953.964844 L 380.269531 953.464844 L 381.195312 951.964844 L 381.503906 951.46875 L 381.808594 950.96875 L 382.734375 949.46875 L 383.039062 948.96875 L 384.273438 946.96875 L 384.578125 946.46875 L 385.503906 944.96875 L 385.808594 944.46875 L 387.042969 942.46875 L 387.347656 941.96875 L 388.273438 940.46875 L 388.578125 939.96875 L 389.8125 937.96875 L 390.117188 937.46875 L 391.042969 935.96875 L 391.351562 935.472656 L 391.65625 934.972656 L 392.582031 933.472656 L 392.886719 932.972656 L 394.121094 930.972656 L 394.425781 930.472656 L 395.351562 928.972656 L 395.65625 928.472656 L 396.890625 926.472656 L 397.195312 925.972656 L 398.121094 924.472656 L 398.425781 923.972656 L 399.660156 921.972656 L 399.964844 921.472656 L 400.582031 920.472656 L 400.890625 919.976562 L 401.195312 919.476562 L 402.429688 917.476562 L 402.734375 916.976562 L 403.660156 915.476562 L 403.964844 914.976562 L 405.199219 912.976562 L 405.503906 912.476562 L 406.738281 910.476562 L 407.042969 909.976562 L 407.96875 908.476562 L 408.273438 907.976562 L 409.507812 905.976562 L 409.8125 905.476562 L 410.429688 904.476562 L 410.738281 903.980469 L 411.042969 903.480469 L 412.277344 901.480469 L 412.582031 900.980469 L 413.507812 899.480469 L 413.8125 898.980469 L 415.046875 896.980469 L 415.351562 896.480469 L 416.277344 894.980469 L 416.582031 894.480469 L 417.816406 892.480469 L 418.121094 891.980469 L 419.046875 890.480469 L 419.351562 889.980469 L 419.96875 888.980469 L 420.277344 888.484375 L 420.585938 887.984375 L 420.890625 887.484375 L 421.816406 885.984375 L 422.125 885.882812 L 452.589844 885.882812 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 885.882812 L 329.496094 885.882812 L 329.804688 885.984375 L 330.109375 886.484375 L 331.035156 887.984375 L 331.339844 888.484375 L 331.648438 888.980469 L 332.574219 890.480469 L 332.878906 890.980469 L 333.804688 892.480469 L 334.109375 892.980469 L 335.34375 894.980469 L 335.648438 895.480469 L 336.574219 896.980469 L 336.878906 897.480469 L 338.113281 899.480469 L 338.417969 899.980469 L 339.34375 901.480469 L 339.648438 901.980469 L 340.882812 903.980469 L 341.1875 904.476562 L 342.421875 906.476562 L 342.726562 906.976562 L 343.652344 908.476562 L 343.957031 908.976562 L 345.191406 910.976562 L 345.496094 911.476562 L 346.421875 912.976562 L 346.726562 913.476562 L 347.960938 915.476562 L 348.265625 915.976562 L 349.191406 917.476562 L 349.496094 917.976562 L 350.730469 919.976562 L 351.035156 920.472656 L 351.960938 921.972656 L 352.265625 922.472656 L 353.5 924.472656 L 353.804688 924.972656 L 354.730469 926.472656 L 355.035156 926.972656 L 356.269531 928.972656 L 356.574219 929.472656 L 357.808594 931.472656 L 358.113281 931.972656 L 359.039062 933.472656 L 359.34375 933.972656 L 360.269531 935.472656 L 360.578125 935.96875 L 360.882812 936.46875 L 361.808594 937.96875 L 362.113281 938.46875 L 363.347656 940.46875 L 363.652344 940.96875 L 364.578125 942.46875 L 364.882812 942.96875 L 366.117188 944.96875 L 366.421875 945.46875 L 367.347656 946.96875 L 367.652344 947.46875 L 368.886719 949.46875 L 369.191406 949.96875 L 370.117188 951.46875 L 370.421875 951.964844 L 371.65625 953.964844 L 371.960938 954.464844 L 373.195312 956.464844 L 373.5 956.964844 L 374.425781 958.464844 L 374.730469 958.964844 L 375.964844 960.964844 L 376.269531 961.464844 L 377.195312 962.964844 L 377.5 963.464844 L 378.734375 965.464844 L 379.039062 965.964844 L 379.65625 966.964844 L 379.964844 967.460938 L 380.269531 967.960938 L 381.503906 969.960938 L 381.808594 970.460938 L 382.734375 971.960938 L 383.039062 972.460938 L 384.273438 974.460938 L 384.578125 974.960938 L 385.503906 976.460938 L 385.808594 976.960938 L 387.042969 978.960938 L 387.347656 979.460938 L 388.273438 980.960938 L 388.578125 981.460938 L 389.195312 982.460938 L 389.503906 982.957031 L 389.8125 983.457031 L 390.117188 983.957031 L 391.351562 985.957031 L 391.65625 986.457031 L 392.582031 987.957031 L 392.886719 988.457031 L 394.121094 990.457031 L 394.425781 990.957031 L 395.351562 992.457031 L 395.65625 992.957031 L 396.890625 994.957031 L 397.195312 995.457031 L 398.121094 996.957031 L 398.425781 997.457031 L 399.042969 998.457031 L 399.351562 998.953125 L 399.660156 999.453125 L 399.964844 999.953125 L 400.890625 1001.453125 L 401.195312 1001.953125 L 402.429688 1003.953125 L 402.734375 1004.453125 L 403.660156 1005.953125 L 403.964844 1006.453125 L 405.199219 1008.453125 L 405.503906 1008.953125 L 406.738281 1010.953125 L 407.042969 1011.453125 L 407.96875 1012.953125 L 408.273438 1013.453125 L 408.582031 1013.953125 L 408.890625 1014.449219 L 409.507812 1015.449219 L 409.8125 1015.949219 L 410.738281 1017.449219 L 411.042969 1017.949219 L 412.277344 1019.949219 L 412.582031 1020.449219 L 413.507812 1021.949219 L 413.8125 1022.449219 L 415.046875 1024.449219 L 415.351562 1024.949219 L 416.277344 1026.449219 L 416.582031 1026.949219 L 417.816406 1028.949219 L 418.121094 1029.449219 L 418.429688 1029.949219 L 418.738281 1030.445312 L 419.046875 1030.945312 L 419.351562 1031.445312 L 420.585938 1033.445312 L 420.890625 1033.945312 L 421.816406 1035.445312 L 422.125 1035.546875 L 452.589844 1035.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1038.984375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1038.984375"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="1038.984375"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1038.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1001.566406"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1001.566406"/>
+ <use xlink:href="#glyph0-3" x="273.594788" y="1001.566406"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="1001.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="964.152344"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="964.152344"/>
+ <use xlink:href="#glyph0-4" x="273.594788" y="964.152344"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="964.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="926.734375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="926.734375"/>
+ <use xlink:href="#glyph0-5" x="273.594788" y="926.734375"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="926.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="265.59375" y="889.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="889.320312"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="889.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="889.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1035.546875 L 291.351562 1035.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 998.128906 L 291.351562 998.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 960.714844 L 291.351562 960.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 923.296875 L 291.351562 923.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 885.882812 L 291.351562 885.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 1047.28125 L 299.03125 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 1047.28125 L 337.417969 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 1047.28125 L 375.808594 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 1047.28125 L 414.199219 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 1047.28125 L 452.589844 1043.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="1056.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="1056.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="1056.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="1069.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="258.992188" y="972.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="258.992188" y="965.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="258.992188" y="960.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="258.992188" y="954.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-23" x="254.003906" y="874.800781"/>
+ <use xlink:href="#glyph5-4" x="262.669922" y="874.800781"/>
+ <use xlink:href="#glyph5-19" x="269.34375" y="874.800781"/>
+ <use xlink:href="#glyph5-13" x="280.013672" y="874.800781"/>
+</g>
+<g clip-path="url(#clip288)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 474.667969 1080 L 712 1080 L 712 864 L 474.667969 864 Z "/>
+</g>
+<g clip-path="url(#clip289)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 1080 L 712 1080 L 712 864 L 474.667969 864 Z "/>
+</g>
+<g clip-path="url(#clip290)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 1043.027344 L 697.597656 1043.027344 L 697.597656 878.398438 L 528.683594 878.398438 Z "/>
+</g>
+<g clip-path="url(#clip291)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1016.839844 L 697.601562 1016.839844 "/>
+</g>
+<g clip-path="url(#clip292)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 979.421875 L 697.601562 979.421875 "/>
+</g>
+<g clip-path="url(#clip293)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 942.007812 L 697.601562 942.007812 "/>
+</g>
+<g clip-path="url(#clip294)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 904.589844 L 697.601562 904.589844 "/>
+</g>
+<g clip-path="url(#clip295)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 1043.027344 L 555.558594 878.398438 "/>
+</g>
+<g clip-path="url(#clip296)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 1043.027344 L 593.949219 878.398438 "/>
+</g>
+<g clip-path="url(#clip297)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 1043.027344 L 632.335938 878.398438 "/>
+</g>
+<g clip-path="url(#clip298)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 1043.027344 L 670.726562 878.398438 "/>
+</g>
+<g clip-path="url(#clip299)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1035.546875 L 697.601562 1035.546875 "/>
+</g>
+<g clip-path="url(#clip300)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 998.128906 L 697.601562 998.128906 "/>
+</g>
+<g clip-path="url(#clip301)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 960.714844 L 697.601562 960.714844 "/>
+</g>
+<g clip-path="url(#clip302)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 923.296875 L 697.601562 923.296875 "/>
+</g>
+<g clip-path="url(#clip303)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 885.882812 L 697.601562 885.882812 "/>
+</g>
+<g clip-path="url(#clip304)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 1043.027344 L 536.363281 878.398438 "/>
+</g>
+<g clip-path="url(#clip305)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 1043.027344 L 574.753906 878.398438 "/>
+</g>
+<g clip-path="url(#clip306)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 1043.027344 L 613.140625 878.398438 "/>
+</g>
+<g clip-path="url(#clip307)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 1043.027344 L 651.53125 878.398438 "/>
+</g>
+<g clip-path="url(#clip308)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 1043.027344 L 689.921875 878.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 536.363281 1035.546875 L 536.671875 1035.542969 L 536.976562 1035.542969 L 537.59375 1035.527344 L 538.210938 1035.503906 L 538.515625 1035.488281 L 539.132812 1035.449219 L 539.441406 1035.425781 L 539.746094 1035.402344 L 540.054688 1035.371094 L 540.363281 1035.34375 L 540.671875 1035.308594 L 540.980469 1035.277344 L 541.285156 1035.238281 L 541.59375 1035.199219 L 542.210938 1035.113281 L 542.515625 1035.066406 L 543.132812 1034.964844 L 543.441406 1034.910156 L 543.75 1034.851562 L 544.054688 1034.792969 L 544.363281 1034.734375 L 545.289062 1034.535156 L 545.59375 1034.464844 L 546.210938 1034.316406 L 546.519531 1034.238281 L 546.824219 1034.15625 L 547.132812 1034.074219 L 547.441406 1033.988281 L 548.058594 1033.808594 L 548.363281 1033.71875 L 549.289062 1033.425781 L 549.59375 1033.324219 L 550.210938 1033.113281 L 550.519531 1033.003906 L 550.828125 1032.890625 L 551.132812 1032.777344 L 551.441406 1032.660156 L 552.058594 1032.417969 L 552.363281 1032.296875 L 553.289062 1031.910156 L 553.597656 1031.777344 L 553.902344 1031.640625 L 554.210938 1031.503906 L 554.519531 1031.363281 L 554.828125 1031.21875 L 555.132812 1031.074219 L 555.441406 1030.925781 L 556.367188 1030.46875 L 556.671875 1030.308594 L 557.289062 1029.988281 L 557.597656 1029.824219 L 557.902344 1029.65625 L 558.828125 1029.140625 L 559.136719 1028.964844 L 559.441406 1028.785156 L 560.058594 1028.417969 L 560.367188 1028.230469 L 560.671875 1028.042969 L 561.289062 1027.660156 L 561.597656 1027.464844 L 561.90625 1027.265625 L 562.210938 1027.0625 L 562.828125 1026.65625 L 563.136719 1026.445312 L 563.445312 1026.238281 L 563.75 1026.023438 L 564.058594 1025.808594 L 564.675781 1025.371094 L 564.980469 1025.148438 L 565.289062 1024.925781 L 565.597656 1024.695312 L 565.90625 1024.46875 L 566.214844 1024.234375 L 566.519531 1024 L 566.828125 1023.765625 L 567.445312 1023.28125 L 567.75 1023.039062 L 568.058594 1022.792969 L 568.675781 1022.292969 L 568.984375 1022.039062 L 569.289062 1021.78125 L 569.597656 1021.523438 L 570.214844 1021 L 570.519531 1020.734375 L 571.136719 1020.195312 L 571.753906 1019.648438 L 572.058594 1019.371094 L 572.675781 1018.808594 L 572.984375 1018.523438 L 573.289062 1018.234375 L 573.597656 1017.945312 L 574.214844 1017.359375 L 574.523438 1017.0625 L 574.828125 1016.761719 L 575.136719 1016.460938 L 575.753906 1015.851562 L 576.058594 1015.542969 L 576.675781 1014.917969 L 576.984375 1014.601562 L 577.292969 1014.28125 L 577.597656 1013.960938 L 578.214844 1013.3125 L 578.523438 1012.984375 L 578.832031 1012.652344 L 579.136719 1012.320312 L 579.753906 1011.648438 L 580.0625 1011.304688 L 580.367188 1010.964844 L 580.675781 1010.617188 L 580.984375 1010.273438 L 581.601562 1009.570312 L 581.90625 1009.214844 L 582.214844 1008.859375 L 582.523438 1008.5 L 582.832031 1008.136719 L 583.136719 1007.773438 L 583.445312 1007.40625 L 584.371094 1006.292969 L 584.675781 1005.914062 L 585.292969 1005.15625 L 585.601562 1004.773438 L 585.90625 1004.386719 L 586.832031 1003.214844 L 587.140625 1002.820312 L 587.445312 1002.421875 L 588.0625 1001.617188 L 588.371094 1001.210938 L 588.675781 1000.804688 L 589.292969 999.984375 L 589.601562 999.566406 L 589.910156 999.152344 L 590.214844 998.730469 L 590.832031 997.886719 L 591.140625 997.457031 L 591.445312 997.027344 L 591.753906 996.597656 L 592.0625 996.164062 L 592.679688 995.289062 L 592.984375 994.847656 L 593.601562 993.957031 L 594.21875 993.058594 L 594.523438 992.605469 L 595.140625 991.691406 L 595.449219 991.230469 L 595.753906 990.769531 L 596.0625 990.304688 L 596.679688 989.367188 L 596.988281 988.894531 L 597.292969 988.417969 L 597.601562 987.941406 L 598.21875 986.980469 L 598.523438 986.496094 L 599.140625 985.519531 L 599.757812 984.535156 L 600.0625 984.035156 L 600.371094 983.539062 L 600.988281 982.53125 L 601.292969 982.027344 L 601.601562 981.519531 L 602.21875 980.496094 L 602.527344 979.980469 L 602.832031 979.460938 L 603.140625 978.941406 L 603.449219 978.417969 L 603.757812 977.890625 L 604.0625 977.363281 L 604.679688 976.300781 L 605.296875 975.230469 L 605.601562 974.6875 L 605.910156 974.148438 L 606.527344 973.054688 L 606.832031 972.507812 L 607.757812 970.84375 L 608.066406 970.285156 L 608.371094 969.722656 L 608.679688 969.160156 L 608.988281 968.59375 L 609.296875 968.023438 L 609.601562 967.453125 L 610.21875 966.304688 L 610.527344 965.726562 L 610.835938 965.144531 L 611.140625 964.5625 L 611.757812 963.390625 L 612.066406 962.800781 L 612.375 962.207031 L 612.679688 961.613281 L 612.988281 961.015625 L 613.296875 960.414062 L 613.605469 959.816406 L 613.910156 959.222656 L 614.21875 958.628906 L 614.527344 958.039062 L 615.144531 956.867188 L 615.449219 956.285156 L 615.757812 955.703125 L 616.375 954.546875 L 616.679688 953.976562 L 616.988281 953.402344 L 617.605469 952.269531 L 617.914062 951.707031 L 618.21875 951.144531 L 618.835938 950.027344 L 619.144531 949.472656 L 619.449219 948.921875 L 620.375 947.28125 L 620.683594 946.738281 L 620.988281 946.199219 L 621.914062 944.59375 L 622.21875 944.066406 L 622.835938 943.011719 L 623.144531 942.488281 L 623.453125 941.96875 L 623.757812 941.449219 L 624.066406 940.933594 L 624.683594 939.910156 L 624.988281 939.402344 L 625.296875 938.894531 L 625.605469 938.390625 L 626.222656 937.390625 L 626.527344 936.894531 L 627.144531 935.910156 L 627.761719 934.933594 L 628.066406 934.449219 L 628.683594 933.488281 L 628.992188 933.011719 L 629.296875 932.535156 L 629.605469 932.0625 L 630.222656 931.125 L 630.53125 930.660156 L 630.835938 930.199219 L 631.453125 929.277344 L 631.761719 928.824219 L 632.066406 928.371094 L 632.375 927.917969 L 632.683594 927.472656 L 632.992188 927.023438 L 633.300781 926.582031 L 633.605469 926.140625 L 634.222656 925.265625 L 634.53125 924.832031 L 634.835938 924.398438 L 635.144531 923.96875 L 635.453125 923.542969 L 636.070312 922.699219 L 636.375 922.277344 L 636.683594 921.859375 L 636.992188 921.445312 L 637.300781 921.035156 L 637.605469 920.625 L 637.914062 920.214844 L 638.839844 919.007812 L 639.144531 918.609375 L 639.761719 917.820312 L 640.070312 917.429688 L 640.375 917.042969 L 640.683594 916.65625 L 641.300781 915.890625 L 641.609375 915.515625 L 641.914062 915.136719 L 642.222656 914.765625 L 642.53125 914.390625 L 643.148438 913.65625 L 643.453125 913.292969 L 643.761719 912.929688 L 644.070312 912.570312 L 644.378906 912.214844 L 644.683594 911.859375 L 645.300781 911.15625 L 645.609375 910.808594 L 645.917969 910.464844 L 646.222656 910.121094 L 646.53125 909.78125 L 647.148438 909.109375 L 647.453125 908.777344 L 647.761719 908.445312 L 648.070312 908.117188 L 648.6875 907.46875 L 648.992188 907.148438 L 649.300781 906.828125 L 649.609375 906.511719 L 649.917969 906.199219 L 650.222656 905.886719 L 650.53125 905.578125 L 651.148438 904.96875 L 651.457031 904.667969 L 651.761719 904.367188 L 652.378906 903.773438 L 652.6875 903.484375 L 652.992188 903.195312 L 653.300781 902.90625 L 653.609375 902.621094 L 654.226562 902.058594 L 654.53125 901.78125 L 654.839844 901.503906 L 655.148438 901.234375 L 655.457031 900.960938 L 655.761719 900.695312 L 656.378906 900.164062 L 656.6875 899.90625 L 656.996094 899.644531 L 657.300781 899.390625 L 657.609375 899.136719 L 658.226562 898.636719 L 658.53125 898.390625 L 658.839844 898.144531 L 659.148438 897.902344 L 659.457031 897.664062 L 659.765625 897.429688 L 660.070312 897.195312 L 660.378906 896.960938 L 660.6875 896.730469 L 660.996094 896.503906 L 661.304688 896.28125 L 661.609375 896.058594 L 661.917969 895.835938 L 662.535156 895.40625 L 662.839844 895.191406 L 663.148438 894.980469 L 663.765625 894.566406 L 664.074219 894.363281 L 664.378906 894.164062 L 664.6875 893.964844 L 664.996094 893.769531 L 665.304688 893.578125 L 665.609375 893.386719 L 665.917969 893.195312 L 666.84375 892.644531 L 667.148438 892.464844 L 667.765625 892.113281 L 668.074219 891.941406 L 668.378906 891.773438 L 668.6875 891.605469 L 668.996094 891.441406 L 669.613281 891.121094 L 669.917969 890.960938 L 670.226562 890.808594 L 670.535156 890.652344 L 670.84375 890.503906 L 671.148438 890.355469 L 671.765625 890.066406 L 672.074219 889.925781 L 672.382812 889.789062 L 672.6875 889.652344 L 673.304688 889.386719 L 673.613281 889.261719 L 673.917969 889.132812 L 674.226562 889.011719 L 674.535156 888.886719 L 675.152344 888.652344 L 675.457031 888.539062 L 675.765625 888.425781 L 676.074219 888.316406 L 676.691406 888.105469 L 676.996094 888.003906 L 677.304688 887.902344 L 677.613281 887.804688 L 677.921875 887.710938 L 678.226562 887.617188 L 678.535156 887.527344 L 679.152344 887.355469 L 679.460938 887.273438 L 679.765625 887.191406 L 680.074219 887.113281 L 680.691406 886.964844 L 680.996094 886.894531 L 681.304688 886.824219 L 681.613281 886.757812 L 682.230469 886.632812 L 682.535156 886.574219 L 683.152344 886.464844 L 683.460938 886.414062 L 683.765625 886.363281 L 684.074219 886.316406 L 684.691406 886.230469 L 685 886.191406 L 685.304688 886.152344 L 685.613281 886.117188 L 686.230469 886.054688 L 686.535156 886.027344 L 687.152344 885.980469 L 687.769531 885.941406 L 688.074219 885.925781 L 688.691406 885.902344 L 689 885.894531 L 689.304688 885.886719 L 689.613281 885.882812 L 689.921875 885.882812 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1038.984375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1038.984375"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="1038.984375"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1038.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1001.566406"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1001.566406"/>
+ <use xlink:href="#glyph0-3" x="510.926819" y="1001.566406"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="1001.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="964.152344"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="964.152344"/>
+ <use xlink:href="#glyph0-4" x="510.926819" y="964.152344"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="964.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="926.734375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="926.734375"/>
+ <use xlink:href="#glyph0-5" x="510.926819" y="926.734375"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="926.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="502.925781" y="889.320312"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="889.320312"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="889.320312"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="889.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1035.546875 L 528.683594 1035.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 998.128906 L 528.683594 998.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 960.714844 L 528.683594 960.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 923.296875 L 528.683594 923.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 885.882812 L 528.683594 885.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 1047.28125 L 536.363281 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 1047.28125 L 574.753906 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 1047.28125 L 613.140625 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 1047.28125 L 651.53125 1043.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 1047.28125 L 689.921875 1043.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="1056.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="1056.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="1056.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="1056.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="1056.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="1056.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="1056.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="1069.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="496.324219" y="972.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.324219" y="965.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.324219" y="960.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.324219" y="954.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-11" x="496.675781" y="874.800781"/>
+ <use xlink:href="#glyph5-11" x="504.679688" y="874.800781"/>
+ <use xlink:href="#glyph5-12" x="512.683594" y="874.800781"/>
+ <use xlink:href="#glyph5-4" x="520.013672" y="874.800781"/>
+ <use xlink:href="#glyph5-13" x="526.6875" y="874.800781"/>
+ <use xlink:href="#glyph5-8" x="534.017578" y="874.800781"/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 1296 L 237.332031 1296 L 237.332031 1080 L 0 1080 Z "/>
+<g clip-path="url(#clip309)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 1296 L 237.332031 1296 L 237.332031 1080 L 0 1080 Z "/>
+</g>
+<g clip-path="url(#clip310)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 1259.027344 L 222.933594 1259.027344 L 222.933594 1094.398438 L 54.019531 1094.398438 Z "/>
+</g>
+<g clip-path="url(#clip311)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1245.933594 L 222.933594 1245.933594 "/>
+</g>
+<g clip-path="url(#clip312)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1204.777344 L 222.933594 1204.777344 "/>
+</g>
+<g clip-path="url(#clip313)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1163.617188 L 222.933594 1163.617188 "/>
+</g>
+<g clip-path="url(#clip314)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1122.460938 L 222.933594 1122.460938 "/>
+</g>
+<g clip-path="url(#clip315)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 1259.027344 L 80.890625 1094.398438 "/>
+</g>
+<g clip-path="url(#clip316)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 1259.027344 L 119.28125 1094.398438 "/>
+</g>
+<g clip-path="url(#clip317)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 1259.027344 L 157.671875 1094.398438 "/>
+</g>
+<g clip-path="url(#clip318)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 1259.027344 L 196.058594 1094.398438 "/>
+</g>
+<g clip-path="url(#clip319)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1225.355469 L 222.933594 1225.355469 "/>
+</g>
+<g clip-path="url(#clip320)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1184.199219 L 222.933594 1184.199219 "/>
+</g>
+<g clip-path="url(#clip321)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1143.039062 L 222.933594 1143.039062 "/>
+</g>
+<g clip-path="url(#clip322)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1101.882812 L 222.933594 1101.882812 "/>
+</g>
+<g clip-path="url(#clip323)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 1259.027344 L 61.695312 1094.398438 "/>
+</g>
+<g clip-path="url(#clip324)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 1259.027344 L 100.085938 1094.398438 "/>
+</g>
+<g clip-path="url(#clip325)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 1259.027344 L 138.476562 1094.398438 "/>
+</g>
+<g clip-path="url(#clip326)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 1259.027344 L 176.867188 1094.398438 "/>
+</g>
+<g clip-path="url(#clip327)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 1259.027344 L 215.253906 1094.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 1101.882812 L 92.160156 1101.882812 L 92.46875 1102.15625 L 92.777344 1103.519531 L 93.085938 1104.863281 L 93.394531 1106.191406 L 93.699219 1107.5 L 94.007812 1108.792969 L 94.316406 1110.066406 L 94.625 1111.328125 L 94.929688 1112.570312 L 95.238281 1113.796875 L 95.546875 1115.011719 L 95.855469 1116.207031 L 96.164062 1117.390625 L 96.46875 1118.558594 L 96.777344 1119.710938 L 97.085938 1120.851562 L 97.394531 1121.976562 L 97.699219 1123.089844 L 98.007812 1124.191406 L 98.316406 1125.277344 L 98.625 1126.351562 L 98.933594 1127.410156 L 99.238281 1128.460938 L 99.546875 1129.496094 L 99.855469 1130.519531 L 100.164062 1131.535156 L 100.46875 1132.535156 L 100.777344 1133.523438 L 101.085938 1134.503906 L 101.394531 1135.472656 L 101.703125 1136.429688 L 102.007812 1137.375 L 102.316406 1138.3125 L 102.625 1139.238281 L 102.933594 1140.152344 L 103.242188 1141.058594 L 103.546875 1141.957031 L 103.855469 1142.84375 L 104.164062 1143.71875 L 104.472656 1144.585938 L 104.777344 1145.445312 L 105.085938 1146.296875 L 105.394531 1147.136719 L 105.703125 1147.96875 L 106.011719 1148.792969 L 106.316406 1149.609375 L 106.625 1150.414062 L 106.933594 1151.214844 L 107.242188 1152.003906 L 107.546875 1152.785156 L 107.855469 1153.5625 L 108.164062 1154.328125 L 108.472656 1155.089844 L 108.78125 1155.839844 L 109.085938 1156.585938 L 109.394531 1157.320312 L 109.703125 1158.050781 L 110.011719 1158.773438 L 110.316406 1159.492188 L 110.625 1160.199219 L 110.933594 1160.902344 L 111.242188 1161.597656 L 111.550781 1162.289062 L 111.855469 1162.972656 L 112.164062 1163.648438 L 112.472656 1164.316406 L 112.78125 1164.980469 L 113.085938 1165.640625 L 113.394531 1166.292969 L 113.703125 1166.9375 L 114.011719 1167.578125 L 114.320312 1168.210938 L 114.625 1168.839844 L 114.933594 1169.464844 L 115.242188 1170.082031 L 115.550781 1170.691406 L 115.855469 1171.296875 L 116.164062 1171.898438 L 116.472656 1172.496094 L 116.78125 1173.085938 L 117.089844 1173.671875 L 117.394531 1174.25 L 117.703125 1174.828125 L 118.011719 1175.398438 L 118.320312 1175.960938 L 118.625 1176.523438 L 118.933594 1177.078125 L 119.242188 1177.628906 L 119.550781 1178.175781 L 119.859375 1178.71875 L 120.164062 1179.257812 L 120.78125 1180.320312 L 121.089844 1180.84375 L 121.398438 1181.363281 L 121.703125 1181.878906 L 122.011719 1182.390625 L 122.320312 1182.898438 L 122.628906 1183.402344 L 122.933594 1183.898438 L 123.242188 1184.394531 L 123.550781 1184.886719 L 123.859375 1185.375 L 124.167969 1185.859375 L 124.472656 1186.335938 L 124.78125 1186.8125 L 125.089844 1187.285156 L 125.398438 1187.753906 L 125.703125 1188.21875 L 126.011719 1188.679688 L 126.628906 1189.59375 L 126.9375 1190.042969 L 127.242188 1190.492188 L 127.859375 1191.375 L 128.167969 1191.8125 L 128.472656 1192.246094 L 128.78125 1192.679688 L 129.398438 1193.53125 L 129.707031 1193.953125 L 130.011719 1194.371094 L 130.320312 1194.785156 L 130.9375 1195.605469 L 131.242188 1196.011719 L 131.859375 1196.816406 L 132.167969 1197.214844 L 132.476562 1197.609375 L 132.78125 1198 L 133.089844 1198.390625 L 133.398438 1198.773438 L 133.707031 1199.160156 L 134.011719 1199.539062 L 134.320312 1199.917969 L 134.9375 1200.667969 L 135.246094 1201.035156 L 135.550781 1201.40625 L 136.167969 1202.132812 L 136.785156 1202.851562 L 137.089844 1203.207031 L 137.707031 1203.910156 L 138.015625 1204.257812 L 138.320312 1204.605469 L 138.628906 1204.949219 L 139.246094 1205.628906 L 139.554688 1205.964844 L 139.859375 1206.300781 L 140.167969 1206.632812 L 140.785156 1207.289062 L 141.089844 1207.617188 L 141.398438 1207.941406 L 142.015625 1208.582031 L 142.324219 1208.898438 L 142.628906 1209.214844 L 143.554688 1210.152344 L 144.167969 1210.765625 L 144.476562 1211.066406 L 144.785156 1211.371094 L 145.09375 1211.671875 L 145.398438 1211.96875 L 145.707031 1212.265625 L 146.324219 1212.851562 L 146.628906 1213.144531 L 146.9375 1213.433594 L 147.863281 1214.289062 L 148.167969 1214.570312 L 148.476562 1214.851562 L 149.09375 1215.40625 L 149.398438 1215.683594 L 150.015625 1216.230469 L 150.632812 1216.769531 L 150.9375 1217.035156 L 151.554688 1217.566406 L 152.171875 1218.089844 L 152.476562 1218.351562 L 152.785156 1218.609375 L 153.09375 1218.863281 L 153.402344 1219.121094 L 153.707031 1219.375 L 154.015625 1219.625 L 154.324219 1219.878906 L 154.632812 1220.125 L 154.941406 1220.375 L 155.246094 1220.621094 L 155.554688 1220.867188 L 156.171875 1221.351562 L 156.476562 1221.59375 L 156.785156 1221.835938 L 157.09375 1222.074219 L 157.402344 1222.308594 L 157.710938 1222.546875 L 158.015625 1222.78125 L 158.324219 1223.015625 L 158.941406 1223.476562 L 159.246094 1223.707031 L 160.480469 1224.613281 L 160.785156 1224.835938 L 161.09375 1225.058594 L 161.710938 1225.496094 L 162.015625 1225.714844 L 162.324219 1225.933594 L 163.25 1226.578125 L 163.554688 1226.792969 L 164.480469 1227.425781 L 164.785156 1227.632812 L 165.402344 1228.046875 L 165.710938 1228.25 L 166.019531 1228.457031 L 166.324219 1228.660156 L 166.632812 1228.859375 L 166.941406 1229.0625 L 167.25 1229.261719 L 167.554688 1229.460938 L 167.863281 1229.660156 L 168.789062 1230.246094 L 169.09375 1230.441406 L 169.402344 1230.632812 L 169.710938 1230.828125 L 170.019531 1231.019531 L 170.328125 1231.207031 L 170.632812 1231.398438 L 171.558594 1231.960938 L 171.863281 1232.144531 L 172.171875 1232.332031 L 172.480469 1232.515625 L 172.789062 1232.695312 L 173.097656 1232.878906 L 173.402344 1233.058594 L 173.710938 1233.242188 L 174.019531 1233.417969 L 174.328125 1233.597656 L 174.632812 1233.777344 L 175.558594 1234.304688 L 175.867188 1234.476562 L 176.171875 1234.652344 L 177.097656 1235.167969 L 177.402344 1235.335938 L 177.710938 1235.507812 L 178.636719 1236.011719 L 178.941406 1236.175781 L 179.25 1236.34375 L 179.867188 1236.671875 L 180.171875 1236.835938 L 180.480469 1236.996094 L 180.789062 1237.160156 L 181.40625 1237.480469 L 181.710938 1237.640625 L 182.019531 1237.796875 L 182.328125 1237.957031 L 182.636719 1238.113281 L 182.941406 1238.269531 L 183.558594 1238.582031 L 183.867188 1238.734375 L 184.175781 1238.890625 L 184.480469 1239.042969 L 185.40625 1239.5 L 185.714844 1239.648438 L 186.019531 1239.800781 L 186.945312 1240.246094 L 187.25 1240.390625 L 187.558594 1240.539062 L 187.867188 1240.683594 L 188.175781 1240.832031 L 188.484375 1240.976562 L 188.789062 1241.117188 L 189.40625 1241.40625 L 189.714844 1241.546875 L 190.019531 1241.6875 L 190.328125 1241.832031 L 190.636719 1241.96875 L 191.253906 1242.25 L 191.558594 1242.386719 L 191.867188 1242.527344 L 192.484375 1242.800781 L 192.789062 1242.9375 L 193.097656 1243.074219 L 193.40625 1243.207031 L 193.714844 1243.34375 L 194.023438 1243.476562 L 194.328125 1243.609375 L 195.253906 1244.007812 L 195.558594 1244.136719 L 195.867188 1244.269531 L 196.792969 1244.65625 L 197.097656 1244.785156 L 197.714844 1245.042969 L 198.023438 1245.167969 L 198.328125 1245.296875 L 199.5625 1245.796875 L 199.867188 1245.921875 L 200.175781 1246.042969 L 200.484375 1246.167969 L 200.792969 1246.289062 L 201.101562 1246.414062 L 201.40625 1246.535156 L 202.023438 1246.777344 L 202.332031 1246.894531 L 202.636719 1247.015625 L 202.945312 1247.132812 L 203.253906 1247.253906 L 203.871094 1247.488281 L 204.175781 1247.605469 L 205.101562 1247.957031 L 205.40625 1248.070312 L 205.714844 1248.1875 L 206.640625 1248.527344 L 206.945312 1248.640625 L 207.871094 1248.980469 L 208.175781 1249.089844 L 208.484375 1249.203125 L 209.101562 1249.421875 L 209.410156 1249.535156 L 209.714844 1249.644531 L 210.023438 1249.753906 L 210.332031 1249.859375 L 210.640625 1249.96875 L 210.945312 1250.078125 L 211.253906 1250.183594 L 211.5625 1250.292969 L 212.179688 1250.503906 L 212.484375 1250.609375 L 213.410156 1250.925781 L 213.714844 1251.03125 L 214.023438 1251.132812 L 214.332031 1251.238281 L 214.640625 1251.339844 L 214.949219 1251.445312 L 215.253906 1251.546875 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 61.695312 1251.546875 L 62.003906 1251.445312 L 62.3125 1251.339844 L 62.621094 1251.238281 L 62.925781 1251.132812 L 63.234375 1251.03125 L 63.851562 1250.820312 L 64.15625 1250.714844 L 65.390625 1250.292969 L 65.695312 1250.183594 L 66.003906 1250.078125 L 66.621094 1249.859375 L 66.925781 1249.753906 L 67.542969 1249.535156 L 67.851562 1249.421875 L 68.160156 1249.3125 L 68.464844 1249.203125 L 68.773438 1249.089844 L 69.082031 1248.980469 L 69.390625 1248.867188 L 69.695312 1248.753906 L 70.929688 1248.300781 L 71.234375 1248.1875 L 71.542969 1248.070312 L 71.851562 1247.957031 L 72.46875 1247.722656 L 72.773438 1247.605469 L 73.699219 1247.253906 L 74.003906 1247.132812 L 74.3125 1247.015625 L 74.621094 1246.894531 L 74.929688 1246.777344 L 75.238281 1246.65625 L 75.542969 1246.535156 L 75.851562 1246.414062 L 76.160156 1246.289062 L 76.46875 1246.167969 L 76.773438 1246.042969 L 77.082031 1245.921875 L 78.007812 1245.546875 L 78.3125 1245.421875 L 78.621094 1245.296875 L 78.929688 1245.167969 L 79.238281 1245.042969 L 79.542969 1244.914062 L 80.777344 1244.398438 L 81.082031 1244.269531 L 81.390625 1244.136719 L 81.699219 1244.007812 L 82.007812 1243.875 L 82.3125 1243.742188 L 83.238281 1243.34375 L 83.546875 1243.207031 L 83.851562 1243.074219 L 84.777344 1242.664062 L 85.082031 1242.527344 L 85.390625 1242.386719 L 85.699219 1242.25 L 86.316406 1241.96875 L 86.621094 1241.832031 L 86.929688 1241.6875 L 87.546875 1241.40625 L 87.855469 1241.261719 L 88.160156 1241.117188 L 88.46875 1240.976562 L 88.777344 1240.832031 L 89.085938 1240.683594 L 89.390625 1240.539062 L 89.699219 1240.390625 L 90.007812 1240.246094 L 90.625 1239.949219 L 90.929688 1239.800781 L 91.238281 1239.648438 L 91.546875 1239.5 L 91.855469 1239.347656 L 92.160156 1239.195312 L 92.777344 1238.890625 L 93.085938 1238.734375 L 93.394531 1238.582031 L 93.699219 1238.425781 L 94.625 1237.957031 L 94.929688 1237.796875 L 95.238281 1237.640625 L 96.164062 1237.160156 L 96.46875 1236.996094 L 96.777344 1236.835938 L 97.394531 1236.507812 L 97.699219 1236.34375 L 98.007812 1236.175781 L 98.316406 1236.011719 L 98.933594 1235.675781 L 99.238281 1235.507812 L 99.546875 1235.335938 L 99.855469 1235.167969 L 100.164062 1234.996094 L 100.46875 1234.824219 L 100.777344 1234.652344 L 101.085938 1234.476562 L 101.394531 1234.304688 L 101.703125 1234.128906 L 102.007812 1233.953125 L 102.316406 1233.777344 L 102.933594 1233.417969 L 103.242188 1233.242188 L 103.546875 1233.058594 L 103.855469 1232.878906 L 104.164062 1232.695312 L 104.472656 1232.515625 L 104.777344 1232.332031 L 105.085938 1232.144531 L 105.394531 1231.960938 L 106.011719 1231.585938 L 106.316406 1231.398438 L 106.625 1231.207031 L 106.933594 1231.019531 L 107.242188 1230.828125 L 107.546875 1230.632812 L 107.855469 1230.441406 L 108.78125 1229.855469 L 109.085938 1229.660156 L 110.011719 1229.0625 L 110.316406 1228.859375 L 110.625 1228.660156 L 110.933594 1228.457031 L 111.242188 1228.25 L 111.550781 1228.046875 L 111.855469 1227.839844 L 112.472656 1227.425781 L 112.78125 1227.214844 L 113.085938 1227.003906 L 113.394531 1226.792969 L 114.320312 1226.148438 L 114.625 1225.933594 L 115.550781 1225.277344 L 115.855469 1225.058594 L 116.472656 1224.613281 L 117.089844 1224.160156 L 117.394531 1223.933594 L 117.703125 1223.707031 L 118.320312 1223.246094 L 118.625 1223.015625 L 119.242188 1222.546875 L 119.550781 1222.308594 L 119.859375 1222.074219 L 120.164062 1221.835938 L 121.398438 1220.867188 L 121.703125 1220.621094 L 122.011719 1220.375 L 122.320312 1220.125 L 122.628906 1219.878906 L 122.933594 1219.625 L 123.242188 1219.375 L 123.550781 1219.121094 L 123.859375 1218.863281 L 124.167969 1218.609375 L 124.472656 1218.351562 L 125.398438 1217.566406 L 125.703125 1217.300781 L 126.320312 1216.769531 L 126.9375 1216.230469 L 127.242188 1215.957031 L 127.550781 1215.683594 L 128.167969 1215.128906 L 128.472656 1214.851562 L 129.089844 1214.289062 L 129.707031 1213.71875 L 130.011719 1213.433594 L 130.320312 1213.144531 L 130.9375 1212.558594 L 131.242188 1212.265625 L 131.859375 1211.671875 L 132.167969 1211.371094 L 132.476562 1211.066406 L 132.78125 1210.765625 L 133.089844 1210.457031 L 133.398438 1210.152344 L 133.707031 1209.839844 L 134.011719 1209.527344 L 134.320312 1209.214844 L 134.9375 1208.582031 L 135.246094 1208.261719 L 135.550781 1207.941406 L 135.859375 1207.617188 L 136.785156 1206.632812 L 137.089844 1206.300781 L 137.707031 1205.628906 L 138.015625 1205.289062 L 138.320312 1204.949219 L 138.628906 1204.605469 L 139.246094 1203.910156 L 139.554688 1203.558594 L 139.859375 1203.207031 L 140.167969 1202.851562 L 140.785156 1202.132812 L 141.089844 1201.769531 L 141.398438 1201.40625 L 141.707031 1201.035156 L 142.015625 1200.667969 L 142.324219 1200.292969 L 142.628906 1199.917969 L 143.246094 1199.160156 L 143.554688 1198.773438 L 143.859375 1198.390625 L 144.476562 1197.609375 L 144.785156 1197.214844 L 145.09375 1196.816406 L 145.398438 1196.414062 L 145.707031 1196.011719 L 146.015625 1195.605469 L 146.324219 1195.195312 L 146.628906 1194.785156 L 146.9375 1194.371094 L 147.246094 1193.953125 L 147.554688 1193.53125 L 147.863281 1193.105469 L 148.167969 1192.679688 L 148.785156 1191.8125 L 149.09375 1191.375 L 149.398438 1190.933594 L 149.707031 1190.492188 L 150.324219 1189.59375 L 150.632812 1189.136719 L 150.9375 1188.679688 L 151.246094 1188.21875 L 151.554688 1187.753906 L 151.863281 1187.285156 L 152.171875 1186.8125 L 152.476562 1186.335938 L 152.785156 1185.859375 L 153.09375 1185.375 L 153.402344 1184.886719 L 153.707031 1184.394531 L 154.324219 1183.402344 L 154.632812 1182.898438 L 154.941406 1182.390625 L 155.246094 1181.878906 L 155.554688 1181.363281 L 155.863281 1180.84375 L 156.171875 1180.320312 L 156.476562 1179.789062 L 156.785156 1179.257812 L 157.09375 1178.71875 L 157.402344 1178.175781 L 157.710938 1177.628906 L 158.015625 1177.078125 L 158.324219 1176.523438 L 158.941406 1175.398438 L 159.246094 1174.828125 L 159.863281 1173.671875 L 160.171875 1173.085938 L 160.480469 1172.496094 L 160.785156 1171.898438 L 161.09375 1171.296875 L 161.402344 1170.691406 L 161.710938 1170.082031 L 162.015625 1169.464844 L 162.324219 1168.839844 L 162.632812 1168.210938 L 162.941406 1167.578125 L 163.25 1166.9375 L 163.554688 1166.292969 L 163.863281 1165.640625 L 164.171875 1164.980469 L 164.480469 1164.316406 L 164.785156 1163.648438 L 165.09375 1162.972656 L 165.402344 1162.289062 L 165.710938 1161.597656 L 166.019531 1160.902344 L 166.324219 1160.199219 L 166.632812 1159.492188 L 166.941406 1158.773438 L 167.25 1158.050781 L 167.554688 1157.320312 L 167.863281 1156.585938 L 168.171875 1155.839844 L 168.480469 1155.089844 L 168.789062 1154.328125 L 169.09375 1153.5625 L 169.402344 1152.785156 L 169.710938 1152.003906 L 170.019531 1151.214844 L 170.328125 1150.414062 L 170.632812 1149.609375 L 170.941406 1148.792969 L 171.25 1147.96875 L 171.558594 1147.136719 L 171.863281 1146.296875 L 172.171875 1145.445312 L 172.480469 1144.585938 L 172.789062 1143.71875 L 173.097656 1142.84375 L 173.402344 1141.957031 L 173.710938 1141.058594 L 174.019531 1140.152344 L 174.328125 1139.238281 L 174.632812 1138.3125 L 174.941406 1137.375 L 175.25 1136.429688 L 175.558594 1135.472656 L 175.867188 1134.503906 L 176.171875 1133.523438 L 176.480469 1132.535156 L 176.789062 1131.535156 L 177.097656 1130.519531 L 177.402344 1129.496094 L 177.710938 1128.460938 L 178.019531 1127.410156 L 178.328125 1126.351562 L 178.636719 1125.277344 L 178.941406 1124.191406 L 179.25 1123.089844 L 179.558594 1121.976562 L 179.867188 1120.851562 L 180.171875 1119.710938 L 180.480469 1118.558594 L 180.789062 1117.390625 L 181.097656 1116.207031 L 181.40625 1115.011719 L 181.710938 1113.796875 L 182.019531 1112.570312 L 182.328125 1111.328125 L 182.636719 1110.066406 L 182.941406 1108.792969 L 183.25 1107.5 L 183.558594 1106.191406 L 183.867188 1104.863281 L 184.175781 1103.519531 L 184.480469 1102.15625 L 184.789062 1101.882812 L 215.253906 1101.882812 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="33.59375" y="1228.792969"/>
+ <use xlink:href="#glyph0-2" x="38.929337" y="1228.792969"/>
+ <use xlink:href="#glyph0-7" x="41.594788" y="1228.792969"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="33.59375" y="1187.636719"/>
+ <use xlink:href="#glyph0-2" x="38.929337" y="1187.636719"/>
+ <use xlink:href="#glyph0-8" x="41.594788" y="1187.636719"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="33.59375" y="1146.476562"/>
+ <use xlink:href="#glyph0-2" x="38.929337" y="1146.476562"/>
+ <use xlink:href="#glyph0-9" x="41.594788" y="1146.476562"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="33.59375" y="1105.320312"/>
+ <use xlink:href="#glyph0-2" x="38.929337" y="1105.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594788" y="1105.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1225.355469 L 54.019531 1225.355469 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1184.199219 L 54.019531 1184.199219 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1143.039062 L 54.019531 1143.039062 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1101.882812 L 54.019531 1101.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 1263.28125 L 61.695312 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 1263.28125 L 100.085938 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 1263.28125 L 138.476562 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 1263.28125 L 176.867188 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 1263.28125 L 215.253906 1259.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="1272.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="1272.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="1272.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="1285.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="1188.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="1181.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="1176.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="1170.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-17" x="25.011719" y="1090.800781"/>
+ <use xlink:href="#glyph5-15" x="33.677734" y="1090.800781"/>
+ <use xlink:href="#glyph5-5" x="41.007812" y="1090.800781"/>
+ <use xlink:href="#glyph5-22" x="48.337891" y="1090.800781"/>
+ <use xlink:href="#glyph5-4" x="55.011719" y="1090.800781"/>
+ <use xlink:href="#glyph5-29" x="61.685547" y="1090.800781"/>
+ <use xlink:href="#glyph5-8" x="68.359375" y="1090.800781"/>
+</g>
+<g clip-path="url(#clip328)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 1296 L 474.664062 1296 L 474.664062 1080 L 237.332031 1080 Z "/>
+</g>
+<g clip-path="url(#clip329)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 1296 L 474.664062 1296 L 474.664062 1080 L 237.332031 1080 Z "/>
+</g>
+<g clip-path="url(#clip330)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 1259.027344 L 460.265625 1259.027344 L 460.265625 1094.398438 L 291.351562 1094.398438 Z "/>
+</g>
+<g clip-path="url(#clip331)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1232.84375 L 460.265625 1232.84375 "/>
+</g>
+<g clip-path="url(#clip332)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1195.425781 L 460.265625 1195.425781 "/>
+</g>
+<g clip-path="url(#clip333)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1158.003906 L 460.265625 1158.003906 "/>
+</g>
+<g clip-path="url(#clip334)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1120.585938 L 460.265625 1120.585938 "/>
+</g>
+<g clip-path="url(#clip335)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 1259.027344 L 318.222656 1094.398438 "/>
+</g>
+<g clip-path="url(#clip336)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 1259.027344 L 356.613281 1094.398438 "/>
+</g>
+<g clip-path="url(#clip337)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 1259.027344 L 395.003906 1094.398438 "/>
+</g>
+<g clip-path="url(#clip338)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 1259.027344 L 433.394531 1094.398438 "/>
+</g>
+<g clip-path="url(#clip339)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1251.550781 L 460.265625 1251.550781 "/>
+</g>
+<g clip-path="url(#clip340)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1214.132812 L 460.265625 1214.132812 "/>
+</g>
+<g clip-path="url(#clip341)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1176.714844 L 460.265625 1176.714844 "/>
+</g>
+<g clip-path="url(#clip342)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1139.296875 L 460.265625 1139.296875 "/>
+</g>
+<g clip-path="url(#clip343)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1101.875 L 460.265625 1101.875 "/>
+</g>
+<g clip-path="url(#clip344)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 1259.027344 L 299.03125 1094.398438 "/>
+</g>
+<g clip-path="url(#clip345)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 1259.027344 L 337.417969 1094.398438 "/>
+</g>
+<g clip-path="url(#clip346)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 1259.027344 L 375.808594 1094.398438 "/>
+</g>
+<g clip-path="url(#clip347)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 1259.027344 L 414.199219 1094.398438 "/>
+</g>
+<g clip-path="url(#clip348)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 1259.027344 L 452.589844 1094.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 1101.882812 L 300.566406 1101.882812 L 300.875 1101.886719 L 303.335938 1101.886719 L 303.644531 1101.890625 L 305.492188 1101.890625 L 305.800781 1101.894531 L 307.339844 1101.894531 L 307.644531 1101.898438 L 308.570312 1101.898438 L 308.878906 1101.902344 L 309.800781 1101.902344 L 310.109375 1101.90625 L 310.722656 1101.90625 L 311.03125 1101.910156 L 311.648438 1101.910156 L 311.953125 1101.914062 L 312.570312 1101.914062 L 312.878906 1101.917969 L 313.183594 1101.917969 L 313.492188 1101.921875 L 313.800781 1101.921875 L 314.109375 1101.925781 L 314.417969 1101.925781 L 314.722656 1101.929688 L 315.03125 1101.929688 L 315.339844 1101.933594 L 315.648438 1101.933594 L 315.953125 1101.9375 L 316.261719 1101.941406 L 316.570312 1101.941406 L 317.1875 1101.949219 L 317.492188 1101.953125 L 317.800781 1101.953125 L 318.417969 1101.960938 L 318.722656 1101.964844 L 319.957031 1101.980469 L 320.261719 1101.984375 L 321.1875 1101.996094 L 321.492188 1102.003906 L 322.109375 1102.011719 L 322.417969 1102.019531 L 322.726562 1102.023438 L 323.03125 1102.03125 L 323.339844 1102.039062 L 323.648438 1102.042969 L 324.265625 1102.058594 L 324.570312 1102.066406 L 325.496094 1102.089844 L 325.800781 1102.097656 L 326.109375 1102.105469 L 326.417969 1102.117188 L 326.726562 1102.125 L 327.035156 1102.136719 L 327.339844 1102.148438 L 327.648438 1102.160156 L 327.957031 1102.167969 L 328.265625 1102.183594 L 328.570312 1102.195312 L 328.878906 1102.207031 L 329.1875 1102.222656 L 329.496094 1102.234375 L 329.804688 1102.25 L 330.109375 1102.265625 L 331.035156 1102.3125 L 331.339844 1102.332031 L 332.574219 1102.410156 L 332.878906 1102.433594 L 333.804688 1102.503906 L 334.109375 1102.527344 L 334.726562 1102.582031 L 335.035156 1102.613281 L 335.34375 1102.640625 L 335.648438 1102.671875 L 335.957031 1102.707031 L 336.265625 1102.738281 L 336.574219 1102.773438 L 336.878906 1102.8125 L 337.1875 1102.847656 L 337.496094 1102.886719 L 338.113281 1102.972656 L 338.417969 1103.015625 L 339.035156 1103.109375 L 339.34375 1103.160156 L 339.648438 1103.210938 L 339.957031 1103.265625 L 340.882812 1103.441406 L 341.1875 1103.507812 L 341.496094 1103.570312 L 342.113281 1103.710938 L 342.421875 1103.785156 L 342.726562 1103.863281 L 343.035156 1103.941406 L 343.652344 1104.113281 L 343.957031 1104.203125 L 344.265625 1104.296875 L 344.574219 1104.394531 L 344.882812 1104.496094 L 345.191406 1104.601562 L 345.496094 1104.710938 L 345.804688 1104.824219 L 346.113281 1104.941406 L 346.421875 1105.0625 L 346.726562 1105.191406 L 347.035156 1105.324219 L 347.34375 1105.460938 L 347.652344 1105.605469 L 347.960938 1105.753906 L 348.265625 1105.90625 L 348.574219 1106.066406 L 348.882812 1106.234375 L 349.191406 1106.40625 L 349.496094 1106.585938 L 349.804688 1106.773438 L 350.113281 1106.964844 L 350.421875 1107.167969 L 350.730469 1107.375 L 351.035156 1107.589844 L 351.34375 1107.816406 L 351.652344 1108.046875 L 351.960938 1108.289062 L 352.265625 1108.539062 L 352.574219 1108.800781 L 352.882812 1109.070312 L 353.191406 1109.351562 L 353.5 1109.640625 L 353.804688 1109.941406 L 354.113281 1110.25 L 354.421875 1110.574219 L 354.730469 1110.90625 L 355.035156 1111.253906 L 355.34375 1111.613281 L 355.652344 1111.984375 L 355.960938 1112.367188 L 356.269531 1112.765625 L 356.574219 1113.179688 L 356.882812 1113.605469 L 357.191406 1114.042969 L 357.5 1114.5 L 357.808594 1114.972656 L 358.113281 1115.457031 L 358.421875 1115.960938 L 358.730469 1116.480469 L 359.039062 1117.019531 L 359.34375 1117.574219 L 359.652344 1118.144531 L 359.960938 1118.734375 L 360.269531 1119.34375 L 360.578125 1119.972656 L 360.882812 1120.617188 L 361.191406 1121.285156 L 361.5 1121.972656 L 361.808594 1122.679688 L 362.113281 1123.410156 L 362.421875 1124.160156 L 362.730469 1124.929688 L 363.039062 1125.722656 L 363.347656 1126.535156 L 363.652344 1127.375 L 363.960938 1128.230469 L 364.269531 1129.113281 L 364.578125 1130.019531 L 364.882812 1130.945312 L 365.191406 1131.894531 L 365.5 1132.871094 L 365.808594 1133.867188 L 366.117188 1134.886719 L 366.421875 1135.929688 L 366.730469 1136.996094 L 367.039062 1138.082031 L 367.347656 1139.195312 L 367.652344 1140.328125 L 367.960938 1141.484375 L 368.269531 1142.664062 L 368.578125 1143.863281 L 368.886719 1145.085938 L 369.191406 1146.328125 L 369.5 1147.589844 L 369.808594 1148.871094 L 370.117188 1150.175781 L 370.421875 1151.496094 L 370.730469 1152.832031 L 371.039062 1154.1875 L 371.347656 1155.558594 L 371.65625 1156.949219 L 371.960938 1158.351562 L 372.269531 1159.765625 L 372.578125 1161.195312 L 372.886719 1162.636719 L 373.195312 1164.089844 L 373.5 1165.550781 L 373.808594 1167.019531 L 374.117188 1168.5 L 374.425781 1169.984375 L 374.730469 1171.472656 L 375.347656 1174.464844 L 375.964844 1177.464844 L 376.269531 1178.964844 L 376.886719 1181.957031 L 377.195312 1183.445312 L 377.5 1184.929688 L 377.808594 1186.40625 L 378.117188 1187.878906 L 378.425781 1189.339844 L 378.734375 1190.792969 L 379.039062 1192.234375 L 379.347656 1193.664062 L 379.65625 1195.078125 L 379.964844 1196.480469 L 380.269531 1197.867188 L 380.578125 1199.242188 L 380.886719 1200.597656 L 381.195312 1201.933594 L 381.503906 1203.253906 L 381.808594 1204.558594 L 382.117188 1205.839844 L 382.425781 1207.101562 L 382.734375 1208.34375 L 383.039062 1209.566406 L 383.347656 1210.765625 L 383.65625 1211.945312 L 383.964844 1213.101562 L 384.273438 1214.234375 L 384.578125 1215.347656 L 384.886719 1216.433594 L 385.195312 1217.5 L 385.503906 1218.542969 L 385.808594 1219.5625 L 386.117188 1220.558594 L 386.425781 1221.53125 L 386.734375 1222.484375 L 387.042969 1223.410156 L 387.347656 1224.316406 L 387.65625 1225.195312 L 387.964844 1226.054688 L 388.273438 1226.890625 L 388.578125 1227.707031 L 388.886719 1228.5 L 389.195312 1229.269531 L 389.503906 1230.019531 L 389.8125 1230.75 L 390.117188 1231.457031 L 390.425781 1232.144531 L 390.734375 1232.808594 L 391.042969 1233.457031 L 391.351562 1234.085938 L 391.65625 1234.695312 L 391.964844 1235.285156 L 392.273438 1235.855469 L 392.582031 1236.410156 L 392.886719 1236.949219 L 393.195312 1237.46875 L 393.503906 1237.972656 L 393.8125 1238.457031 L 394.121094 1238.929688 L 394.425781 1239.382812 L 394.734375 1239.824219 L 395.042969 1240.25 L 395.351562 1240.664062 L 395.65625 1241.058594 L 395.964844 1241.445312 L 396.273438 1241.816406 L 396.582031 1242.175781 L 396.890625 1242.519531 L 397.195312 1242.855469 L 397.503906 1243.175781 L 397.8125 1243.488281 L 398.121094 1243.789062 L 398.425781 1244.078125 L 398.734375 1244.359375 L 399.042969 1244.628906 L 399.351562 1244.886719 L 399.660156 1245.140625 L 399.964844 1245.378906 L 400.273438 1245.613281 L 400.582031 1245.835938 L 400.890625 1246.054688 L 401.195312 1246.261719 L 401.503906 1246.464844 L 401.8125 1246.65625 L 402.121094 1246.84375 L 402.429688 1247.023438 L 402.734375 1247.195312 L 403.042969 1247.363281 L 403.351562 1247.523438 L 403.660156 1247.675781 L 403.964844 1247.824219 L 404.273438 1247.96875 L 404.582031 1248.105469 L 404.890625 1248.238281 L 405.199219 1248.363281 L 405.503906 1248.488281 L 405.8125 1248.605469 L 406.121094 1248.71875 L 406.429688 1248.828125 L 406.738281 1248.933594 L 407.042969 1249.035156 L 407.351562 1249.132812 L 407.660156 1249.226562 L 407.96875 1249.316406 L 408.273438 1249.402344 L 408.890625 1249.566406 L 409.199219 1249.644531 L 409.507812 1249.71875 L 409.8125 1249.789062 L 410.429688 1249.921875 L 410.738281 1249.984375 L 411.042969 1250.046875 L 411.351562 1250.105469 L 412.277344 1250.269531 L 412.582031 1250.316406 L 412.890625 1250.367188 L 413.199219 1250.414062 L 413.507812 1250.457031 L 413.8125 1250.5 L 414.121094 1250.539062 L 414.429688 1250.582031 L 414.738281 1250.617188 L 415.046875 1250.65625 L 415.351562 1250.691406 L 415.660156 1250.722656 L 415.96875 1250.757812 L 416.277344 1250.789062 L 416.582031 1250.816406 L 416.890625 1250.847656 L 417.199219 1250.875 L 417.507812 1250.898438 L 417.816406 1250.925781 L 418.121094 1250.949219 L 419.046875 1251.019531 L 419.351562 1251.039062 L 420.277344 1251.097656 L 420.585938 1251.113281 L 420.890625 1251.132812 L 422.125 1251.195312 L 422.429688 1251.207031 L 422.738281 1251.222656 L 423.355469 1251.246094 L 423.660156 1251.257812 L 424.585938 1251.292969 L 424.894531 1251.300781 L 425.199219 1251.3125 L 425.507812 1251.320312 L 425.816406 1251.332031 L 426.125 1251.339844 L 426.429688 1251.347656 L 427.664062 1251.378906 L 427.96875 1251.386719 L 428.277344 1251.390625 L 428.585938 1251.398438 L 428.894531 1251.402344 L 429.199219 1251.410156 L 429.507812 1251.414062 L 429.816406 1251.421875 L 430.433594 1251.429688 L 430.738281 1251.4375 L 431.664062 1251.449219 L 431.96875 1251.453125 L 433.203125 1251.46875 L 433.507812 1251.472656 L 433.816406 1251.472656 L 434.433594 1251.480469 L 434.738281 1251.484375 L 435.046875 1251.484375 L 435.664062 1251.492188 L 435.972656 1251.492188 L 436.277344 1251.496094 L 436.585938 1251.5 L 436.894531 1251.5 L 437.203125 1251.503906 L 437.507812 1251.503906 L 437.816406 1251.507812 L 438.433594 1251.507812 L 438.742188 1251.511719 L 439.046875 1251.511719 L 439.355469 1251.515625 L 439.972656 1251.515625 L 440.28125 1251.519531 L 440.585938 1251.519531 L 440.894531 1251.523438 L 441.816406 1251.523438 L 442.125 1251.527344 L 443.050781 1251.527344 L 443.355469 1251.53125 L 444.28125 1251.53125 L 444.585938 1251.535156 L 446.125 1251.535156 L 446.433594 1251.539062 L 448.28125 1251.539062 L 448.589844 1251.542969 L 451.359375 1251.542969 L 451.664062 1251.546875 L 452.589844 1251.546875 "/>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 299.03125 1251.546875 L 299.953125 1251.546875 L 300.261719 1251.542969 L 303.03125 1251.542969 L 303.335938 1251.539062 L 305.183594 1251.539062 L 305.492188 1251.535156 L 307.03125 1251.535156 L 307.339844 1251.53125 L 308.261719 1251.53125 L 308.570312 1251.527344 L 309.492188 1251.527344 L 309.800781 1251.523438 L 310.722656 1251.523438 L 311.03125 1251.519531 L 311.339844 1251.519531 L 311.648438 1251.515625 L 312.261719 1251.515625 L 312.570312 1251.511719 L 312.878906 1251.511719 L 313.183594 1251.507812 L 313.800781 1251.507812 L 314.109375 1251.503906 L 314.417969 1251.503906 L 314.722656 1251.5 L 315.03125 1251.5 L 315.648438 1251.492188 L 315.953125 1251.492188 L 316.570312 1251.484375 L 316.878906 1251.484375 L 317.1875 1251.480469 L 317.492188 1251.476562 L 317.800781 1251.472656 L 318.109375 1251.472656 L 318.417969 1251.46875 L 318.722656 1251.464844 L 319.957031 1251.449219 L 320.261719 1251.445312 L 320.878906 1251.4375 L 321.1875 1251.429688 L 321.492188 1251.425781 L 321.800781 1251.421875 L 322.109375 1251.414062 L 322.417969 1251.410156 L 322.726562 1251.402344 L 323.03125 1251.398438 L 323.339844 1251.390625 L 323.648438 1251.386719 L 324.265625 1251.371094 L 324.570312 1251.363281 L 325.496094 1251.339844 L 325.800781 1251.332031 L 326.109375 1251.320312 L 326.417969 1251.3125 L 326.726562 1251.300781 L 327.035156 1251.292969 L 327.339844 1251.28125 L 328.265625 1251.246094 L 328.570312 1251.234375 L 328.878906 1251.222656 L 329.1875 1251.207031 L 329.496094 1251.195312 L 329.804688 1251.179688 L 330.109375 1251.164062 L 330.726562 1251.132812 L 331.035156 1251.113281 L 331.339844 1251.097656 L 332.574219 1251.019531 L 332.878906 1250.996094 L 333.804688 1250.925781 L 334.109375 1250.898438 L 334.417969 1250.875 L 334.726562 1250.847656 L 335.035156 1250.816406 L 335.34375 1250.789062 L 335.648438 1250.757812 L 335.957031 1250.722656 L 336.265625 1250.691406 L 336.574219 1250.65625 L 336.878906 1250.617188 L 337.1875 1250.582031 L 337.496094 1250.539062 L 337.804688 1250.5 L 338.113281 1250.457031 L 338.417969 1250.414062 L 338.726562 1250.367188 L 339.035156 1250.316406 L 339.34375 1250.269531 L 339.648438 1250.214844 L 340.265625 1250.105469 L 340.574219 1250.046875 L 340.882812 1249.984375 L 341.1875 1249.921875 L 341.804688 1249.789062 L 342.113281 1249.71875 L 342.421875 1249.644531 L 342.726562 1249.566406 L 343.34375 1249.402344 L 343.652344 1249.316406 L 343.957031 1249.226562 L 344.265625 1249.132812 L 344.574219 1249.035156 L 344.882812 1248.933594 L 345.191406 1248.828125 L 345.496094 1248.71875 L 345.804688 1248.605469 L 346.113281 1248.488281 L 346.421875 1248.363281 L 346.726562 1248.238281 L 347.035156 1248.105469 L 347.34375 1247.96875 L 347.652344 1247.824219 L 347.960938 1247.675781 L 348.265625 1247.523438 L 348.574219 1247.363281 L 348.882812 1247.195312 L 349.191406 1247.023438 L 349.496094 1246.84375 L 349.804688 1246.65625 L 350.113281 1246.464844 L 350.421875 1246.261719 L 350.730469 1246.054688 L 351.035156 1245.835938 L 351.34375 1245.613281 L 351.652344 1245.378906 L 351.960938 1245.140625 L 352.265625 1244.886719 L 352.574219 1244.628906 L 352.882812 1244.359375 L 353.191406 1244.078125 L 353.5 1243.789062 L 353.804688 1243.488281 L 354.113281 1243.175781 L 354.421875 1242.855469 L 354.730469 1242.519531 L 355.035156 1242.175781 L 355.34375 1241.816406 L 355.652344 1241.445312 L 355.960938 1241.058594 L 356.269531 1240.664062 L 356.574219 1240.25 L 356.882812 1239.824219 L 357.191406 1239.382812 L 357.5 1238.929688 L 357.808594 1238.457031 L 358.113281 1237.972656 L 358.421875 1237.46875 L 358.730469 1236.949219 L 359.039062 1236.410156 L 359.34375 1235.855469 L 359.652344 1235.285156 L 359.960938 1234.695312 L 360.269531 1234.085938 L 360.578125 1233.457031 L 360.882812 1232.808594 L 361.191406 1232.144531 L 361.5 1231.457031 L 361.808594 1230.75 L 362.113281 1230.019531 L 362.421875 1229.269531 L 362.730469 1228.5 L 363.039062 1227.707031 L 363.347656 1226.890625 L 363.652344 1226.054688 L 363.960938 1225.195312 L 364.269531 1224.316406 L 364.578125 1223.410156 L 364.882812 1222.484375 L 365.191406 1221.53125 L 365.5 1220.558594 L 365.808594 1219.5625 L 366.117188 1218.542969 L 366.421875 1217.5 L 366.730469 1216.433594 L 367.039062 1215.347656 L 367.347656 1214.234375 L 367.652344 1213.101562 L 367.960938 1211.945312 L 368.269531 1210.765625 L 368.578125 1209.566406 L 368.886719 1208.34375 L 369.191406 1207.101562 L 369.5 1205.839844 L 369.808594 1204.558594 L 370.117188 1203.253906 L 370.421875 1201.933594 L 370.730469 1200.597656 L 371.039062 1199.242188 L 371.347656 1197.867188 L 371.65625 1196.480469 L 371.960938 1195.078125 L 372.269531 1193.664062 L 372.578125 1192.234375 L 372.886719 1190.792969 L 373.195312 1189.339844 L 373.5 1187.878906 L 373.808594 1186.40625 L 374.117188 1184.929688 L 374.425781 1183.445312 L 374.730469 1181.957031 L 375.347656 1178.964844 L 375.964844 1175.964844 L 376.269531 1174.464844 L 376.886719 1171.472656 L 377.195312 1169.984375 L 377.5 1168.5 L 377.808594 1167.019531 L 378.117188 1165.550781 L 378.425781 1164.089844 L 378.734375 1162.636719 L 379.039062 1161.195312 L 379.347656 1159.765625 L 379.65625 1158.351562 L 379.964844 1156.949219 L 380.269531 1155.558594 L 380.578125 1154.1875 L 380.886719 1152.832031 L 381.195312 1151.496094 L 381.503906 1150.175781 L 381.808594 1148.871094 L 382.117188 1147.589844 L 382.425781 1146.328125 L 382.734375 1145.085938 L 383.039062 1143.863281 L 383.347656 1142.664062 L 383.65625 1141.484375 L 383.964844 1140.328125 L 384.273438 1139.195312 L 384.578125 1138.082031 L 384.886719 1136.996094 L 385.195312 1135.929688 L 385.503906 1134.886719 L 385.808594 1133.867188 L 386.117188 1132.871094 L 386.425781 1131.894531 L 386.734375 1130.945312 L 387.042969 1130.019531 L 387.347656 1129.113281 L 387.65625 1128.230469 L 387.964844 1127.375 L 388.273438 1126.535156 L 388.578125 1125.722656 L 388.886719 1124.929688 L 389.195312 1124.160156 L 389.503906 1123.410156 L 389.8125 1122.679688 L 390.117188 1121.972656 L 390.425781 1121.285156 L 390.734375 1120.617188 L 391.042969 1119.972656 L 391.351562 1119.34375 L 391.65625 1118.734375 L 391.964844 1118.144531 L 392.273438 1117.574219 L 392.582031 1117.019531 L 392.886719 1116.480469 L 393.195312 1115.960938 L 393.503906 1115.457031 L 393.8125 1114.972656 L 394.121094 1114.5 L 394.425781 1114.042969 L 394.734375 1113.605469 L 395.042969 1113.179688 L 395.351562 1112.765625 L 395.65625 1112.367188 L 395.964844 1111.984375 L 396.273438 1111.613281 L 396.582031 1111.253906 L 396.890625 1110.90625 L 397.195312 1110.574219 L 397.503906 1110.25 L 397.8125 1109.941406 L 398.121094 1109.640625 L 398.425781 1109.351562 L 398.734375 1109.070312 L 399.042969 1108.800781 L 399.351562 1108.539062 L 399.660156 1108.289062 L 399.964844 1108.046875 L 400.273438 1107.816406 L 400.582031 1107.589844 L 400.890625 1107.375 L 401.195312 1107.167969 L 401.503906 1106.964844 L 401.8125 1106.773438 L 402.121094 1106.585938 L 402.429688 1106.40625 L 402.734375 1106.234375 L 403.042969 1106.066406 L 403.351562 1105.90625 L 403.660156 1105.753906 L 403.964844 1105.605469 L 404.273438 1105.460938 L 404.582031 1105.324219 L 404.890625 1105.191406 L 405.199219 1105.0625 L 405.503906 1104.941406 L 405.8125 1104.824219 L 406.121094 1104.710938 L 406.429688 1104.601562 L 406.738281 1104.496094 L 407.042969 1104.394531 L 407.351562 1104.296875 L 407.660156 1104.203125 L 407.96875 1104.113281 L 408.273438 1104.027344 L 408.582031 1103.941406 L 409.199219 1103.785156 L 409.507812 1103.710938 L 409.8125 1103.640625 L 410.121094 1103.570312 L 410.429688 1103.507812 L 410.738281 1103.441406 L 411.042969 1103.382812 L 411.660156 1103.265625 L 411.96875 1103.210938 L 412.277344 1103.160156 L 412.582031 1103.109375 L 413.199219 1103.015625 L 413.507812 1102.972656 L 413.8125 1102.929688 L 414.121094 1102.886719 L 414.429688 1102.847656 L 414.738281 1102.8125 L 415.046875 1102.773438 L 415.351562 1102.738281 L 415.660156 1102.707031 L 415.96875 1102.671875 L 416.277344 1102.640625 L 416.582031 1102.613281 L 416.890625 1102.582031 L 417.507812 1102.527344 L 417.816406 1102.503906 L 418.121094 1102.480469 L 419.046875 1102.410156 L 419.351562 1102.390625 L 420.585938 1102.3125 L 420.890625 1102.296875 L 422.125 1102.234375 L 422.429688 1102.222656 L 422.738281 1102.207031 L 423.355469 1102.183594 L 423.660156 1102.167969 L 423.96875 1102.160156 L 424.894531 1102.125 L 425.199219 1102.117188 L 425.507812 1102.105469 L 426.125 1102.089844 L 426.429688 1102.082031 L 427.664062 1102.050781 L 427.96875 1102.042969 L 428.277344 1102.039062 L 428.894531 1102.023438 L 429.199219 1102.019531 L 429.507812 1102.011719 L 430.125 1102.003906 L 430.433594 1101.996094 L 430.738281 1101.992188 L 431.664062 1101.980469 L 431.96875 1101.976562 L 433.203125 1101.960938 L 433.507812 1101.957031 L 433.816406 1101.953125 L 434.125 1101.953125 L 434.433594 1101.949219 L 434.738281 1101.945312 L 435.046875 1101.941406 L 435.355469 1101.941406 L 435.972656 1101.933594 L 436.277344 1101.933594 L 436.585938 1101.929688 L 436.894531 1101.929688 L 437.203125 1101.925781 L 437.507812 1101.925781 L 437.816406 1101.921875 L 438.125 1101.921875 L 438.433594 1101.917969 L 438.742188 1101.917969 L 439.046875 1101.914062 L 439.664062 1101.914062 L 439.972656 1101.910156 L 440.585938 1101.910156 L 440.894531 1101.90625 L 441.511719 1101.90625 L 441.816406 1101.902344 L 442.742188 1101.902344 L 443.050781 1101.898438 L 443.972656 1101.898438 L 444.28125 1101.894531 L 445.820312 1101.894531 L 446.125 1101.890625 L 447.972656 1101.890625 L 448.28125 1101.886719 L 450.742188 1101.886719 L 451.050781 1101.882812 L 452.589844 1101.882812 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1254.988281"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1254.988281"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="1254.988281"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1254.988281"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1217.570312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1217.570312"/>
+ <use xlink:href="#glyph0-3" x="273.594788" y="1217.570312"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="1217.570312"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1180.152344"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1180.152344"/>
+ <use xlink:href="#glyph0-4" x="273.594788" y="1180.152344"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1180.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1142.734375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1142.734375"/>
+ <use xlink:href="#glyph0-5" x="273.594788" y="1142.734375"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="1142.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="265.59375" y="1105.3125"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1105.3125"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="1105.3125"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1105.3125"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1251.550781 L 291.351562 1251.550781 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1214.132812 L 291.351562 1214.132812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1176.714844 L 291.351562 1176.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1139.296875 L 291.351562 1139.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1101.875 L 291.351562 1101.875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 1263.28125 L 299.03125 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 1263.28125 L 337.417969 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 1263.28125 L 375.808594 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 1263.28125 L 414.199219 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 1263.28125 L 452.589844 1259.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="1272.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="1272.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="1272.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="1285.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="258.992188" y="1188.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="258.992188" y="1181.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="258.992188" y="1176.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="258.992188" y="1170.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-11" x="260.996094" y="1090.800781"/>
+ <use xlink:href="#glyph5-3" x="269" y="1090.800781"/>
+ <use xlink:href="#glyph5-6" x="272.333984" y="1090.800781"/>
+ <use xlink:href="#glyph5-19" x="279.664062" y="1090.800781"/>
+ <use xlink:href="#glyph5-15" x="290.333984" y="1090.800781"/>
+ <use xlink:href="#glyph5-3" x="297.664062" y="1090.800781"/>
+ <use xlink:href="#glyph5-16" x="300.998047" y="1090.800781"/>
+</g>
+<g clip-path="url(#clip349)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 474.667969 1296 L 712 1296 L 712 1080 L 474.667969 1080 Z "/>
+</g>
+<g clip-path="url(#clip350)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 1296 L 712 1296 L 712 1080 L 474.667969 1080 Z "/>
+</g>
+<g clip-path="url(#clip351)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 1259.027344 L 697.597656 1259.027344 L 697.597656 1094.398438 L 528.683594 1094.398438 Z "/>
+</g>
+<g clip-path="url(#clip352)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1232.839844 L 697.601562 1232.839844 "/>
+</g>
+<g clip-path="url(#clip353)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1195.421875 L 697.601562 1195.421875 "/>
+</g>
+<g clip-path="url(#clip354)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1158.007812 L 697.601562 1158.007812 "/>
+</g>
+<g clip-path="url(#clip355)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1120.589844 L 697.601562 1120.589844 "/>
+</g>
+<g clip-path="url(#clip356)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 1259.027344 L 555.558594 1094.398438 "/>
+</g>
+<g clip-path="url(#clip357)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 1259.027344 L 593.949219 1094.398438 "/>
+</g>
+<g clip-path="url(#clip358)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 1259.027344 L 632.335938 1094.398438 "/>
+</g>
+<g clip-path="url(#clip359)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 1259.027344 L 670.726562 1094.398438 "/>
+</g>
+<g clip-path="url(#clip360)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1251.546875 L 697.601562 1251.546875 "/>
+</g>
+<g clip-path="url(#clip361)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1214.128906 L 697.601562 1214.128906 "/>
+</g>
+<g clip-path="url(#clip362)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1176.714844 L 697.601562 1176.714844 "/>
+</g>
+<g clip-path="url(#clip363)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1139.296875 L 697.601562 1139.296875 "/>
+</g>
+<g clip-path="url(#clip364)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1101.882812 L 697.601562 1101.882812 "/>
+</g>
+<g clip-path="url(#clip365)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 1259.027344 L 536.363281 1094.398438 "/>
+</g>
+<g clip-path="url(#clip366)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 1259.027344 L 574.753906 1094.398438 "/>
+</g>
+<g clip-path="url(#clip367)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 1259.027344 L 613.140625 1094.398438 "/>
+</g>
+<g clip-path="url(#clip368)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 1259.027344 L 651.53125 1094.398438 "/>
+</g>
+<g clip-path="url(#clip369)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 1259.027344 L 689.921875 1094.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 536.363281 1101.882812 L 536.671875 1101.882812 L 536.976562 1101.886719 L 537.59375 1101.902344 L 538.210938 1101.925781 L 538.515625 1101.941406 L 539.132812 1101.980469 L 539.441406 1102.003906 L 539.746094 1102.027344 L 540.054688 1102.054688 L 540.671875 1102.117188 L 540.980469 1102.152344 L 541.285156 1102.191406 L 541.59375 1102.230469 L 542.210938 1102.316406 L 542.515625 1102.363281 L 543.132812 1102.464844 L 543.75 1102.574219 L 544.054688 1102.632812 L 544.671875 1102.757812 L 544.980469 1102.824219 L 545.289062 1102.894531 L 545.59375 1102.964844 L 546.210938 1103.113281 L 546.519531 1103.191406 L 546.824219 1103.273438 L 547.132812 1103.355469 L 547.75 1103.527344 L 548.058594 1103.617188 L 548.363281 1103.710938 L 548.671875 1103.804688 L 548.980469 1103.902344 L 549.289062 1104.003906 L 549.59375 1104.105469 L 550.210938 1104.316406 L 550.519531 1104.425781 L 550.828125 1104.539062 L 551.132812 1104.652344 L 551.75 1104.886719 L 552.058594 1105.011719 L 552.363281 1105.132812 L 552.671875 1105.261719 L 552.980469 1105.386719 L 553.597656 1105.652344 L 553.902344 1105.789062 L 554.210938 1105.925781 L 554.519531 1106.066406 L 554.828125 1106.210938 L 555.132812 1106.355469 L 555.75 1106.652344 L 556.058594 1106.808594 L 556.367188 1106.960938 L 556.671875 1107.121094 L 557.289062 1107.441406 L 557.597656 1107.605469 L 557.902344 1107.773438 L 558.210938 1107.941406 L 558.519531 1108.113281 L 559.136719 1108.464844 L 559.441406 1108.644531 L 560.367188 1109.195312 L 560.671875 1109.386719 L 561.289062 1109.769531 L 561.597656 1109.964844 L 561.90625 1110.164062 L 562.210938 1110.363281 L 562.519531 1110.566406 L 563.136719 1110.980469 L 563.445312 1111.191406 L 563.75 1111.40625 L 564.367188 1111.835938 L 564.675781 1112.058594 L 564.980469 1112.28125 L 565.289062 1112.503906 L 565.597656 1112.730469 L 565.90625 1112.960938 L 566.214844 1113.195312 L 566.519531 1113.429688 L 566.828125 1113.664062 L 567.136719 1113.902344 L 567.445312 1114.144531 L 567.75 1114.390625 L 568.058594 1114.636719 L 568.675781 1115.136719 L 568.984375 1115.390625 L 569.289062 1115.644531 L 569.597656 1115.90625 L 569.90625 1116.164062 L 570.214844 1116.429688 L 570.519531 1116.695312 L 570.828125 1116.960938 L 571.136719 1117.234375 L 571.445312 1117.503906 L 571.753906 1117.78125 L 572.058594 1118.058594 L 572.675781 1118.621094 L 572.984375 1118.90625 L 573.289062 1119.195312 L 573.90625 1119.773438 L 574.523438 1120.367188 L 574.828125 1120.667969 L 575.136719 1120.96875 L 575.753906 1121.578125 L 576.058594 1121.886719 L 576.675781 1122.511719 L 576.984375 1122.828125 L 577.292969 1123.148438 L 577.597656 1123.46875 L 578.214844 1124.117188 L 578.523438 1124.445312 L 578.832031 1124.777344 L 579.136719 1125.109375 L 579.753906 1125.78125 L 580.0625 1126.121094 L 580.367188 1126.464844 L 580.675781 1126.808594 L 580.984375 1127.15625 L 581.601562 1127.859375 L 581.90625 1128.214844 L 582.214844 1128.570312 L 582.523438 1128.929688 L 582.832031 1129.292969 L 583.136719 1129.65625 L 583.753906 1130.390625 L 584.0625 1130.765625 L 584.371094 1131.136719 L 584.675781 1131.515625 L 584.984375 1131.890625 L 585.601562 1132.65625 L 585.90625 1133.042969 L 586.214844 1133.429688 L 586.523438 1133.820312 L 587.140625 1134.609375 L 587.445312 1135.007812 L 588.371094 1136.214844 L 588.675781 1136.625 L 589.292969 1137.445312 L 589.601562 1137.859375 L 589.910156 1138.277344 L 590.214844 1138.699219 L 590.832031 1139.542969 L 591.140625 1139.96875 L 591.445312 1140.398438 L 592.0625 1141.265625 L 592.679688 1142.140625 L 592.984375 1142.582031 L 593.292969 1143.023438 L 593.601562 1143.472656 L 593.910156 1143.917969 L 594.21875 1144.371094 L 594.523438 1144.824219 L 594.832031 1145.277344 L 595.449219 1146.199219 L 595.753906 1146.660156 L 596.0625 1147.125 L 596.679688 1148.0625 L 596.988281 1148.535156 L 597.292969 1149.011719 L 597.601562 1149.488281 L 598.21875 1150.449219 L 598.523438 1150.933594 L 599.140625 1151.910156 L 599.757812 1152.894531 L 600.0625 1153.390625 L 600.679688 1154.390625 L 600.988281 1154.894531 L 601.292969 1155.402344 L 601.601562 1155.910156 L 602.21875 1156.933594 L 602.527344 1157.449219 L 602.832031 1157.96875 L 603.140625 1158.488281 L 603.449219 1159.011719 L 603.757812 1159.539062 L 604.0625 1160.066406 L 604.371094 1160.59375 L 605.296875 1162.199219 L 605.601562 1162.738281 L 605.910156 1163.28125 L 606.527344 1164.375 L 606.832031 1164.921875 L 607.140625 1165.472656 L 607.449219 1166.027344 L 608.066406 1167.144531 L 608.371094 1167.707031 L 608.679688 1168.269531 L 609.296875 1169.402344 L 609.601562 1169.976562 L 609.910156 1170.546875 L 610.527344 1171.703125 L 610.835938 1172.285156 L 611.140625 1172.867188 L 611.757812 1174.039062 L 612.066406 1174.628906 L 612.375 1175.222656 L 612.679688 1175.816406 L 612.988281 1176.414062 L 613.296875 1177.015625 L 613.605469 1177.613281 L 613.910156 1178.207031 L 614.21875 1178.800781 L 614.527344 1179.390625 L 615.144531 1180.5625 L 615.449219 1181.144531 L 615.757812 1181.726562 L 616.066406 1182.304688 L 616.375 1182.878906 L 616.679688 1183.453125 L 617.296875 1184.59375 L 617.605469 1185.160156 L 617.914062 1185.722656 L 618.21875 1186.285156 L 618.527344 1186.84375 L 619.144531 1187.953125 L 619.449219 1188.507812 L 620.375 1190.148438 L 620.683594 1190.6875 L 620.988281 1191.230469 L 621.605469 1192.300781 L 621.914062 1192.832031 L 622.21875 1193.363281 L 622.835938 1194.417969 L 623.144531 1194.941406 L 623.453125 1195.460938 L 623.757812 1195.980469 L 624.066406 1196.496094 L 624.683594 1197.519531 L 624.988281 1198.027344 L 625.914062 1199.539062 L 626.222656 1200.035156 L 626.527344 1200.535156 L 627.144531 1201.519531 L 627.761719 1202.496094 L 628.066406 1202.980469 L 628.683594 1203.941406 L 628.992188 1204.417969 L 629.296875 1204.894531 L 629.605469 1205.367188 L 630.222656 1206.304688 L 630.53125 1206.769531 L 630.835938 1207.230469 L 631.144531 1207.691406 L 631.761719 1208.605469 L 632.066406 1209.058594 L 632.683594 1209.957031 L 633.300781 1210.847656 L 633.605469 1211.289062 L 634.222656 1212.164062 L 634.53125 1212.597656 L 634.835938 1213.027344 L 635.453125 1213.886719 L 636.070312 1214.730469 L 636.375 1215.152344 L 636.683594 1215.566406 L 636.992188 1215.984375 L 637.300781 1216.394531 L 637.605469 1216.804688 L 638.222656 1217.617188 L 638.839844 1218.421875 L 639.144531 1218.820312 L 639.453125 1219.214844 L 640.070312 1219.996094 L 640.375 1220.386719 L 640.683594 1220.773438 L 640.992188 1221.15625 L 641.609375 1221.914062 L 641.914062 1222.292969 L 642.839844 1223.40625 L 643.148438 1223.773438 L 643.453125 1224.136719 L 643.761719 1224.5 L 644.070312 1224.859375 L 644.378906 1225.214844 L 644.683594 1225.570312 L 645.300781 1226.273438 L 645.609375 1226.617188 L 645.917969 1226.964844 L 646.222656 1227.304688 L 646.53125 1227.648438 L 647.148438 1228.320312 L 647.453125 1228.652344 L 647.761719 1228.984375 L 648.070312 1229.3125 L 648.6875 1229.960938 L 648.992188 1230.28125 L 649.300781 1230.601562 L 649.609375 1230.917969 L 649.917969 1231.230469 L 650.222656 1231.542969 L 650.53125 1231.851562 L 651.148438 1232.460938 L 651.457031 1232.761719 L 651.761719 1233.0625 L 652.070312 1233.359375 L 652.6875 1233.945312 L 652.992188 1234.234375 L 653.300781 1234.523438 L 653.609375 1234.808594 L 654.226562 1235.371094 L 654.53125 1235.648438 L 655.148438 1236.195312 L 655.457031 1236.464844 L 655.761719 1236.734375 L 656.070312 1237 L 656.6875 1237.523438 L 656.996094 1237.78125 L 657.300781 1238.039062 L 657.609375 1238.292969 L 658.226562 1238.792969 L 658.53125 1239.039062 L 659.457031 1239.765625 L 659.765625 1240 L 660.070312 1240.234375 L 660.378906 1240.46875 L 660.6875 1240.695312 L 660.996094 1240.925781 L 661.304688 1241.148438 L 661.609375 1241.371094 L 662.226562 1241.808594 L 662.535156 1242.023438 L 662.839844 1242.238281 L 663.148438 1242.445312 L 663.457031 1242.65625 L 664.074219 1243.0625 L 664.378906 1243.265625 L 664.6875 1243.464844 L 664.996094 1243.660156 L 665.304688 1243.851562 L 665.609375 1244.042969 L 666.226562 1244.417969 L 666.84375 1244.785156 L 667.148438 1244.964844 L 667.457031 1245.140625 L 668.074219 1245.484375 L 668.378906 1245.65625 L 668.6875 1245.824219 L 668.996094 1245.988281 L 669.613281 1246.308594 L 669.917969 1246.46875 L 670.84375 1246.925781 L 671.148438 1247.074219 L 671.765625 1247.363281 L 672.074219 1247.503906 L 672.382812 1247.640625 L 672.6875 1247.777344 L 672.996094 1247.910156 L 673.613281 1248.167969 L 673.917969 1248.296875 L 674.84375 1248.660156 L 675.152344 1248.777344 L 675.457031 1248.890625 L 675.765625 1249.003906 L 676.074219 1249.113281 L 676.691406 1249.324219 L 676.996094 1249.425781 L 677.921875 1249.71875 L 678.226562 1249.808594 L 678.84375 1249.988281 L 679.152344 1250.074219 L 679.460938 1250.15625 L 679.765625 1250.238281 L 680.074219 1250.316406 L 680.691406 1250.464844 L 680.996094 1250.535156 L 681.921875 1250.734375 L 682.230469 1250.792969 L 682.535156 1250.851562 L 682.84375 1250.910156 L 683.152344 1250.964844 L 683.460938 1251.015625 L 683.765625 1251.066406 L 684.074219 1251.113281 L 684.691406 1251.199219 L 685 1251.238281 L 685.304688 1251.277344 L 685.613281 1251.308594 L 685.921875 1251.34375 L 686.230469 1251.371094 L 686.535156 1251.402344 L 687.152344 1251.449219 L 687.769531 1251.488281 L 688.074219 1251.503906 L 688.691406 1251.527344 L 689 1251.535156 L 689.304688 1251.542969 L 689.613281 1251.542969 L 689.921875 1251.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1254.984375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1254.984375"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="1254.984375"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1254.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1217.566406"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1217.566406"/>
+ <use xlink:href="#glyph0-3" x="510.926819" y="1217.566406"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="1217.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1180.152344"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1180.152344"/>
+ <use xlink:href="#glyph0-4" x="510.926819" y="1180.152344"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1180.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1142.734375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1142.734375"/>
+ <use xlink:href="#glyph0-5" x="510.926819" y="1142.734375"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="1142.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="502.925781" y="1105.320312"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1105.320312"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="1105.320312"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1105.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1251.546875 L 528.683594 1251.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1214.128906 L 528.683594 1214.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1176.714844 L 528.683594 1176.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1139.296875 L 528.683594 1139.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1101.882812 L 528.683594 1101.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 1263.28125 L 536.363281 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 1263.28125 L 574.753906 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 1263.28125 L 613.140625 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 1263.28125 L 651.53125 1259.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 1263.28125 L 689.921875 1259.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="1272.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="1272.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="1272.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="1272.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="1272.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="1272.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="1272.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="1285.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="496.324219" y="1188.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.324219" y="1181.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.324219" y="1176.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.324219" y="1170.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-30" x="496.339844" y="1090.800781"/>
+ <use xlink:href="#glyph5-11" x="503.669922" y="1090.800781"/>
+ <use xlink:href="#glyph5-12" x="511.673828" y="1090.800781"/>
+ <use xlink:href="#glyph5-4" x="519.003906" y="1090.800781"/>
+ <use xlink:href="#glyph5-13" x="525.677734" y="1090.800781"/>
+ <use xlink:href="#glyph5-8" x="533.007812" y="1090.800781"/>
+</g>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0 1512 L 237.332031 1512 L 237.332031 1296 L 0 1296 Z "/>
+<g clip-path="url(#clip370)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 1512 L 237.332031 1512 L 237.332031 1296 L 0 1296 Z "/>
+</g>
+<g clip-path="url(#clip371)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 1475.027344 L 222.933594 1475.027344 L 222.933594 1310.398438 L 54.019531 1310.398438 Z "/>
+</g>
+<g clip-path="url(#clip372)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1448.839844 L 222.933594 1448.839844 "/>
+</g>
+<g clip-path="url(#clip373)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1411.421875 L 222.933594 1411.421875 "/>
+</g>
+<g clip-path="url(#clip374)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1374.007812 L 222.933594 1374.007812 "/>
+</g>
+<g clip-path="url(#clip375)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1336.589844 L 222.933594 1336.589844 "/>
+</g>
+<g clip-path="url(#clip376)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 80.890625 1475.027344 L 80.890625 1310.398438 "/>
+</g>
+<g clip-path="url(#clip377)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 119.28125 1475.027344 L 119.28125 1310.398438 "/>
+</g>
+<g clip-path="url(#clip378)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.671875 1475.027344 L 157.671875 1310.398438 "/>
+</g>
+<g clip-path="url(#clip379)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 196.058594 1475.027344 L 196.058594 1310.398438 "/>
+</g>
+<g clip-path="url(#clip380)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1467.546875 L 222.933594 1467.546875 "/>
+</g>
+<g clip-path="url(#clip381)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1430.128906 L 222.933594 1430.128906 "/>
+</g>
+<g clip-path="url(#clip382)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1392.714844 L 222.933594 1392.714844 "/>
+</g>
+<g clip-path="url(#clip383)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1355.296875 L 222.933594 1355.296875 "/>
+</g>
+<g clip-path="url(#clip384)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 1317.882812 L 222.933594 1317.882812 "/>
+</g>
+<g clip-path="url(#clip385)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 1475.027344 L 61.695312 1310.398438 "/>
+</g>
+<g clip-path="url(#clip386)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 1475.027344 L 100.085938 1310.398438 "/>
+</g>
+<g clip-path="url(#clip387)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 1475.027344 L 138.476562 1310.398438 "/>
+</g>
+<g clip-path="url(#clip388)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 1475.027344 L 176.867188 1310.398438 "/>
+</g>
+<g clip-path="url(#clip389)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 1475.027344 L 215.253906 1310.398438 "/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-1" x="74.902344" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph7-1" x="88.023438" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-2" x="101.144531" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph7-2" x="121.875" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-1" x="156.402344" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph8-1" x="164.277344" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-2" x="176.078125" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph8-2" x="190.25" y="1402.058594"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="1470.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1470.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="1470.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="1470.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="1433.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1433.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="1433.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="1433.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="1396.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1396.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="1396.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="1396.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="1358.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1358.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="1358.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="1358.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="1321.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="1321.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="1321.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="1321.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1467.546875 L 54.019531 1467.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1430.128906 L 54.019531 1430.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1392.714844 L 54.019531 1392.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1355.296875 L 54.019531 1355.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 1317.882812 L 54.019531 1317.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 61.695312 1479.28125 L 61.695312 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100.085938 1479.28125 L 100.085938 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 138.476562 1479.28125 L 138.476562 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 176.867188 1479.28125 L 176.867188 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.253906 1479.28125 L 215.253906 1475.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="52.359375" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="57.694962" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="60.360413" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="65.695999" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="90.75" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="96.085587" y="1488.992188"/>
+ <use xlink:href="#glyph0-3" x="98.751038" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="104.086624" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="129.140625" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="134.476212" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="137.141663" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="142.477249" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="167.53125" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="172.866837" y="1488.992188"/>
+ <use xlink:href="#glyph0-5" x="175.532288" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="180.867874" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="205.917969" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="211.253555" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="213.919006" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="219.254593" y="1488.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="135.476562" y="1501.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-2" x="21.683594" y="1402.375"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.683594" y="1399.042969"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.683594" y="1394.046875"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.683594" y="1388.046875"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-31" x="25.328125" y="1306.800781"/>
+ <use xlink:href="#glyph5-26" x="32.658203" y="1306.800781"/>
+ <use xlink:href="#glyph5-5" x="39.988281" y="1306.800781"/>
+ <use xlink:href="#glyph5-22" x="47.318359" y="1306.800781"/>
+ <use xlink:href="#glyph5-24" x="53.992188" y="1306.800781"/>
+ <use xlink:href="#glyph5-3" x="57.988281" y="1306.800781"/>
+ <use xlink:href="#glyph5-15" x="61.322266" y="1306.800781"/>
+ <use xlink:href="#glyph5-5" x="68.652344" y="1306.800781"/>
+</g>
+<g clip-path="url(#clip390)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 237.332031 1512 L 474.664062 1512 L 474.664062 1296 L 237.332031 1296 Z "/>
+</g>
+<g clip-path="url(#clip391)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 237.332031 1512 L 474.664062 1512 L 474.664062 1296 L 237.332031 1296 Z "/>
+</g>
+<g clip-path="url(#clip392)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 291.351562 1475.027344 L 460.265625 1475.027344 L 460.265625 1310.398438 L 291.351562 1310.398438 Z "/>
+</g>
+<g clip-path="url(#clip393)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1448.839844 L 460.265625 1448.839844 "/>
+</g>
+<g clip-path="url(#clip394)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1411.421875 L 460.265625 1411.421875 "/>
+</g>
+<g clip-path="url(#clip395)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1374.007812 L 460.265625 1374.007812 "/>
+</g>
+<g clip-path="url(#clip396)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1336.589844 L 460.265625 1336.589844 "/>
+</g>
+<g clip-path="url(#clip397)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 318.222656 1475.027344 L 318.222656 1310.398438 "/>
+</g>
+<g clip-path="url(#clip398)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 356.613281 1475.027344 L 356.613281 1310.398438 "/>
+</g>
+<g clip-path="url(#clip399)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 395.003906 1475.027344 L 395.003906 1310.398438 "/>
+</g>
+<g clip-path="url(#clip400)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 433.394531 1475.027344 L 433.394531 1310.398438 "/>
+</g>
+<g clip-path="url(#clip401)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1467.546875 L 460.265625 1467.546875 "/>
+</g>
+<g clip-path="url(#clip402)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1430.128906 L 460.265625 1430.128906 "/>
+</g>
+<g clip-path="url(#clip403)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1392.714844 L 460.265625 1392.714844 "/>
+</g>
+<g clip-path="url(#clip404)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1355.296875 L 460.265625 1355.296875 "/>
+</g>
+<g clip-path="url(#clip405)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 291.351562 1317.882812 L 460.265625 1317.882812 "/>
+</g>
+<g clip-path="url(#clip406)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 1475.027344 L 299.03125 1310.398438 "/>
+</g>
+<g clip-path="url(#clip407)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 1475.027344 L 337.417969 1310.398438 "/>
+</g>
+<g clip-path="url(#clip408)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 1475.027344 L 375.808594 1310.398438 "/>
+</g>
+<g clip-path="url(#clip409)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 1475.027344 L 414.199219 1310.398438 "/>
+</g>
+<g clip-path="url(#clip410)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 1475.027344 L 452.589844 1310.398438 "/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph9-1" x="312.132812" y="1456.953125"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph10-1" x="317.699219" y="1451.386719"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph9-2" x="326.042969" y="1443.042969"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph10-2" x="336.066406" y="1433.019531"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph11-1" x="349.046875" y="1420.039062"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph10-3" x="364.917969" y="1404.632812"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph12-1" x="389.914062" y="1414.882812"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph9-3" x="385.332031" y="1383.753906"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph12-1" x="399.023437" y="1377.402344"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph9-4" x="398.46875" y="1370.617188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph12-1" x="412.160156" y="1364.265625"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph11-2" x="415.316406" y="1353.769531"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph9-5" x="430.027344" y="1339.058594"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1470.984375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1470.984375"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="1470.984375"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1470.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1433.566406"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1433.566406"/>
+ <use xlink:href="#glyph0-3" x="273.594788" y="1433.566406"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="1433.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1396.152344"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1396.152344"/>
+ <use xlink:href="#glyph0-4" x="273.594788" y="1396.152344"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1396.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="265.59375" y="1358.734375"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1358.734375"/>
+ <use xlink:href="#glyph0-5" x="273.594788" y="1358.734375"/>
+ <use xlink:href="#glyph0-4" x="278.930374" y="1358.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="265.59375" y="1321.320312"/>
+ <use xlink:href="#glyph0-2" x="270.929337" y="1321.320312"/>
+ <use xlink:href="#glyph0-1" x="273.594788" y="1321.320312"/>
+ <use xlink:href="#glyph0-1" x="278.930374" y="1321.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1467.546875 L 291.351562 1467.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1430.128906 L 291.351562 1430.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1392.714844 L 291.351562 1392.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1355.296875 L 291.351562 1355.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 287.097656 1317.882812 L 291.351562 1317.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 299.03125 1479.28125 L 299.03125 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 337.417969 1479.28125 L 337.417969 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 375.808594 1479.28125 L 375.808594 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 414.199219 1479.28125 L 414.199219 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 452.589844 1479.28125 L 452.589844 1475.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="289.695312" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="295.030899" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="297.69635" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="303.031937" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="328.082031" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="333.417618" y="1488.992188"/>
+ <use xlink:href="#glyph0-3" x="336.083069" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="341.418655" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="366.472656" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="371.808243" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="374.473694" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="379.80928" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="404.863281" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="410.198868" y="1488.992188"/>
+ <use xlink:href="#glyph0-5" x="412.864319" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="418.199905" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="443.253906" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="448.589493" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="451.254944" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="456.59053" y="1488.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="372.808594" y="1501.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-2" x="259.015625" y="1402.375"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="259.015625" y="1399.042969"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="259.015625" y="1394.046875"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="259.015625" y="1388.046875"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-32" x="255.339844" y="1306.800781"/>
+ <use xlink:href="#glyph5-3" x="262.669922" y="1306.800781"/>
+ <use xlink:href="#glyph5-5" x="266.003906" y="1306.800781"/>
+ <use xlink:href="#glyph5-8" x="273.333984" y="1306.800781"/>
+ <use xlink:href="#glyph5-4" x="280.007812" y="1306.800781"/>
+ <use xlink:href="#glyph5-2" x="286.681641" y="1306.800781"/>
+</g>
+<g clip-path="url(#clip411)" clip-rule="nonzero">
+<path style="fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 474.667969 1512 L 712 1512 L 712 1296 L 474.667969 1296 Z "/>
+</g>
+<g clip-path="url(#clip412)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 528.683594 1475.027344 L 697.597656 1475.027344 L 697.597656 1310.398438 L 528.683594 1310.398438 Z "/>
+</g>
+<g clip-path="url(#clip413)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1448.839844 L 697.601562 1448.839844 "/>
+</g>
+<g clip-path="url(#clip414)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1411.421875 L 697.601562 1411.421875 "/>
+</g>
+<g clip-path="url(#clip415)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1374.007812 L 697.601562 1374.007812 "/>
+</g>
+<g clip-path="url(#clip416)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1336.589844 L 697.601562 1336.589844 "/>
+</g>
+<g clip-path="url(#clip417)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 555.558594 1475.027344 L 555.558594 1310.398438 "/>
+</g>
+<g clip-path="url(#clip418)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 593.949219 1475.027344 L 593.949219 1310.398438 "/>
+</g>
+<g clip-path="url(#clip419)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 632.335938 1475.027344 L 632.335938 1310.398438 "/>
+</g>
+<g clip-path="url(#clip420)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 670.726562 1475.027344 L 670.726562 1310.398438 "/>
+</g>
+<g clip-path="url(#clip421)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1467.546875 L 697.601562 1467.546875 "/>
+</g>
+<g clip-path="url(#clip422)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1430.128906 L 697.601562 1430.128906 "/>
+</g>
+<g clip-path="url(#clip423)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1392.714844 L 697.601562 1392.714844 "/>
+</g>
+<g clip-path="url(#clip424)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1355.296875 L 697.601562 1355.296875 "/>
+</g>
+<g clip-path="url(#clip425)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 528.683594 1317.882812 L 697.601562 1317.882812 "/>
+</g>
+<g clip-path="url(#clip426)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 1475.027344 L 536.363281 1310.398438 "/>
+</g>
+<g clip-path="url(#clip427)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 1475.027344 L 574.753906 1310.398438 "/>
+</g>
+<g clip-path="url(#clip428)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 1475.027344 L 613.140625 1310.398438 "/>
+</g>
+<g clip-path="url(#clip429)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 1475.027344 L 651.53125 1310.398438 "/>
+</g>
+<g clip-path="url(#clip430)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 1475.027344 L 689.921875 1310.398438 "/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-1" x="568.894531" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph8-1" x="576.769531" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-2" x="588.570312" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph8-2" x="602.742188" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph7-3" x="621.101562" y="1402.058594"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph6-3" x="643.21875" y="1402.058594"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1470.984375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1470.984375"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="1470.984375"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1470.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1433.566406"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1433.566406"/>
+ <use xlink:href="#glyph0-3" x="510.926819" y="1433.566406"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="1433.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1396.152344"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1396.152344"/>
+ <use xlink:href="#glyph0-4" x="510.926819" y="1396.152344"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1396.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="502.925781" y="1358.734375"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1358.734375"/>
+ <use xlink:href="#glyph0-5" x="510.926819" y="1358.734375"/>
+ <use xlink:href="#glyph0-4" x="516.262405" y="1358.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="502.925781" y="1321.320312"/>
+ <use xlink:href="#glyph0-2" x="508.261368" y="1321.320312"/>
+ <use xlink:href="#glyph0-1" x="510.926819" y="1321.320312"/>
+ <use xlink:href="#glyph0-1" x="516.262405" y="1321.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1467.546875 L 528.683594 1467.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1430.128906 L 528.683594 1430.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1392.714844 L 528.683594 1392.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1355.296875 L 528.683594 1355.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 524.433594 1317.882812 L 528.683594 1317.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 536.363281 1479.28125 L 536.363281 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 574.753906 1479.28125 L 574.753906 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 613.140625 1479.28125 L 613.140625 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 651.53125 1479.28125 L 651.53125 1475.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 689.921875 1479.28125 L 689.921875 1475.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="527.027344" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="532.36293" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="535.028381" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="540.363968" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="565.417969" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="570.753555" y="1488.992188"/>
+ <use xlink:href="#glyph0-3" x="573.419006" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="578.754593" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="603.804688" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="609.140274" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="611.805725" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="617.141312" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="642.195312" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="647.530899" y="1488.992188"/>
+ <use xlink:href="#glyph0-5" x="650.19635" y="1488.992188"/>
+ <use xlink:href="#glyph0-4" x="655.531937" y="1488.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="680.585938" y="1488.992188"/>
+ <use xlink:href="#glyph0-2" x="685.921524" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="688.586975" y="1488.992188"/>
+ <use xlink:href="#glyph0-1" x="693.922562" y="1488.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="610.140625" y="1501.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-2" x="496.347656" y="1402.375"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="496.347656" y="1399.042969"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="496.347656" y="1394.046875"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="496.347656" y="1388.046875"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph5-17" x="500.667969" y="1306.800781"/>
+ <use xlink:href="#glyph5-15" x="509.333984" y="1306.800781"/>
+ <use xlink:href="#glyph5-5" x="516.664062" y="1306.800781"/>
+ <use xlink:href="#glyph5-18" x="523.994141" y="1306.800781"/>
+ <use xlink:href="#glyph5-24" x="530.667969" y="1306.800781"/>
+ <use xlink:href="#glyph5-4" x="534.664062" y="1306.800781"/>
+ <use xlink:href="#glyph5-5" x="541.337891" y="1306.800781"/>
+ <use xlink:href="#glyph5-24" x="548.667969" y="1306.800781"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/trapezoid.svg b/documentation/ui/figure/trapezoid.svg
new file mode 100644
index 0000000..4cd17a2
--- /dev/null
+++ b/documentation/ui/figure/trapezoid.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface186">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.839844 L 201.601562 152.839844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 60.996094 170.347656 L 61.265625 169.144531 L 61.53125 167.945312 L 62.878906 161.949219 L 63.144531 160.75 L 63.414062 159.550781 L 63.683594 158.347656 L 64.492188 154.75 L 64.757812 153.550781 L 65.566406 149.953125 L 65.835938 148.75 L 66.105469 147.550781 L 66.371094 146.351562 L 67.71875 140.355469 L 67.984375 139.152344 L 69.332031 133.15625 L 69.597656 131.957031 L 69.867188 130.757812 L 70.136719 129.554688 L 70.945312 125.957031 L 71.210938 124.757812 L 72.019531 121.160156 L 72.289062 119.957031 L 72.558594 118.757812 L 72.824219 117.558594 L 73.902344 112.761719 L 74.167969 111.5625 L 74.4375 110.359375 L 75.515625 105.5625 L 75.78125 104.363281 L 76.320312 101.964844 L 76.589844 100.761719 L 77.128906 98.363281 L 77.394531 97.164062 L 78.472656 92.367188 L 78.742188 91.164062 L 79.007812 89.964844 L 80.355469 83.96875 L 80.621094 82.769531 L 80.890625 81.566406 L 81.96875 76.769531 L 82.234375 75.570312 L 82.773438 73.171875 L 83.042969 71.96875 L 83.582031 69.570312 L 83.847656 68.371094 L 85.195312 62.375 L 85.460938 61.171875 L 86.808594 55.175781 L 87.074219 53.976562 L 87.34375 52.777344 L 87.613281 51.574219 L 88.152344 49.175781 L 88.417969 47.976562 L 89.496094 43.179688 L 89.765625 41.976562 L 90.03125 40.777344 L 91.378906 34.78125 L 91.644531 33.582031 L 91.914062 32.378906 L 92.992188 27.582031 L 93.257812 26.382812 L 93.796875 23.984375 L 94.066406 22.78125 L 94.335938 21.882812 L 161.28125 21.882812 L 161.550781 22.78125 L 161.820312 23.984375 L 162.628906 27.582031 L 162.894531 28.78125 L 163.703125 32.378906 L 163.972656 33.582031 L 164.242188 34.78125 L 164.507812 35.980469 L 165.855469 41.976562 L 166.121094 43.179688 L 167.46875 49.175781 L 167.734375 50.375 L 168.003906 51.574219 L 168.273438 52.777344 L 169.082031 56.375 L 169.347656 57.574219 L 170.15625 61.171875 L 170.425781 62.375 L 170.695312 63.574219 L 170.960938 64.773438 L 172.308594 70.769531 L 172.574219 71.96875 L 172.84375 73.171875 L 173.921875 77.96875 L 174.1875 79.167969 L 174.726562 81.566406 L 174.996094 82.769531 L 175.535156 85.167969 L 175.800781 86.367188 L 176.878906 91.164062 L 177.144531 92.367188 L 178.492188 98.363281 L 178.757812 99.5625 L 179.027344 100.761719 L 179.296875 101.964844 L 180.105469 105.5625 L 180.371094 106.761719 L 181.179688 110.359375 L 181.449219 111.5625 L 181.71875 112.761719 L 181.984375 113.960938 L 183.332031 119.957031 L 183.597656 121.160156 L 184.945312 127.15625 L 185.210938 128.355469 L 185.480469 129.554688 L 185.75 130.757812 L 186.558594 134.355469 L 186.824219 135.554688 L 187.632812 139.152344 L 187.902344 140.355469 L 188.171875 141.554688 L 188.4375 142.753906 L 189.785156 148.75 L 190.050781 149.953125 L 191.128906 154.75 L 191.394531 155.949219 L 191.933594 158.347656 L 192.203125 159.550781 L 192.742188 161.949219 L 193.007812 163.148438 L 194.355469 169.144531 L 194.621094 170.347656 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/triangle.svg b/documentation/ui/figure/triangle.svg
new file mode 100644
index 0000000..fd3e09d
--- /dev/null
+++ b/documentation/ui/figure/triangle.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface181">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.800781 L 201.601562 152.800781 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.308594 L 201.601562 115.308594 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 77.820312 L 201.601562 77.820312 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.328125 L 201.601562 40.328125 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.054688 L 201.601562 134.054688 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.5625 L 201.601562 96.5625 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.074219 L 201.601562 59.074219 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.582031 L 201.601562 21.582031 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 171.546875 L 61.265625 170.34375 L 61.53125 169.742188 L 62.070312 168.539062 L 62.339844 167.941406 L 62.878906 166.738281 L 63.144531 166.136719 L 64.222656 163.730469 L 64.492188 163.132812 L 64.757812 162.53125 L 66.105469 159.523438 L 66.371094 158.921875 L 66.640625 158.324219 L 67.71875 155.917969 L 67.984375 155.316406 L 68.253906 154.714844 L 68.523438 154.117188 L 69.332031 152.3125 L 69.597656 151.710938 L 70.40625 149.90625 L 70.675781 149.308594 L 70.945312 148.707031 L 71.210938 148.105469 L 72.558594 145.097656 L 72.824219 144.5 L 73.902344 142.09375 L 74.167969 141.492188 L 74.707031 140.289062 L 74.976562 139.691406 L 75.515625 138.488281 L 75.78125 137.886719 L 76.589844 136.082031 L 76.859375 135.484375 L 77.128906 134.882812 L 77.394531 134.28125 L 78.742188 131.273438 L 79.007812 130.675781 L 80.355469 127.667969 L 80.621094 127.066406 L 80.890625 126.464844 L 81.160156 125.867188 L 81.96875 124.0625 L 82.234375 123.460938 L 82.773438 122.257812 L 83.042969 121.660156 L 83.582031 120.457031 L 83.847656 119.855469 L 84.925781 117.449219 L 85.195312 116.851562 L 85.460938 116.25 L 86.808594 113.242188 L 87.074219 112.640625 L 87.34375 112.042969 L 88.152344 110.238281 L 88.417969 109.636719 L 88.957031 108.433594 L 89.226562 107.835938 L 89.765625 106.632812 L 90.03125 106.03125 L 91.109375 103.625 L 91.378906 103.027344 L 91.644531 102.425781 L 92.992188 99.417969 L 93.257812 98.816406 L 93.527344 98.21875 L 94.605469 95.8125 L 94.871094 95.210938 L 95.410156 94.007812 L 95.679688 93.410156 L 96.21875 92.207031 L 96.484375 91.605469 L 97.292969 89.800781 L 97.5625 89.203125 L 97.832031 88.601562 L 98.097656 88 L 99.445312 84.992188 L 99.710938 84.394531 L 101.058594 81.386719 L 101.324219 80.785156 L 101.59375 80.183594 L 101.863281 79.585938 L 102.402344 78.382812 L 102.667969 77.78125 L 103.476562 75.976562 L 103.746094 75.378906 L 104.015625 74.777344 L 104.28125 74.175781 L 105.628906 71.167969 L 105.894531 70.570312 L 107.242188 67.5625 L 107.507812 66.960938 L 107.777344 66.359375 L 108.046875 65.761719 L 108.855469 63.957031 L 109.121094 63.355469 L 109.660156 62.152344 L 109.929688 61.554688 L 110.46875 60.351562 L 110.734375 59.75 L 111.8125 57.34375 L 112.082031 56.746094 L 112.347656 56.144531 L 113.695312 53.136719 L 113.960938 52.535156 L 114.230469 51.9375 L 115.308594 49.53125 L 115.574219 48.929688 L 116.113281 47.726562 L 116.382812 47.128906 L 116.921875 45.925781 L 117.1875 45.324219 L 117.996094 43.519531 L 118.265625 42.921875 L 118.53125 42.320312 L 119.878906 39.3125 L 120.144531 38.710938 L 120.414062 38.113281 L 121.492188 35.707031 L 121.757812 35.105469 L 122.296875 33.902344 L 122.566406 33.304688 L 123.105469 32.101562 L 123.371094 31.5 L 124.179688 29.695312 L 124.449219 29.097656 L 124.71875 28.496094 L 124.984375 27.894531 L 126.332031 24.886719 L 126.597656 24.289062 L 127.675781 21.882812 L 127.945312 21.882812 L 128.210938 22.484375 L 129.019531 24.289062 L 129.289062 24.886719 L 129.558594 25.488281 L 129.824219 26.089844 L 131.171875 29.097656 L 131.4375 29.695312 L 132.515625 32.101562 L 132.78125 32.703125 L 133.050781 33.304688 L 133.320312 33.902344 L 134.128906 35.707031 L 134.394531 36.308594 L 135.203125 38.113281 L 135.472656 38.710938 L 135.742188 39.3125 L 136.007812 39.914062 L 137.355469 42.921875 L 137.621094 43.519531 L 138.96875 46.527344 L 139.234375 47.128906 L 139.503906 47.726562 L 140.582031 50.132812 L 140.847656 50.734375 L 141.386719 51.9375 L 141.65625 52.535156 L 142.195312 53.738281 L 142.460938 54.339844 L 143.539062 56.746094 L 143.808594 57.34375 L 144.074219 57.945312 L 145.421875 60.953125 L 145.6875 61.554688 L 145.957031 62.152344 L 146.765625 63.957031 L 147.03125 64.558594 L 147.570312 65.761719 L 147.839844 66.359375 L 148.378906 67.5625 L 148.644531 68.164062 L 149.722656 70.570312 L 149.992188 71.167969 L 150.257812 71.769531 L 151.605469 74.777344 L 151.871094 75.378906 L 152.140625 75.976562 L 153.21875 78.382812 L 153.484375 78.984375 L 153.753906 79.585938 L 154.023438 80.183594 L 154.832031 81.988281 L 155.097656 82.589844 L 155.90625 84.394531 L 156.175781 84.992188 L 156.445312 85.59375 L 156.710938 86.195312 L 158.058594 89.203125 L 158.324219 89.800781 L 159.671875 92.808594 L 159.9375 93.410156 L 160.207031 94.007812 L 161.015625 95.8125 L 161.28125 96.414062 L 162.089844 98.21875 L 162.359375 98.816406 L 162.628906 99.417969 L 162.894531 100.019531 L 164.242188 103.027344 L 164.507812 103.625 L 165.855469 106.632812 L 166.121094 107.234375 L 166.390625 107.835938 L 166.660156 108.433594 L 167.46875 110.238281 L 167.734375 110.839844 L 168.273438 112.042969 L 168.542969 112.640625 L 169.082031 113.84375 L 169.347656 114.445312 L 170.425781 116.851562 L 170.695312 117.449219 L 170.960938 118.050781 L 172.308594 121.058594 L 172.574219 121.660156 L 172.84375 122.257812 L 173.921875 124.664062 L 174.1875 125.265625 L 174.457031 125.867188 L 174.726562 126.464844 L 175.535156 128.269531 L 175.800781 128.871094 L 176.609375 130.675781 L 176.878906 131.273438 L 177.144531 131.875 L 178.492188 134.882812 L 178.757812 135.484375 L 179.027344 136.082031 L 180.105469 138.488281 L 180.371094 139.089844 L 180.640625 139.691406 L 180.910156 140.289062 L 181.71875 142.09375 L 181.984375 142.695312 L 182.792969 144.5 L 183.0625 145.097656 L 183.332031 145.699219 L 183.597656 146.300781 L 184.945312 149.308594 L 185.210938 149.90625 L 186.558594 152.914062 L 186.824219 153.515625 L 187.09375 154.117188 L 187.363281 154.714844 L 188.171875 156.519531 L 188.4375 157.121094 L 188.976562 158.324219 L 189.246094 158.921875 L 189.785156 160.125 L 190.050781 160.726562 L 191.128906 163.132812 L 191.394531 163.730469 L 192.742188 166.738281 L 193.007812 167.339844 L 193.277344 167.941406 L 193.546875 168.539062 L 194.355469 170.34375 L 194.621094 170.945312 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.492188"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.492188"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.492188"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.492188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.511719"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.511719"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.511719"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.511719"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.019531"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.019531"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.019531"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.019531"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.054688 L 54.019531 134.054688 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.5625 L 54.019531 96.5625 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.074219 L 54.019531 59.074219 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.582031 L 54.019531 21.582031 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/figure/zShape.svg b/documentation/ui/figure/zShape.svg
new file mode 100644
index 0000000..40b41b3
--- /dev/null
+++ b/documentation/ui/figure/zShape.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="216pt" height="216pt" viewBox="0 0 216 216" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.3125 0 L 0.3125 -6.875 L 5.765625 -6.875 L 5.765625 0 Z M 4.90625 -0.859375 L 4.90625 -6.015625 L 1.171875 -6.015625 L 1.171875 -0.859375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 2.59375 -6.703125 C 3.457031 -6.703125 4.085938 -6.347656 4.484375 -5.640625 C 4.773438 -5.085938 4.921875 -4.328125 4.921875 -3.359375 C 4.921875 -2.453125 4.785156 -1.695312 4.515625 -1.09375 C 4.128906 -0.238281 3.488281 0.1875 2.59375 0.1875 C 1.78125 0.1875 1.179688 -0.160156 0.796875 -0.859375 C 0.460938 -1.453125 0.296875 -2.238281 0.296875 -3.21875 C 0.296875 -3.976562 0.394531 -4.632812 0.59375 -5.1875 C 0.957031 -6.195312 1.625 -6.703125 2.59375 -6.703125 Z M 2.578125 -0.578125 C 3.015625 -0.578125 3.363281 -0.769531 3.625 -1.15625 C 3.882812 -1.550781 4.015625 -2.273438 4.015625 -3.328125 C 4.015625 -4.085938 3.921875 -4.710938 3.734375 -5.203125 C 3.546875 -5.703125 3.179688 -5.953125 2.640625 -5.953125 C 2.148438 -5.953125 1.789062 -5.71875 1.5625 -5.25 C 1.332031 -4.78125 1.21875 -4.09375 1.21875 -3.1875 C 1.21875 -2.5 1.289062 -1.945312 1.4375 -1.53125 C 1.65625 -0.894531 2.035156 -0.578125 2.578125 -0.578125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 0.8125 -1.015625 L 1.796875 -1.015625 L 1.796875 0 L 0.8125 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;" d="M 0.296875 0 C 0.328125 -0.570312 0.445312 -1.070312 0.65625 -1.5 C 0.863281 -1.9375 1.269531 -2.328125 1.875 -2.671875 L 2.765625 -3.1875 C 3.171875 -3.425781 3.457031 -3.628906 3.625 -3.796875 C 3.875 -4.054688 4 -4.351562 4 -4.6875 C 4 -5.070312 3.878906 -5.378906 3.640625 -5.609375 C 3.410156 -5.835938 3.101562 -5.953125 2.71875 -5.953125 C 2.132812 -5.953125 1.734375 -5.734375 1.515625 -5.296875 C 1.398438 -5.066406 1.335938 -4.742188 1.328125 -4.328125 L 0.46875 -4.328125 C 0.476562 -4.910156 0.582031 -5.382812 0.78125 -5.75 C 1.144531 -6.40625 1.789062 -6.734375 2.71875 -6.734375 C 3.488281 -6.734375 4.050781 -6.523438 4.40625 -6.109375 C 4.757812 -5.691406 4.9375 -5.226562 4.9375 -4.71875 C 4.9375 -4.1875 4.75 -3.726562 4.375 -3.34375 C 4.15625 -3.125 3.757812 -2.851562 3.1875 -2.53125 L 2.546875 -2.1875 C 2.242188 -2.019531 2.003906 -1.859375 1.828125 -1.703125 C 1.515625 -1.429688 1.316406 -1.128906 1.234375 -0.796875 L 4.90625 -0.796875 L 4.90625 0 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-4">
+<path style="stroke:none;" d="M 1.1875 -1.703125 C 1.238281 -1.222656 1.460938 -0.894531 1.859375 -0.71875 C 2.054688 -0.625 2.285156 -0.578125 2.546875 -0.578125 C 3.046875 -0.578125 3.414062 -0.734375 3.65625 -1.046875 C 3.894531 -1.367188 4.015625 -1.722656 4.015625 -2.109375 C 4.015625 -2.578125 3.867188 -2.9375 3.578125 -3.1875 C 3.296875 -3.445312 2.957031 -3.578125 2.5625 -3.578125 C 2.269531 -3.578125 2.019531 -3.519531 1.8125 -3.40625 C 1.601562 -3.289062 1.425781 -3.132812 1.28125 -2.9375 L 0.546875 -2.984375 L 1.0625 -6.59375 L 4.546875 -6.59375 L 4.546875 -5.78125 L 1.703125 -5.78125 L 1.40625 -3.921875 C 1.5625 -4.035156 1.710938 -4.125 1.859375 -4.1875 C 2.109375 -4.289062 2.394531 -4.34375 2.71875 -4.34375 C 3.332031 -4.34375 3.851562 -4.140625 4.28125 -3.734375 C 4.707031 -3.335938 4.921875 -2.835938 4.921875 -2.234375 C 4.921875 -1.597656 4.722656 -1.035156 4.328125 -0.546875 C 3.941406 -0.0664062 3.320312 0.171875 2.46875 0.171875 C 1.914062 0.171875 1.429688 0.0195312 1.015625 -0.28125 C 0.597656 -0.59375 0.363281 -1.066406 0.3125 -1.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-5">
+<path style="stroke:none;" d="M 5.015625 -6.59375 L 5.015625 -5.859375 C 4.796875 -5.648438 4.507812 -5.285156 4.15625 -4.765625 C 3.800781 -4.242188 3.484375 -3.6875 3.203125 -3.09375 C 2.929688 -2.507812 2.726562 -1.976562 2.59375 -1.5 C 2.5 -1.1875 2.378906 -0.6875 2.234375 0 L 1.3125 0 C 1.519531 -1.28125 1.988281 -2.554688 2.71875 -3.828125 C 3.144531 -4.566406 3.59375 -5.207031 4.0625 -5.75 L 0.34375 -5.75 L 0.34375 -6.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-6">
+<path style="stroke:none;" d="M 0.921875 -4.75 L 0.921875 -5.390625 C 1.523438 -5.453125 1.945312 -5.550781 2.1875 -5.6875 C 2.425781 -5.832031 2.609375 -6.164062 2.734375 -6.6875 L 3.390625 -6.6875 L 3.390625 0 L 2.5 0 L 2.5 -4.75 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-0">
+<path style="stroke:none;" d="M 0.390625 0 L 0.390625 -8.609375 L 7.21875 -8.609375 L 7.21875 0 Z M 6.140625 -1.078125 L 6.140625 -7.53125 L 1.46875 -7.53125 L 1.46875 -1.078125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph1-1">
+<path style="stroke:none;" d="M 0.171875 -6.28125 L 1.546875 -6.28125 L 2.984375 -4.0625 L 4.4375 -6.28125 L 5.71875 -6.25 L 3.609375 -3.21875 L 5.8125 0 L 4.46875 0 L 2.90625 -2.359375 L 1.40625 0 L 0.0625 0 L 2.28125 -3.21875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-0">
+<path style="stroke:none;" d="M 2.125 -0.59375 L -8.46875 -0.59375 L -8.46875 -6.59375 L 2.125 -6.59375 Z M 1.453125 -1.265625 L 1.453125 -5.9375 L -7.78125 -5.9375 L -7.78125 -1.265625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph2-1">
+<path style="stroke:none;" d="M -1.828125 -2 C -1.265625 -2 -0.882812 -2.050781 -0.6875 -2.15625 C -0.5 -2.269531 -0.40625 -2.472656 -0.40625 -2.765625 C -0.40625 -3.222656 -0.726562 -3.601562 -1.375 -3.90625 C -2.019531 -4.207031 -2.835938 -4.359375 -3.828125 -4.359375 L -5.390625 -4.359375 L -5.390625 -5.46875 L -1.453125 -5.46875 C -1.097656 -5.46875 -0.832031 -5.503906 -0.65625 -5.578125 C -0.488281 -5.648438 -0.40625 -5.765625 -0.40625 -5.921875 C -0.40625 -6.085938 -0.488281 -6.210938 -0.65625 -6.296875 C -0.820312 -6.390625 -1.066406 -6.4375 -1.390625 -6.4375 L -1.5625 -6.4375 L -1.5625 -6.6875 C -1.53125 -6.6875 -1.492188 -6.6875 -1.453125 -6.6875 C -1.421875 -6.695312 -1.367188 -6.703125 -1.296875 -6.703125 C -0.847656 -6.703125 -0.5 -6.601562 -0.25 -6.40625 C -0.0078125 -6.21875 0.109375 -5.953125 0.109375 -5.609375 C 0.109375 -5.210938 -0.0625 -4.910156 -0.40625 -4.703125 C -0.75 -4.503906 -1.265625 -4.398438 -1.953125 -4.390625 C -1.242188 -4.210938 -0.722656 -3.96875 -0.390625 -3.65625 C -0.0546875 -3.351562 0.109375 -2.96875 0.109375 -2.5 C 0.109375 -2.144531 0.00390625 -1.851562 -0.203125 -1.625 C -0.410156 -1.394531 -0.71875 -1.234375 -1.125 -1.140625 C -1.050781 -1.128906 -0.941406 -1.125 -0.796875 -1.125 C -0.285156 -1.125 0.273438 -1.253906 0.890625 -1.515625 C 1.515625 -1.773438 1.882812 -1.90625 2 -1.90625 C 2.15625 -1.90625 2.28125 -1.859375 2.375 -1.765625 C 2.46875 -1.671875 2.515625 -1.546875 2.515625 -1.390625 C 2.515625 -1.210938 2.445312 -1.082031 2.3125 -1 C 2.175781 -0.914062 1.960938 -0.875 1.671875 -0.875 C 1.597656 -0.875 1.363281 -0.878906 0.96875 -0.890625 C 0.582031 -0.910156 0.226562 -0.921875 -0.09375 -0.921875 C -0.382812 -0.921875 -0.789062 -0.914062 -1.3125 -0.90625 C -1.832031 -0.894531 -2.210938 -0.890625 -2.453125 -0.890625 L -5.390625 -0.890625 L -5.390625 -2 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-0">
+<path style="stroke:none;" d="M 2.65625 -0.75 L -10.578125 -0.75 L -10.578125 -8.25 L 2.65625 -8.25 Z M 1.8125 -1.59375 L 1.8125 -7.40625 L -9.734375 -7.40625 L -9.734375 -1.59375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-1">
+<path style="stroke:none;" d="M -10.546875 -4.296875 C -9.796875 -3.460938 -8.925781 -2.867188 -7.9375 -2.515625 C -6.945312 -2.171875 -5.617188 -2 -3.953125 -2 C -2.273438 -2 -0.945312 -2.171875 0.03125 -2.515625 C 1.019531 -2.867188 1.890625 -3.460938 2.640625 -4.296875 L 2.953125 -3.984375 C 2.191406 -2.953125 1.203125 -2.144531 -0.015625 -1.5625 C -1.234375 -0.976562 -2.546875 -0.6875 -3.953125 -0.6875 C -5.359375 -0.6875 -6.671875 -0.976562 -7.890625 -1.5625 C -9.117188 -2.15625 -10.109375 -2.960938 -10.859375 -3.984375 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph3-2">
+<path style="stroke:none;" d="M -10.546875 -0.703125 L -10.859375 -0.984375 C -10.109375 -2.023438 -9.117188 -2.835938 -7.890625 -3.421875 C -6.660156 -4.015625 -5.347656 -4.3125 -3.953125 -4.3125 C -2.546875 -4.3125 -1.234375 -4.015625 -0.015625 -3.421875 C 1.203125 -2.835938 2.191406 -2.023438 2.953125 -0.984375 L 2.640625 -0.703125 C 1.898438 -1.535156 1.035156 -2.125 0.046875 -2.46875 C -0.929688 -2.820312 -2.265625 -3 -3.953125 -3 C -5.628906 -3 -6.957031 -2.820312 -7.9375 -2.46875 C -8.925781 -2.125 -9.796875 -1.535156 -10.546875 -0.703125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-0">
+<path style="stroke:none;" d="M 0 -0.390625 L -8.609375 -0.390625 L -8.609375 -7.21875 L 0 -7.21875 Z M -1.078125 -6.140625 L -7.53125 -6.140625 L -7.53125 -1.46875 L -1.078125 -1.46875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph4-1">
+<path style="stroke:none;" d="M -6.28125 -0.171875 L -6.28125 -1.546875 L -4.0625 -2.984375 L -6.28125 -4.4375 L -6.25 -5.71875 L -3.21875 -3.609375 L 0 -5.8125 L 0 -4.46875 L -2.359375 -2.90625 L 0 -1.40625 L 0 -0.0625 L -3.21875 -2.28125 Z "/>
+</symbol>
+</g>
+<clipPath id="clip1">
+ <path d="M 54.019531 14.398438 L 202 14.398438 L 202 180 L 54.019531 180 Z "/>
+</clipPath>
+<clipPath id="clip2">
+ <path d="M 54.019531 152 L 202 152 L 202 154 L 54.019531 154 Z "/>
+</clipPath>
+<clipPath id="clip3">
+ <path d="M 54.019531 115 L 202 115 L 202 116 L 54.019531 116 Z "/>
+</clipPath>
+<clipPath id="clip4">
+ <path d="M 54.019531 77 L 202 77 L 202 79 L 54.019531 79 Z "/>
+</clipPath>
+<clipPath id="clip5">
+ <path d="M 54.019531 40 L 202 40 L 202 41 L 54.019531 41 Z "/>
+</clipPath>
+<clipPath id="clip6">
+ <path d="M 77 14.398438 L 78 14.398438 L 78 180 L 77 180 Z "/>
+</clipPath>
+<clipPath id="clip7">
+ <path d="M 110 14.398438 L 112 14.398438 L 112 180 L 110 180 Z "/>
+</clipPath>
+<clipPath id="clip8">
+ <path d="M 144 14.398438 L 145 14.398438 L 145 180 L 144 180 Z "/>
+</clipPath>
+<clipPath id="clip9">
+ <path d="M 177 14.398438 L 179 14.398438 L 179 180 L 177 180 Z "/>
+</clipPath>
+<clipPath id="clip10">
+ <path d="M 54.019531 171 L 202.601562 171 L 202.601562 173 L 54.019531 173 Z "/>
+</clipPath>
+<clipPath id="clip11">
+ <path d="M 54.019531 133 L 202.601562 133 L 202.601562 135 L 54.019531 135 Z "/>
+</clipPath>
+<clipPath id="clip12">
+ <path d="M 54.019531 96 L 202.601562 96 L 202.601562 98 L 54.019531 98 Z "/>
+</clipPath>
+<clipPath id="clip13">
+ <path d="M 54.019531 58 L 202.601562 58 L 202.601562 60 L 54.019531 60 Z "/>
+</clipPath>
+<clipPath id="clip14">
+ <path d="M 54.019531 21 L 202.601562 21 L 202.601562 23 L 54.019531 23 Z "/>
+</clipPath>
+<clipPath id="clip15">
+ <path d="M 60 14.398438 L 62 14.398438 L 62 180 L 60 180 Z "/>
+</clipPath>
+<clipPath id="clip16">
+ <path d="M 93 14.398438 L 95 14.398438 L 95 180 L 93 180 Z "/>
+</clipPath>
+<clipPath id="clip17">
+ <path d="M 127 14.398438 L 129 14.398438 L 129 180 L 127 180 Z "/>
+</clipPath>
+<clipPath id="clip18">
+ <path d="M 160 14.398438 L 162 14.398438 L 162 180 L 160 180 Z "/>
+</clipPath>
+<clipPath id="clip19">
+ <path d="M 194 14.398438 L 196 14.398438 L 196 180 L 194 180 Z "/>
+</clipPath>
+</defs>
+<g id="surface266">
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<rect x="0" y="0" width="216" height="216" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 216 L 216 216 L 216 0 L 0 0 Z "/>
+<g clip-path="url(#clip1)" clip-rule="nonzero">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(89.803922%,89.803922%,89.803922%);fill-opacity:1;" d="M 54.019531 179.027344 L 201.601562 179.027344 L 201.601562 14.398438 L 54.019531 14.398438 Z "/>
+</g>
+<g clip-path="url(#clip2)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 152.839844 L 201.601562 152.839844 "/>
+</g>
+<g clip-path="url(#clip3)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 115.421875 L 201.601562 115.421875 "/>
+</g>
+<g clip-path="url(#clip4)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 78.007812 L 201.601562 78.007812 "/>
+</g>
+<g clip-path="url(#clip5)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 40.589844 L 201.601562 40.589844 "/>
+</g>
+<g clip-path="url(#clip6)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 77.496094 179.027344 L 77.496094 14.398438 "/>
+</g>
+<g clip-path="url(#clip7)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.039062 179.027344 L 111.039062 14.398438 "/>
+</g>
+<g clip-path="url(#clip8)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 144.578125 179.027344 L 144.578125 14.398438 "/>
+</g>
+<g clip-path="url(#clip9)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:0.531496;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(94.901961%,94.901961%,94.901961%);stroke-opacity:1;stroke-miterlimit:10;" d="M 178.121094 179.027344 L 178.121094 14.398438 "/>
+</g>
+<g clip-path="url(#clip10)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 171.546875 L 201.601562 171.546875 "/>
+</g>
+<g clip-path="url(#clip11)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 134.128906 L 201.601562 134.128906 "/>
+</g>
+<g clip-path="url(#clip12)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 96.714844 L 201.601562 96.714844 "/>
+</g>
+<g clip-path="url(#clip13)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 59.296875 L 201.601562 59.296875 "/>
+</g>
+<g clip-path="url(#clip14)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.019531 21.882812 L 201.601562 21.882812 "/>
+</g>
+<g clip-path="url(#clip15)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 179.027344 L 60.726562 14.398438 "/>
+</g>
+<g clip-path="url(#clip16)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 179.027344 L 94.269531 14.398438 "/>
+</g>
+<g clip-path="url(#clip17)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 179.027344 L 127.808594 14.398438 "/>
+</g>
+<g clip-path="url(#clip18)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 179.027344 L 161.351562 14.398438 "/>
+</g>
+<g clip-path="url(#clip19)" clip-rule="nonzero">
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 179.027344 L 194.890625 14.398438 "/>
+</g>
+<path style="fill:none;stroke-width:7.440945;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:1;" d="M 60.726562 21.882812 L 60.996094 21.882812 L 61.265625 21.886719 L 61.53125 21.894531 L 61.800781 21.902344 L 62.339844 21.925781 L 62.609375 21.941406 L 62.878906 21.960938 L 63.144531 21.980469 L 63.683594 22.027344 L 63.953125 22.054688 L 64.492188 22.117188 L 64.757812 22.152344 L 65.296875 22.230469 L 65.835938 22.316406 L 66.105469 22.363281 L 66.371094 22.414062 L 66.640625 22.464844 L 67.179688 22.574219 L 67.449219 22.632812 L 67.71875 22.695312 L 67.984375 22.757812 L 68.253906 22.824219 L 68.792969 22.964844 L 69.332031 23.113281 L 69.597656 23.191406 L 70.136719 23.355469 L 70.675781 23.527344 L 70.945312 23.617188 L 71.210938 23.710938 L 71.480469 23.804688 L 71.75 23.902344 L 72.289062 24.105469 L 72.558594 24.210938 L 72.824219 24.316406 L 73.09375 24.425781 L 73.632812 24.652344 L 73.902344 24.769531 L 74.167969 24.886719 L 74.4375 25.011719 L 74.707031 25.132812 L 74.976562 25.261719 L 75.246094 25.386719 L 75.515625 25.519531 L 75.78125 25.652344 L 76.320312 25.925781 L 76.589844 26.066406 L 77.128906 26.355469 L 77.394531 26.503906 L 77.664062 26.652344 L 77.933594 26.808594 L 78.203125 26.960938 L 78.742188 27.28125 L 79.007812 27.441406 L 79.277344 27.605469 L 79.816406 27.941406 L 80.085938 28.113281 L 80.355469 28.289062 L 80.621094 28.464844 L 80.890625 28.644531 L 81.699219 29.195312 L 81.96875 29.386719 L 82.234375 29.578125 L 82.503906 29.769531 L 82.773438 29.964844 L 83.3125 30.363281 L 83.582031 30.566406 L 83.847656 30.773438 L 84.117188 30.980469 L 84.386719 31.191406 L 85.195312 31.835938 L 85.460938 32.058594 L 86 32.503906 L 86.269531 32.730469 L 86.539062 32.960938 L 86.808594 33.195312 L 87.074219 33.429688 L 87.34375 33.664062 L 87.613281 33.902344 L 87.882812 34.144531 L 88.152344 34.390625 L 88.417969 34.636719 L 88.957031 35.136719 L 89.496094 35.644531 L 89.765625 35.90625 L 90.03125 36.164062 L 90.839844 36.960938 L 91.109375 37.234375 L 91.378906 37.503906 L 91.644531 37.78125 L 91.914062 38.058594 L 92.453125 38.621094 L 92.722656 38.90625 L 92.992188 39.195312 L 93.257812 39.484375 L 93.527344 39.773438 L 94.066406 40.367188 L 94.605469 40.96875 L 94.871094 41.273438 L 95.140625 41.578125 L 95.410156 41.886719 L 95.949219 42.511719 L 96.21875 42.828125 L 96.484375 43.148438 L 96.753906 43.46875 L 97.292969 44.117188 L 97.5625 44.445312 L 97.832031 44.777344 L 98.097656 45.109375 L 98.636719 45.78125 L 98.90625 46.121094 L 99.445312 46.808594 L 99.710938 47.15625 L 100.25 47.859375 L 100.789062 48.570312 L 101.058594 48.929688 L 101.324219 49.292969 L 101.59375 49.65625 L 102.132812 50.390625 L 102.402344 50.765625 L 102.667969 51.136719 L 102.9375 51.515625 L 103.207031 51.890625 L 103.746094 52.65625 L 104.015625 53.042969 L 104.28125 53.429688 L 104.550781 53.820312 L 105.089844 54.609375 L 105.359375 55.007812 L 105.628906 55.410156 L 105.894531 55.8125 L 106.164062 56.214844 L 106.972656 57.445312 L 107.242188 57.859375 L 107.507812 58.277344 L 108.316406 59.542969 L 108.585938 59.96875 L 108.855469 60.398438 L 109.121094 60.832031 L 109.390625 61.265625 L 109.929688 62.140625 L 110.46875 63.023438 L 110.734375 63.472656 L 111.003906 63.917969 L 111.8125 65.277344 L 112.082031 65.738281 L 112.347656 66.199219 L 112.617188 66.660156 L 112.886719 67.125 L 113.425781 68.0625 L 113.695312 68.535156 L 113.960938 69.011719 L 114.230469 69.488281 L 114.769531 70.449219 L 115.039062 70.933594 L 115.308594 71.421875 L 115.574219 71.910156 L 116.113281 72.894531 L 116.382812 73.390625 L 116.921875 74.390625 L 117.1875 74.894531 L 117.726562 75.910156 L 118.265625 76.933594 L 118.53125 77.449219 L 119.070312 78.488281 L 119.339844 79.011719 L 119.878906 80.066406 L 120.144531 80.59375 L 120.953125 82.199219 L 121.222656 82.738281 L 121.492188 83.28125 L 121.757812 83.828125 L 122.296875 84.921875 L 122.566406 85.472656 L 122.835938 86.027344 L 123.105469 86.585938 L 123.371094 87.144531 L 123.910156 88.269531 L 124.449219 89.402344 L 124.71875 89.976562 L 124.984375 90.546875 L 125.523438 91.703125 L 126.0625 92.867188 L 126.332031 93.453125 L 126.597656 94.039062 L 126.867188 94.628906 L 127.40625 95.816406 L 127.675781 96.414062 L 127.945312 97.015625 L 128.210938 97.613281 L 128.75 98.800781 L 129.019531 99.390625 L 129.558594 100.5625 L 129.824219 101.144531 L 130.09375 101.726562 L 130.363281 102.304688 L 130.902344 103.453125 L 131.171875 104.023438 L 131.4375 104.59375 L 131.707031 105.160156 L 132.246094 106.285156 L 132.515625 106.84375 L 132.78125 107.398438 L 133.320312 108.507812 L 134.128906 110.148438 L 134.394531 110.6875 L 134.664062 111.230469 L 135.203125 112.300781 L 135.742188 113.363281 L 136.007812 113.890625 L 136.277344 114.417969 L 136.546875 114.941406 L 137.085938 115.980469 L 137.355469 116.496094 L 137.621094 117.007812 L 137.890625 117.519531 L 138.160156 118.027344 L 138.96875 119.539062 L 139.234375 120.035156 L 139.503906 120.535156 L 140.042969 121.519531 L 140.582031 122.496094 L 140.847656 122.980469 L 141.386719 123.941406 L 141.925781 124.894531 L 142.195312 125.367188 L 142.460938 125.835938 L 142.730469 126.304688 L 143 126.769531 L 143.539062 127.691406 L 143.808594 128.148438 L 144.074219 128.605469 L 144.34375 129.058594 L 144.882812 129.957031 L 145.421875 130.847656 L 145.6875 131.289062 L 146.226562 132.164062 L 146.496094 132.597656 L 146.765625 133.027344 L 147.03125 133.457031 L 147.300781 133.886719 L 148.109375 135.152344 L 148.378906 135.566406 L 148.644531 135.984375 L 149.183594 136.804688 L 149.722656 137.617188 L 149.992188 138.019531 L 150.257812 138.421875 L 150.527344 138.820312 L 150.796875 139.214844 L 151.605469 140.386719 L 151.871094 140.773438 L 152.140625 141.15625 L 152.949219 142.292969 L 153.21875 142.664062 L 153.484375 143.035156 L 153.753906 143.40625 L 154.023438 143.773438 L 154.5625 144.5 L 154.832031 144.859375 L 155.097656 145.214844 L 155.367188 145.570312 L 155.90625 146.273438 L 156.175781 146.617188 L 156.445312 146.964844 L 156.710938 147.304688 L 156.980469 147.648438 L 157.519531 148.320312 L 158.058594 148.984375 L 158.324219 149.3125 L 158.863281 149.960938 L 159.402344 150.601562 L 159.671875 150.917969 L 159.9375 151.230469 L 160.207031 151.542969 L 160.476562 151.851562 L 161.015625 152.460938 L 161.28125 152.761719 L 161.550781 153.0625 L 161.820312 153.359375 L 162.359375 153.945312 L 162.628906 154.234375 L 162.894531 154.523438 L 163.164062 154.808594 L 163.703125 155.371094 L 163.972656 155.648438 L 164.242188 155.921875 L 164.507812 156.195312 L 165.046875 156.734375 L 165.316406 157 L 165.855469 157.523438 L 166.121094 157.78125 L 166.390625 158.039062 L 166.660156 158.292969 L 167.199219 158.792969 L 167.46875 159.039062 L 167.734375 159.28125 L 168.273438 159.765625 L 169.082031 160.46875 L 169.347656 160.695312 L 169.617188 160.925781 L 170.15625 161.371094 L 170.695312 161.808594 L 170.960938 162.023438 L 171.230469 162.238281 L 171.5 162.445312 L 171.769531 162.65625 L 172.308594 163.0625 L 172.574219 163.265625 L 172.84375 163.464844 L 173.113281 163.660156 L 173.652344 164.042969 L 173.921875 164.230469 L 174.1875 164.417969 L 174.726562 164.785156 L 174.996094 164.964844 L 175.265625 165.140625 L 175.535156 165.3125 L 175.800781 165.484375 L 176.070312 165.65625 L 176.339844 165.824219 L 176.609375 165.988281 L 176.878906 166.148438 L 177.144531 166.308594 L 177.414062 166.46875 L 178.222656 166.925781 L 178.492188 167.074219 L 178.757812 167.21875 L 179.027344 167.363281 L 179.296875 167.503906 L 179.835938 167.777344 L 180.105469 167.910156 L 180.371094 168.039062 L 180.910156 168.296875 L 181.71875 168.660156 L 181.984375 168.777344 L 182.523438 169.003906 L 182.792969 169.113281 L 183.332031 169.324219 L 183.597656 169.425781 L 184.40625 169.71875 L 184.945312 169.898438 L 185.210938 169.988281 L 185.480469 170.074219 L 186.019531 170.238281 L 186.289062 170.316406 L 186.558594 170.390625 L 186.824219 170.464844 L 187.09375 170.535156 L 187.902344 170.734375 L 188.171875 170.792969 L 188.4375 170.851562 L 188.707031 170.910156 L 188.976562 170.964844 L 189.515625 171.066406 L 189.785156 171.113281 L 190.050781 171.15625 L 190.320312 171.199219 L 190.859375 171.277344 L 191.128906 171.308594 L 191.394531 171.34375 L 191.664062 171.371094 L 191.933594 171.402344 L 192.472656 171.449219 L 192.742188 171.46875 L 193.007812 171.488281 L 193.277344 171.503906 L 193.816406 171.527344 L 194.355469 171.542969 L 194.621094 171.542969 L 194.890625 171.546875 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="174.984375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="174.984375"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="174.984375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="137.566406"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="137.566406"/>
+ <use xlink:href="#glyph0-3" x="36.25885" y="137.566406"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="137.566406"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="100.152344"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="100.152344"/>
+ <use xlink:href="#glyph0-4" x="36.25885" y="100.152344"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="100.152344"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="28.257812" y="62.734375"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="62.734375"/>
+ <use xlink:href="#glyph0-5" x="36.25885" y="62.734375"/>
+ <use xlink:href="#glyph0-4" x="41.594437" y="62.734375"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="28.257812" y="25.320312"/>
+ <use xlink:href="#glyph0-2" x="33.593399" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="36.25885" y="25.320312"/>
+ <use xlink:href="#glyph0-1" x="41.594437" y="25.320312"/>
+</g>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 171.546875 L 54.019531 171.546875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 134.128906 L 54.019531 134.128906 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 96.714844 L 54.019531 96.714844 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 59.296875 L 54.019531 59.296875 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 49.765625 21.882812 L 54.019531 21.882812 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 60.726562 183.28125 L 60.726562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 94.269531 183.28125 L 94.269531 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 127.808594 183.28125 L 127.808594 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 161.351562 183.28125 L 161.351562 179.027344 "/>
+<path style="fill:none;stroke-width:1.062992;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(49.803922%,49.803922%,49.803922%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.890625 183.28125 L 194.890625 179.027344 "/>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="51.390625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="56.726212" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="59.391663" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="64.727249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="84.933594" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="90.26918" y="192.992188"/>
+ <use xlink:href="#glyph0-3" x="92.934631" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="98.270218" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="118.472656" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="123.808243" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="126.473694" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="131.80928" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-1" x="152.015625" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="157.351212" y="192.992188"/>
+ <use xlink:href="#glyph0-5" x="160.016663" y="192.992188"/>
+ <use xlink:href="#glyph0-4" x="165.352249" y="192.992188"/>
+</g>
+<g style="fill:rgb(49.803922%,49.803922%,49.803922%);fill-opacity:1;">
+ <use xlink:href="#glyph0-6" x="185.554688" y="192.992188"/>
+ <use xlink:href="#glyph0-2" x="190.890274" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="193.555725" y="192.992188"/>
+ <use xlink:href="#glyph0-1" x="198.891312" y="192.992188"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph1-1" x="124.808594" y="205.199219"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph2-1" x="21.660156" y="108.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-1" x="21.660156" y="101.210938"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph4-1" x="21.660156" y="96.214844"/>
+</g>
+<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
+ <use xlink:href="#glyph3-2" x="21.660156" y="90.214844"/>
+</g>
+</g>
+</svg>
diff --git a/documentation/ui/footer.html b/documentation/ui/footer.html
new file mode 100644
index 0000000..2a56075
--- /dev/null
+++ b/documentation/ui/footer.html
@@ -0,0 +1,22 @@
+<!-- HTML footer for doxygen 1.8.11-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+ <ul>
+ $navpath
+ <li>Copyright © 2010-2017 FuzzyLite Limited. All rights reserved.</li>
+ <li class="footer">$generatedby
+ <a href="http://www.doxygen.org/index.html">
+ <img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+ </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby &#160;<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/documentation/ui/header.html b/documentation/ui/header.html
new file mode 100644
index 0000000..a8b2bb9
--- /dev/null
+++ b/documentation/ui/header.html
@@ -0,0 +1,77 @@
+<!-- HTML header for doxygen 1.8.11-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+
+<link rel="apple-touch-icon" sizes="57x57" href="$relpath^apple-touch-icon-57x57.png">
+<link rel="apple-touch-icon" sizes="60x60" href="$relpath^apple-touch-icon-60x60.png">
+<link rel="apple-touch-icon" sizes="72x72" href="$relpath^apple-touch-icon-72x72.png">
+<link rel="apple-touch-icon" sizes="76x76" href="$relpath^apple-touch-icon-76x76.png">
+<link rel="apple-touch-icon" sizes="114x114" href="$relpath^apple-touch-icon-114x114.png">
+<link rel="apple-touch-icon" sizes="120x120" href="$relpath^apple-touch-icon-120x120.png">
+<link rel="apple-touch-icon" sizes="144x144" href="$relpath^apple-touch-icon-144x144.png">
+<link rel="apple-touch-icon" sizes="152x152" href="$relpath^apple-touch-icon-152x152.png">
+<link rel="apple-touch-icon" sizes="180x180" href="$relpath^apple-touch-icon-180x180.png">
+<link rel="icon" type="image/png" href="$relpath^favicon-32x32.png" sizes="32x32">
+<link rel="icon" type="image/png" href="$relpath^android-chrome-192x192.png" sizes="192x192">
+<link rel="icon" type="image/png" href="$relpath^favicon-96x96.png" sizes="96x96">
+<link rel="icon" type="image/png" href="$relpath^favicon-16x16.png" sizes="16x16">
+<link rel="manifest" href="$relpath^manifest.json">
+<link rel="mask-icon" href="$relpath^safari-pinned-tab.svg" color="#00d200">
+<meta name="msapplication-TileColor" content="#da532c">
+<meta name="msapplication-TileImage" content="$relpath^mstile-144x144.png">
+<meta name="theme-color" content="#ffffff">
+<link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" />
+
+
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <!--BEGIN PROJECT_LOGO-->
+ <td id="projectlogo"><a href="http://www.fuzzylite.com/" title="http://www.fuzzylite.com" target="_blank"><img src="$relpath^$projectlogo"/></a></td>
+ <!--END PROJECT_LOGO-->
+ <!--BEGIN PROJECT_NAME-->
+ <td id="projectalign" style="padding-left: 0.5em;">
+ <div id="projectname">$projectname
+ <!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+ </div>
+ <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+ </td>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectbrief">$projectbrief</div>
+ </td>
+ <!--END PROJECT_BRIEF-->
+ <!--END !PROJECT_NAME-->
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/documentation/ui/image/android-chrome-144x144.png b/documentation/ui/image/android-chrome-144x144.png
new file mode 100644
index 0000000..13a60a8
--- /dev/null
+++ b/documentation/ui/image/android-chrome-144x144.png
Binary files differ
diff --git a/documentation/ui/image/android-chrome-192x192.png b/documentation/ui/image/android-chrome-192x192.png
new file mode 100644
index 0000000..8507762
--- /dev/null
+++ b/documentation/ui/image/android-chrome-192x192.png
Binary files differ
diff --git a/documentation/ui/image/android-chrome-36x36.png b/documentation/ui/image/android-chrome-36x36.png
new file mode 100644
index 0000000..ad8e7d1
--- /dev/null
+++ b/documentation/ui/image/android-chrome-36x36.png
Binary files differ
diff --git a/documentation/ui/image/android-chrome-48x48.png b/documentation/ui/image/android-chrome-48x48.png
new file mode 100644
index 0000000..94b2dfe
--- /dev/null
+++ b/documentation/ui/image/android-chrome-48x48.png
Binary files differ
diff --git a/documentation/ui/image/android-chrome-72x72.png b/documentation/ui/image/android-chrome-72x72.png
new file mode 100644
index 0000000..8f90b01
--- /dev/null
+++ b/documentation/ui/image/android-chrome-72x72.png
Binary files differ
diff --git a/documentation/ui/image/android-chrome-96x96.png b/documentation/ui/image/android-chrome-96x96.png
new file mode 100644
index 0000000..7b29762
--- /dev/null
+++ b/documentation/ui/image/android-chrome-96x96.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-114x114.png b/documentation/ui/image/apple-touch-icon-114x114.png
new file mode 100644
index 0000000..0b70f67
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-114x114.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-120x120.png b/documentation/ui/image/apple-touch-icon-120x120.png
new file mode 100644
index 0000000..b43d10e
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-120x120.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-144x144.png b/documentation/ui/image/apple-touch-icon-144x144.png
new file mode 100644
index 0000000..07a81e6
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-144x144.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-152x152.png b/documentation/ui/image/apple-touch-icon-152x152.png
new file mode 100644
index 0000000..7900187
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-152x152.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-180x180.png b/documentation/ui/image/apple-touch-icon-180x180.png
new file mode 100644
index 0000000..3d9e74f
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-180x180.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-57x57.png b/documentation/ui/image/apple-touch-icon-57x57.png
new file mode 100644
index 0000000..cf40432
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-57x57.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-60x60.png b/documentation/ui/image/apple-touch-icon-60x60.png
new file mode 100644
index 0000000..2f208d1
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-60x60.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-72x72.png b/documentation/ui/image/apple-touch-icon-72x72.png
new file mode 100644
index 0000000..2e8f273
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-72x72.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-76x76.png b/documentation/ui/image/apple-touch-icon-76x76.png
new file mode 100644
index 0000000..a10c74f
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-76x76.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon-precomposed.png b/documentation/ui/image/apple-touch-icon-precomposed.png
new file mode 100644
index 0000000..9cdd1f0
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon-precomposed.png
Binary files differ
diff --git a/documentation/ui/image/apple-touch-icon.png b/documentation/ui/image/apple-touch-icon.png
new file mode 100644
index 0000000..3d9e74f
--- /dev/null
+++ b/documentation/ui/image/apple-touch-icon.png
Binary files differ
diff --git a/documentation/ui/image/browserconfig.xml b/documentation/ui/image/browserconfig.xml
new file mode 100644
index 0000000..65380f3
--- /dev/null
+++ b/documentation/ui/image/browserconfig.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<browserconfig>
+ <msapplication>
+ <tile>
+ <square70x70logo src="/mstile-70x70.png"/>
+ <square150x150logo src="/mstile-150x150.png"/>
+ <square310x310logo src="/mstile-310x310.png"/>
+ <wide310x150logo src="/mstile-310x150.png"/>
+ <TileColor>#da532c</TileColor>
+ </tile>
+ </msapplication>
+</browserconfig>
diff --git a/documentation/ui/image/favicon-16x16.png b/documentation/ui/image/favicon-16x16.png
new file mode 100644
index 0000000..3e95d61
--- /dev/null
+++ b/documentation/ui/image/favicon-16x16.png
Binary files differ
diff --git a/documentation/ui/image/favicon-32x32.png b/documentation/ui/image/favicon-32x32.png
new file mode 100644
index 0000000..d7db569
--- /dev/null
+++ b/documentation/ui/image/favicon-32x32.png
Binary files differ
diff --git a/documentation/ui/image/favicon-96x96.png b/documentation/ui/image/favicon-96x96.png
new file mode 100644
index 0000000..7b29762
--- /dev/null
+++ b/documentation/ui/image/favicon-96x96.png
Binary files differ
diff --git a/documentation/ui/image/favicon.ico b/documentation/ui/image/favicon.ico
new file mode 100644
index 0000000..c2e7915
--- /dev/null
+++ b/documentation/ui/image/favicon.ico
Binary files differ
diff --git a/documentation/ui/image/manifest.json b/documentation/ui/image/manifest.json
new file mode 100644
index 0000000..b595012
--- /dev/null
+++ b/documentation/ui/image/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "fuzzylite",
+ "icons": [
+ {
+ "src": "\/android-chrome-36x36.png",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/android-chrome-48x48.png",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/android-chrome-72x72.png",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/android-chrome-96x96.png",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/android-chrome-144x144.png",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ]
+}
diff --git a/documentation/ui/image/mstile-144x144.png b/documentation/ui/image/mstile-144x144.png
new file mode 100644
index 0000000..fcba19e
--- /dev/null
+++ b/documentation/ui/image/mstile-144x144.png
Binary files differ
diff --git a/documentation/ui/image/mstile-150x150.png b/documentation/ui/image/mstile-150x150.png
new file mode 100644
index 0000000..6748bc1
--- /dev/null
+++ b/documentation/ui/image/mstile-150x150.png
Binary files differ
diff --git a/documentation/ui/image/mstile-310x150.png b/documentation/ui/image/mstile-310x150.png
new file mode 100644
index 0000000..29c3eaa
--- /dev/null
+++ b/documentation/ui/image/mstile-310x150.png
Binary files differ
diff --git a/documentation/ui/image/mstile-310x310.png b/documentation/ui/image/mstile-310x310.png
new file mode 100644
index 0000000..16aa141
--- /dev/null
+++ b/documentation/ui/image/mstile-310x310.png
Binary files differ
diff --git a/documentation/ui/image/mstile-70x70.png b/documentation/ui/image/mstile-70x70.png
new file mode 100644
index 0000000..6531179
--- /dev/null
+++ b/documentation/ui/image/mstile-70x70.png
Binary files differ
diff --git a/documentation/ui/image/safari-pinned-tab.svg b/documentation/ui/image/safari-pinned-tab.svg
new file mode 100644
index 0000000..6f4db51
--- /dev/null
+++ b/documentation/ui/image/safari-pinned-tab.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
+ width="72.000000pt" height="73.000000pt" viewBox="0 0 72.000000 73.000000"
+ preserveAspectRatio="xMidYMid meet">
+<metadata>
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+</metadata>
+<g transform="translate(0.000000,73.000000) scale(0.100000,-0.100000)"
+fill="#000000" stroke="none">
+<path d="M69 713 c-16 -6 -38 -27 -49 -45 -19 -31 -20 -50 -20 -301 0 -382
+-25 -357 357 -357 248 0 270 2 300 20 17 10 37 28 43 40 8 14 11 111 11 296 0
+382 27 354 -347 357 -188 1 -275 -2 -295 -10z m561 -28 c56 -29 60 -50 60
+-313 0 -145 -4 -251 -11 -270 -22 -63 -38 -67 -299 -70 -260 -4 -298 2 -334
+51 -20 27 -21 40 -21 281 0 279 3 298 60 322 47 20 506 19 545 -1z"/>
+<path d="M477 633 c-3 -4 -13 -37 -22 -73 -9 -36 -21 -83 -27 -105 l-11 -40
+-17 65 c-34 128 -41 150 -48 150 -5 0 -19 -44 -31 -97 -13 -54 -27 -104 -31
+-112 -4 -8 -18 32 -35 98 -15 62 -31 109 -35 104 -7 -8 -130 -493 -130 -513 0
+-6 93 -10 265 -10 246 0 265 1 265 18 0 20 -126 511 -133 518 -3 3 -7 2 -10
+-3z m-223 -151 l27 -107 -34 -130 -34 -130 -57 -3 c-52 -3 -57 -1 -52 15 3 10
+26 101 51 203 59 237 65 260 69 260 2 0 16 -48 30 -108z m146 -114 c0 -50 -9
+-58 -61 -58 -27 0 -49 2 -49 5 0 3 14 63 32 133 l32 127 23 -90 c12 -49 23
+-102 23 -117z m129 25 c5 -21 23 -91 39 -155 l30 -118 -179 0 c-98 0 -179 3
+-179 8 0 4 8 39 18 77 l18 70 62 3 c70 3 73 6 92 95 l13 57 38 0 c36 0 39 -2
+48 -37z"/>
+</g>
+</svg>
diff --git a/documentation/ui/stylesheet.css b/documentation/ui/stylesheet.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/documentation/ui/stylesheet.css
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..6525a9a
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,13 @@
+Disclaimer
+==========
+
+The following folders contain examples from Matlab and Octave distributions. The examples are presented in the following formats: fuzzylite v5.0 `.cpp`, jfuzzylite v5.0 `.java`, FuzzyLite Language `.fll`, FuzzyLite Dataset `.fld`, Fuzzy Inference System `.fis`, and Fuzzy Controller Language `.fcl`. The formats were created automatically utilizing the `[Cpp|Java|Fll|Fld|Fis|Fcl]Exporter`.
+
+The original files from Matlab and Octave distributions are contained within the folder `original`, although the following files from Matlab were modified to remove the fourth parameter of the term `gbellmf`, which is not required for its configuration.
+
++ [`examples/original/mamdani/matlab/mam21.fis`](/examples/original/mamdani/matlab/mam21.fis)
+
++ [`examples/original/mamdani/matlab/mam22.fis`](/examples/original/mamdani/matlab/mam22.fis)
+
+In addition to the original examples, the examples are presented in the FuzzyLite Language to include scalar values with at least the same number of decimal places, and a proper configuration in the cases of Takagi-Sugeno controllers (i.e., `RuleBlock::activation = none` and `OutputVariable::accumulation = none`) to satisfy the regular operation of the controllers in `fuzzylite` v5.0.
+
diff --git a/examples/application/CMakeLists.txt b/examples/application/CMakeLists.txt
new file mode 100644
index 0000000..3ec0869
--- /dev/null
+++ b/examples/application/CMakeLists.txt
@@ -0,0 +1,140 @@
+cmake_minimum_required(VERSION 2.8.8)
+
+project(FuzzyLiteDemo CXX)
+
+#Some default policies and variables
+if (APPLE)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+if (MSVC)
+ cmake_policy(SET CMP0054 NEW)
+endif()
+
+if(NOT CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_VERBOSE_MAKEFILE false)
+endif()
+
+if( NOT CMAKE_BUILD_TYPE )
+ set( CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo
+MinSizeRel." FORCE )
+endif()
+
+option(FL_BACKTRACE "Provide backtrace information in case of errors" ON)
+option(FL_STATIC "Statically link to fuzzylite libraries" ON)
+
+set(BacktraceLibrary)
+
+if (MSVC AND FL_BACKTRACE)
+ set(BacktraceLibrary dbghelp)
+endif()
+
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+ set(FL_DEBUG ON)
+else()
+ set(FL_DEBUG OFF)
+endif()
+
+
+set(FL_SYSTEM_LIBRARY FALSE) #Finds the library installed in the system
+set(FL_LIBRARY_DIR)
+
+if (NOT FL_SYSTEM_LIBRARY)
+ #it is possible to find the FuzzyLiteLibrary locally as follows,
+ #assuming the submodule of fuzzylite is added to the ${PROJECT_SOURCE_DIR}:
+ set(FL_HOME ${PROJECT_SOURCE_DIR}/../../fuzzylite/)
+ set(FL_INCLUDE_DIR ${FL_HOME})
+ if (FL_DEBUG)
+ set(FL_LIBRARY_DIR ${FL_HOME}/debug/bin)
+ else()
+ set(FL_LIBRARY_DIR ${FL_HOME}/release/bin)
+ endif()
+ message("Finding FuzzyLiteLibrary locally at ${FL_LIBRARY_DIR}")
+
+ include_directories(${FL_INCLUDE_DIR})
+endif()
+
+set(FL_POSTFIX)
+if (FL_STATIC)
+ set(FL_POSTFIX "-static")
+endif()
+if (FL_DEBUG)
+ set(FL_POSTFIX "${FL_POSTFIX}-debug")
+endif()
+
+set(FL_LIBRARY_NAME fuzzylite${FL_POSTFIX})
+find_library (FuzzyLiteLibrary ${FL_LIBRARY_NAME} HINTS ${FL_LIBRARY_DIR})
+
+if (MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19)
+#C++11 not available before Visual Studio 2015
+ if (NOT FL_CPP98)
+ set(FL_CPP98 ON)
+ endif()
+endif()
+
+
+#if building using C++98
+if(FL_CPP98)
+ add_definitions(-DFL_CPP98)
+ if(NOT MSVC)
+ #Set C++98 by default in Clang and others
+ add_definitions(-std=c++98)
+ endif()
+else()
+ if(NOT MSVC)
+ #Set C++11 by default in Clang and others
+ add_definitions(-std=c++11)
+ endif()
+endif(FL_CPP98)
+
+#we add the definition of the building path to remove it when using macro FL_LOG
+add_definitions(-DFL_BUILD_PATH="${CMAKE_SOURCE_DIR}") #used to determine
+#we add the sources
+set(sources src/main.cpp)
+
+
+
+if(MSVC)
+#Set compilation flags in Windows
+ set(CMAKE_CXX_FLAGS "/W4 /EHsc")
+ #Wx: Treat warnings as errors. W4: All warnings
+ #http://msdn.microsoft.com/en-us/library/thxezb7y.aspx
+ #EHsc: call destructors on __try __catch, and to ignore C4530: C++ exception handler used. Note, unwind semantics are not enabled
+endif()
+
+
+#we create the binary
+add_executable(binary ${sources})
+if (NOT FL_STATIC)
+ target_compile_definitions(binary PRIVATE FL_IMPORT_LIBRARY)
+endif()
+#linking the fuzzylite library
+target_link_libraries (binary ${FuzzyLiteLibrary} ${BacktraceLibrary})
+#setting the name of the product
+set_target_properties(binary PROPERTIES OUTPUT_NAME FuzzyLiteDemo)
+#specially for windows
+set_target_properties(binary PROPERTIES OUTPUT_NAME FuzzyLiteDemo IMPORT_PREFIX tmp-) #To prevent LNK1149 in Windows
+#in case of building on debug mode
+set_target_properties(binary PROPERTIES DEBUG_POSTFIX d)
+
+
+
+message("=====================================")
+message("FuzzyLite Demo v6.0\n")
+message("FL_HOME=${FL_HOME}")
+message("FL_LIBRARY_NAME=${FL_LIBRARY_NAME}")
+message("FuzzyLiteLibrary=${FuzzyLiteLibrary}")
+message("")
+message("FL_BACKTRACE=${FL_BACKTRACE}")
+message("FL_STATIC=${FL_STATIC}")
+message("FL_DEBUG=${FL_DEBUG}")
+message("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
+message("CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}")
+message("CMAKE_CXX_COMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION}")
+message("CMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}")
+message("COMPILE_DEFINITIONS:")
+get_directory_property(fl-definitions DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS )
+foreach(d ${fl-definitions})
+ message( STATUS "Defined: " ${d} )
+endforeach()
+message("=====================================\n")
+
diff --git a/examples/application/clean.sh b/examples/application/clean.sh
new file mode 100755
index 0000000..4f4bc9c
--- /dev/null
+++ b/examples/application/clean.sh
@@ -0,0 +1 @@
+rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake FuzzyLiteDemo \ No newline at end of file
diff --git a/examples/application/compile.bat b/examples/application/compile.bat
new file mode 100644
index 0000000..8baf5a3
--- /dev/null
+++ b/examples/application/compile.bat
@@ -0,0 +1,24 @@
+FL_HOME="../../fuzzylite/"
+
+rem Static Linking
+rem --------------
+rem For C++11
+cl.exe src/main.cpp %FL_HOME%/release/bin/fuzzylite-static.lib /I%FL_HOME% /EHsc /MD
+
+rem For C++98
+cl.exe src/main.cpp %FL_HOME%/release/bin/fuzzylite-static.lib /I%FL_HOME% /DFL_CPP98=ON /EHsc /MD
+
+
+rem Dynamic Linking
+rem ---------------
+rem For C++11
+rem For C++11
+cl.exe src/main.cpp %FL_HOME%/release/bin/fuzzylite-static.lib /I%FL_HOME% /DFL_IMPORT_LIBRARY /EHsc /MD
+
+rem For C++98
+cl.exe src/main.cpp %FL_HOME%/release/bin/fuzzylite-static.lib /I%FL_HOME% /DFL_CPP98=ON /DFL_IMPORT_LIBRARY /EHsc /MD
+
+rem Note: when using dynamic linking, the path to fuzzylite libraries must be specified. For example, run from console the following:
+
+set PATH="%FL_HOME%\release\bin;%PATH%"
+example-dynamic-11.exe
diff --git a/examples/application/compile.sh b/examples/application/compile.sh
new file mode 100755
index 0000000..1ea1aa4
--- /dev/null
+++ b/examples/application/compile.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+FL_HOME="../../fuzzylite/"
+
+#Static Linking
+#--------------
+#For C++11
+g++ src/main.cpp -oexample-static-11 -I$FL_HOME -L$FL_HOME/release/bin -lfuzzylite-static -std=c++11
+
+#For C++98
+g++ src/main.cpp -oexample-static-98 -I$FL_HOME -L$FL_HOME/release/bin -lfuzzylite-static -DFL_CPP98=ON -Wno-non-literal-null-conversion
+
+
+#Dynamic Linking
+#---------------
+#For C++11
+g++ src/main.cpp -oexample-dynamic-11 -I$FL_HOME -L$FL_HOME/release/bin -lfuzzylite -std=c++11
+
+#For C++98
+g++ src/main.cpp -oexample-dynamic-98 -I$FL_HOME -L$FL_HOME/release/bin -lfuzzylite -DFL_CPP98=ON -Wno-non-literal-null-conversion
+
+#Note: when using dynamic linking, the path to fuzzylite libraries must be specified. For example, run from console the following:
+
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$FL_HOME/release/bin;
+./example-dynamic-11
diff --git a/examples/application/src/main.cpp b/examples/application/src/main.cpp
new file mode 100644
index 0000000..d547b72
--- /dev/null
+++ b/examples/application/src/main.cpp
@@ -0,0 +1,16 @@
+
+#include "fl/Headers.h"
+
+int main(int argc, char** argv){
+ FL_IUNUSED(argc);
+ FL_IUNUSED(argv);
+
+ using namespace fl;
+
+ Engine* hybrid = Console::hybrid();
+ FL_LOG("Hybrid Demo: FuzzyLite Dataset");
+ FL_LOG("===============================");
+ FL_LOG(FldExporter().toString(hybrid));
+ delete hybrid;
+
+} \ No newline at end of file
diff --git a/examples/examples.R b/examples/examples.R
new file mode 100644
index 0000000..7b905bf
--- /dev/null
+++ b/examples/examples.R
@@ -0,0 +1,16 @@
+directories = c("mamdani/", "mamdani/matlab/", "mamdani/octave/", "takagi-sugeno/", "takagi-sugeno/matlab/", "takagi-sugeno/octave/", "tsukamoto/", "hybrid")
+baseDirectory = getwd()
+
+for (directory in directories){
+ message("Processing directory: ", directory)
+ setwd(directory)
+ rScripts = list.files(".", pattern = ".R$")
+ for (i in seq(1, length(rScripts))){
+ rScript = rScripts[i]
+ message(sprintf("\tProcessing file %i/%i: %s", i, length(rScripts), rScript))
+ scriptEnvironment = new.env()
+ sys.source(rScript, scriptEnvironment)
+ rm(scriptEnvironment)
+ }
+ setwd(baseDirectory)
+}
diff --git a/examples/hybrid/ObstacleAvoidance.R b/examples/hybrid/ObstacleAvoidance.R
new file mode 100644
index 0000000..5a94543
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.R
@@ -0,0 +1,86 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "ObstacleAvoidance"
+engine.fll = "Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: mSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: tsSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: left Constant 0.333
+ term: right Constant 0.666
+RuleBlock: mamdani
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: AlgebraicProduct
+ activation: General
+ rule: if obstacle is left then mSteer is right
+ rule: if obstacle is right then mSteer is left
+RuleBlock: takagiSugeno
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if obstacle is left then tsSteer is right
+ rule: if obstacle is right then tsSteer is left"
+
+engine.fldFile = "ObstacleAvoidance.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(obstacle, mSteer)) +
+ geom_line(aes(color=mSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("obstacle vs mSteer")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(obstacle, mSteer)) +
+ geom_line(aes(color=mSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("mSteer vs obstacle")
+
+engine.plot.i1_o2 = ggplot(engine.df, aes(obstacle, tsSteer)) +
+ geom_line(aes(color=tsSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("obstacle vs tsSteer")
+
+engine.plot.o2_i1 = ggplot(engine.df, aes(obstacle, tsSteer)) +
+ geom_line(aes(color=tsSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("tsSteer vs obstacle")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, engine.plot.i1_o2, engine.plot.o2_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/hybrid/ObstacleAvoidance.cpp b/examples/hybrid/ObstacleAvoidance.cpp
new file mode 100644
index 0000000..a5e42e1
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.cpp
@@ -0,0 +1,75 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("ObstacleAvoidance");
+engine->setDescription("");
+
+InputVariable* obstacle = new InputVariable;
+obstacle->setName("obstacle");
+obstacle->setDescription("");
+obstacle->setEnabled(true);
+obstacle->setRange(0.000, 1.000);
+obstacle->setLockValueInRange(false);
+obstacle->addTerm(new Ramp("left", 1.000, 0.000));
+obstacle->addTerm(new Ramp("right", 0.000, 1.000));
+engine->addInputVariable(obstacle);
+
+OutputVariable* mSteer = new OutputVariable;
+mSteer->setName("mSteer");
+mSteer->setDescription("");
+mSteer->setEnabled(true);
+mSteer->setRange(0.000, 1.000);
+mSteer->setLockValueInRange(false);
+mSteer->setAggregation(new Maximum);
+mSteer->setDefuzzifier(new Centroid(100));
+mSteer->setDefaultValue(fl::nan);
+mSteer->setLockPreviousValue(false);
+mSteer->addTerm(new Ramp("left", 1.000, 0.000));
+mSteer->addTerm(new Ramp("right", 0.000, 1.000));
+engine->addOutputVariable(mSteer);
+
+OutputVariable* tsSteer = new OutputVariable;
+tsSteer->setName("tsSteer");
+tsSteer->setDescription("");
+tsSteer->setEnabled(true);
+tsSteer->setRange(0.000, 1.000);
+tsSteer->setLockValueInRange(false);
+tsSteer->setAggregation(new Maximum);
+tsSteer->setDefuzzifier(new WeightedAverage("Automatic"));
+tsSteer->setDefaultValue(fl::nan);
+tsSteer->setLockPreviousValue(false);
+tsSteer->addTerm(new Constant("left", 0.333));
+tsSteer->addTerm(new Constant("right", 0.666));
+engine->addOutputVariable(tsSteer);
+
+RuleBlock* mamdani = new RuleBlock;
+mamdani->setName("mamdani");
+mamdani->setDescription("");
+mamdani->setEnabled(true);
+mamdani->setConjunction(fl::null);
+mamdani->setDisjunction(fl::null);
+mamdani->setImplication(new AlgebraicProduct);
+mamdani->setActivation(new General);
+mamdani->addRule(Rule::parse("if obstacle is left then mSteer is right", engine));
+mamdani->addRule(Rule::parse("if obstacle is right then mSteer is left", engine));
+engine->addRuleBlock(mamdani);
+
+RuleBlock* takagiSugeno = new RuleBlock;
+takagiSugeno->setName("takagiSugeno");
+takagiSugeno->setDescription("");
+takagiSugeno->setEnabled(true);
+takagiSugeno->setConjunction(fl::null);
+takagiSugeno->setDisjunction(fl::null);
+takagiSugeno->setImplication(fl::null);
+takagiSugeno->setActivation(new General);
+takagiSugeno->addRule(Rule::parse("if obstacle is left then tsSteer is right", engine));
+takagiSugeno->addRule(Rule::parse("if obstacle is right then tsSteer is left", engine));
+engine->addRuleBlock(takagiSugeno);
+
+
+}
diff --git a/examples/hybrid/ObstacleAvoidance.fcl b/examples/hybrid/ObstacleAvoidance.fcl
new file mode 100644
index 0000000..81a30a7
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.fcl
@@ -0,0 +1,49 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK ObstacleAvoidance
+
+VAR_INPUT
+ obstacle: REAL;
+END_VAR
+
+VAR_OUTPUT
+ mSteer: REAL;
+ tsSteer: REAL;
+END_VAR
+
+FUZZIFY obstacle
+ RANGE := (0.000 .. 1.000);
+ TERM left := Ramp 1.000 0.000;
+ TERM right := Ramp 0.000 1.000;
+END_FUZZIFY
+
+DEFUZZIFY mSteer
+ RANGE := (0.000 .. 1.000);
+ TERM left := Ramp 1.000 0.000;
+ TERM right := Ramp 0.000 1.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY tsSteer
+ RANGE := (0.000 .. 1.000);
+ TERM left := 0.333;
+ TERM right := 0.666;
+ METHOD : COGS;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK mamdani
+ ACT : PROD;
+ RULE 1 : if obstacle is left then mSteer is right
+ RULE 2 : if obstacle is right then mSteer is left
+END_RULEBLOCK
+
+RULEBLOCK takagiSugeno
+ RULE 1 : if obstacle is left then tsSteer is right
+ RULE 2 : if obstacle is right then tsSteer is left
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/hybrid/ObstacleAvoidance.fis b/examples/hybrid/ObstacleAvoidance.fis
new file mode 100644
index 0000000..1bf0476
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.fis
@@ -0,0 +1,43 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='ObstacleAvoidance'
+Type='hybrid'
+Version=6.0
+NumInputs=1
+NumOutputs=2
+NumRules=4
+AndMethod='min'
+OrMethod='max'
+ImpMethod='prod'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='obstacle'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'rampmf',[1.000 0.000]
+MF2='right':'rampmf',[0.000 1.000]
+
+[Output1]
+Name='mSteer'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'rampmf',[1.000 0.000]
+MF2='right':'rampmf',[0.000 1.000]
+
+[Output2]
+Name='tsSteer'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'constant',[0.333]
+MF2='right':'constant',[0.666]
+
+[Rules]
+# RuleBlock mamdani
+1.000 , 2.000 0.000 (1.000) : 1
+2.000 , 1.000 0.000 (1.000) : 1
+# RuleBlock takagiSugeno
+1.000 , 0.000 2.000 (1.000) : 1
+2.000 , 0.000 1.000 (1.000) : 1
diff --git a/examples/hybrid/ObstacleAvoidance.fld b/examples/hybrid/ObstacleAvoidance.fld
new file mode 100644
index 0000000..bd96696
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.fld
@@ -0,0 +1,1025 @@
+obstacle mSteer tsSteer
+0.000000000 0.666650000 0.666000000
+0.000977517 0.666650000 0.665674487
+0.001955034 0.666650000 0.665348974
+0.002932551 0.666650000 0.665023460
+0.003910068 0.666650000 0.664697947
+0.004887586 0.666650000 0.664372434
+0.005865103 0.666638485 0.664046921
+0.006842620 0.666625450 0.663721408
+0.007820137 0.666612389 0.663395894
+0.008797654 0.666599303 0.663070381
+0.009775171 0.666586193 0.662744868
+0.010752688 0.666573056 0.662419355
+0.011730205 0.666559894 0.662093842
+0.012707722 0.666546707 0.661768328
+0.013685239 0.666533494 0.661442815
+0.014662757 0.666520255 0.661117302
+0.015640274 0.666498518 0.660791789
+0.016617791 0.666472271 0.660466276
+0.017595308 0.666445974 0.660140762
+0.018572825 0.666419626 0.659815249
+0.019550342 0.666393229 0.659489736
+0.020527859 0.666366781 0.659164223
+0.021505376 0.666340282 0.658838710
+0.022482893 0.666313732 0.658513196
+0.023460411 0.666287131 0.658187683
+0.024437928 0.666260479 0.657862170
+0.025415445 0.666228313 0.657536657
+0.026392962 0.666188686 0.657211144
+0.027370479 0.666148986 0.656885630
+0.028347996 0.666109209 0.656560117
+0.029325513 0.666069358 0.656234604
+0.030303030 0.666029432 0.655909091
+0.031280547 0.665989429 0.655583578
+0.032258065 0.665949351 0.655258065
+0.033235582 0.665909196 0.654932551
+0.034213099 0.665868966 0.654607038
+0.035190616 0.665826169 0.654281525
+0.036168133 0.665773005 0.653956012
+0.037145650 0.665719742 0.653630499
+0.038123167 0.665666380 0.653304985
+0.039100684 0.665612917 0.652979472
+0.040078201 0.665559355 0.652653959
+0.041055718 0.665505693 0.652328446
+0.042033236 0.665451930 0.652002933
+0.043010753 0.665398066 0.651677419
+0.043988270 0.665344101 0.651351906
+0.044965787 0.665290034 0.651026393
+0.045943304 0.665223628 0.650700880
+0.046920821 0.665156655 0.650375367
+0.047898338 0.665089559 0.650049853
+0.048875855 0.665022339 0.649724340
+0.049853372 0.664954994 0.649398827
+0.050830890 0.664887525 0.649073314
+0.051808407 0.664819932 0.648747801
+0.052785924 0.664752213 0.648422287
+0.053763441 0.664684369 0.648096774
+0.054740958 0.664616398 0.647771261
+0.055718475 0.664539056 0.647445748
+0.056695992 0.664458237 0.647120235
+0.057673509 0.664377270 0.646794721
+0.058651026 0.664296156 0.646469208
+0.059628543 0.664214895 0.646143695
+0.060606061 0.664133485 0.645818182
+0.061583578 0.664051926 0.645492669
+0.062561095 0.663970218 0.645167155
+0.063538612 0.663888361 0.644841642
+0.064516129 0.663806354 0.644516129
+0.065493646 0.663717900 0.644190616
+0.066471163 0.663623109 0.643865103
+0.067448680 0.663528148 0.643539589
+0.068426197 0.663433016 0.643214076
+0.069403715 0.663337714 0.642888563
+0.070381232 0.663242240 0.642563050
+0.071358749 0.663146594 0.642237537
+0.072336266 0.663050776 0.641912023
+0.073313783 0.662954785 0.641586510
+0.074291300 0.662858620 0.641260997
+0.075268817 0.662758885 0.640935484
+0.076246334 0.662650011 0.640609971
+0.077223851 0.662540943 0.640284457
+0.078201369 0.662431683 0.639958944
+0.079178886 0.662322229 0.639633431
+0.080156403 0.662212581 0.639307918
+0.081133920 0.662102739 0.638982405
+0.082111437 0.661992701 0.638656891
+0.083088954 0.661882468 0.638331378
+0.084066471 0.661772039 0.638005865
+0.085043988 0.661660863 0.637680352
+0.086021505 0.661537806 0.637354839
+0.086999022 0.661414534 0.637029326
+0.087976540 0.661291048 0.636703812
+0.088954057 0.661167346 0.636378299
+0.089931574 0.661043428 0.636052786
+0.090909091 0.660919294 0.635727273
+0.091886608 0.660794942 0.635401760
+0.092864125 0.660670373 0.635076246
+0.093841642 0.660545585 0.634750733
+0.094819159 0.660420579 0.634425220
+0.095796676 0.660285492 0.634099707
+0.096774194 0.660147932 0.633774194
+0.097751711 0.660010136 0.633448680
+0.098729228 0.659872104 0.633123167
+0.099706745 0.659733835 0.632797654
+0.100684262 0.659595328 0.632472141
+0.101661779 0.659456582 0.632146628
+0.102639296 0.659317597 0.631821114
+0.103616813 0.659178373 0.631495601
+0.104594330 0.659038909 0.631170088
+0.105571848 0.658892208 0.630844575
+0.106549365 0.658740291 0.630519062
+0.107526882 0.658588119 0.630193548
+0.108504399 0.658435689 0.629868035
+0.109481916 0.658283002 0.629542522
+0.110459433 0.658130057 0.629217009
+0.111436950 0.657976852 0.628891496
+0.112414467 0.657823389 0.628565982
+0.113391984 0.657669665 0.628240469
+0.114369501 0.657515680 0.627914956
+0.115347019 0.657357242 0.627589443
+0.116324536 0.657190916 0.627263930
+0.117302053 0.657024315 0.626938416
+0.118279570 0.656857437 0.626612903
+0.119257087 0.656690282 0.626287390
+0.120234604 0.656522850 0.625961877
+0.121212121 0.656355139 0.625636364
+0.122189638 0.656187149 0.625310850
+0.123167155 0.656018879 0.624985337
+0.124144673 0.655850329 0.624659824
+0.125122190 0.655680041 0.624334311
+0.126099707 0.655499270 0.624008798
+0.127077224 0.655318205 0.623683284
+0.128054741 0.655136845 0.623357771
+0.129032258 0.654955190 0.623032258
+0.130009775 0.654773238 0.622706745
+0.130987292 0.654590990 0.622381232
+0.131964809 0.654408443 0.622055718
+0.132942326 0.654225598 0.621730205
+0.133919844 0.654042454 0.621404692
+0.134897361 0.653859010 0.621079179
+0.135874878 0.653664982 0.620753666
+0.136852395 0.653469436 0.620428152
+0.137829912 0.653273578 0.620102639
+0.138807429 0.653077407 0.619777126
+0.139784946 0.652880922 0.619451613
+0.140762463 0.652684123 0.619126100
+0.141739980 0.652487008 0.618800587
+0.142717498 0.652289577 0.618475073
+0.143695015 0.652091829 0.618149560
+0.144672532 0.651893763 0.617824047
+0.145650049 0.651687855 0.617498534
+0.146627566 0.651477831 0.617173021
+0.147605083 0.651267477 0.616847507
+0.148582600 0.651056794 0.616521994
+0.149560117 0.650845780 0.616196481
+0.150537634 0.650634436 0.615870968
+0.151515152 0.650422759 0.615545455
+0.152492669 0.650210750 0.615219941
+0.153470186 0.649998407 0.614894428
+0.154447703 0.649785731 0.614568915
+0.155425220 0.649567877 0.614243402
+0.156402737 0.649343393 0.613917889
+0.157380254 0.649118566 0.613592375
+0.158357771 0.648893393 0.613266862
+0.159335288 0.648667875 0.612941349
+0.160312805 0.648442011 0.612615836
+0.161290323 0.648215799 0.612290323
+0.162267840 0.647989239 0.611964809
+0.163245357 0.647762331 0.611639296
+0.164222874 0.647535073 0.611313783
+0.165200391 0.647305221 0.610988270
+0.166177908 0.647066320 0.610662757
+0.167155425 0.646827060 0.610337243
+0.168132942 0.646587441 0.610011730
+0.169110459 0.646347463 0.609686217
+0.170087977 0.646107124 0.609360704
+0.171065494 0.645866424 0.609035191
+0.172043011 0.645625361 0.608709677
+0.173020528 0.645383936 0.608384164
+0.173998045 0.645142147 0.608058651
+0.174975562 0.644899993 0.607733138
+0.175953079 0.644647002 0.607407625
+0.176930596 0.644393373 0.607082111
+0.177908113 0.644139372 0.606756598
+0.178885630 0.643884998 0.606431085
+0.179863148 0.643630251 0.606105572
+0.180840665 0.643375130 0.605780059
+0.181818182 0.643119633 0.605454545
+0.182795699 0.642863761 0.605129032
+0.183773216 0.642607513 0.604803519
+0.184750733 0.642350886 0.604478006
+0.185728250 0.642086038 0.604152493
+0.186705767 0.641818123 0.603826979
+0.187683284 0.641549824 0.603501466
+0.188660802 0.641281142 0.603175953
+0.189638319 0.641012074 0.602850440
+0.190615836 0.640742621 0.602524927
+0.191593353 0.640472782 0.602199413
+0.192570870 0.640202555 0.601873900
+0.193548387 0.639931940 0.601548387
+0.194525904 0.639660937 0.601222874
+0.195503421 0.639384233 0.600897361
+0.196480938 0.639102138 0.600571848
+0.197458456 0.638819650 0.600246334
+0.198435973 0.638536767 0.599920821
+0.199413490 0.638253490 0.599595308
+0.200391007 0.637969817 0.599269795
+0.201368524 0.637685747 0.598944282
+0.202346041 0.637401280 0.598618768
+0.203323558 0.637116415 0.598293255
+0.204301075 0.636831150 0.597967742
+0.205278592 0.636542613 0.597642229
+0.206256109 0.636246466 0.597316716
+0.207233627 0.635949918 0.596991202
+0.208211144 0.635652966 0.596665689
+0.209188661 0.635355612 0.596340176
+0.210166178 0.635057853 0.596014663
+0.211143695 0.634759688 0.595689150
+0.212121212 0.634461118 0.595363636
+0.213098729 0.634162142 0.595038123
+0.214076246 0.633862757 0.594712610
+0.215053763 0.633562423 0.594387097
+0.216031281 0.633252376 0.594061584
+0.217008798 0.632941920 0.593736070
+0.217986315 0.632631055 0.593410557
+0.218963832 0.632319779 0.593085044
+0.219941349 0.632008091 0.592759531
+0.220918866 0.631695992 0.592434018
+0.221896383 0.631383479 0.592108504
+0.222873900 0.631070553 0.591782991
+0.223851417 0.630757212 0.591457478
+0.224828935 0.630443455 0.591131965
+0.225806452 0.630121364 0.590806452
+0.226783969 0.629797178 0.590480938
+0.227761486 0.629472576 0.590155425
+0.228739003 0.629147559 0.589829912
+0.229716520 0.628822125 0.589504399
+0.230694037 0.628496272 0.589178886
+0.231671554 0.628170002 0.588853372
+0.232649071 0.627843312 0.588527859
+0.233626588 0.627516202 0.588202346
+0.234604106 0.627188671 0.587876833
+0.235581623 0.626855159 0.587551320
+0.236559140 0.626517443 0.587225806
+0.237536657 0.626179308 0.586900293
+0.238514174 0.625840753 0.586574780
+0.239491691 0.625501777 0.586249267
+0.240469208 0.625162379 0.585923754
+0.241446725 0.624822559 0.585598240
+0.242424242 0.624482316 0.585272727
+0.243401760 0.624141649 0.584947214
+0.244379277 0.623800557 0.584621701
+0.245356794 0.623455725 0.584296188
+0.246334311 0.623104704 0.583970674
+0.247311828 0.622753262 0.583645161
+0.248289345 0.622401397 0.583319648
+0.249266862 0.622049109 0.582994135
+0.250244379 0.621696398 0.582668622
+0.251221896 0.621343261 0.582343109
+0.252199413 0.620989700 0.582017595
+0.253176931 0.620635712 0.581692082
+0.254154448 0.620281297 0.581366569
+0.255131965 0.619925265 0.581041056
+0.256109482 0.619561189 0.580715543
+0.257086999 0.619196691 0.580390029
+0.258064516 0.618831769 0.580064516
+0.259042033 0.618466424 0.579739003
+0.260019550 0.618100655 0.579413490
+0.260997067 0.617734460 0.579087977
+0.261974585 0.617367839 0.578762463
+0.262952102 0.617000791 0.578436950
+0.263929619 0.616633316 0.578111437
+0.264907136 0.616265413 0.577785924
+0.265884653 0.615889366 0.577460411
+0.266862170 0.615512088 0.577134897
+0.267839687 0.615134387 0.576809384
+0.268817204 0.614756264 0.576483871
+0.269794721 0.614377718 0.576158358
+0.270772239 0.613998747 0.575832845
+0.271749756 0.613619351 0.575507331
+0.272727273 0.613239530 0.575181818
+0.273704790 0.612859282 0.574856305
+0.274682307 0.612478608 0.574530792
+0.275659824 0.612091947 0.574205279
+0.276637341 0.611702189 0.573879765
+0.277614858 0.611312012 0.573554252
+0.278592375 0.610921415 0.573228739
+0.279569892 0.610530398 0.572903226
+0.280547410 0.610138959 0.572577713
+0.281524927 0.609747097 0.572252199
+0.282502444 0.609354813 0.571926686
+0.283479961 0.608962106 0.571601173
+0.284457478 0.608568974 0.571275660
+0.285434995 0.608171886 0.570950147
+0.286412512 0.607769974 0.570624633
+0.287390029 0.607367648 0.570299120
+0.288367546 0.606964906 0.569973607
+0.289345064 0.606561748 0.569648094
+0.290322581 0.606158173 0.569322581
+0.291300098 0.605754180 0.568997067
+0.292277615 0.605349770 0.568671554
+0.293255132 0.604944940 0.568346041
+0.294232649 0.604539690 0.568020528
+0.295210166 0.604132380 0.567695015
+0.296187683 0.603718665 0.567369501
+0.297165200 0.603304542 0.567043988
+0.298142717 0.602890009 0.566718475
+0.299120235 0.602475066 0.566392962
+0.300097752 0.602059712 0.566067449
+0.301075269 0.601643947 0.565741935
+0.302052786 0.601227769 0.565416422
+0.303030303 0.600811179 0.565090909
+0.304007820 0.600394176 0.564765396
+0.304985337 0.599976759 0.564439883
+0.305962854 0.599551726 0.564114370
+0.306940371 0.599126182 0.563788856
+0.307917889 0.598700236 0.563463343
+0.308895406 0.598273888 0.563137830
+0.309872923 0.597847137 0.562812317
+0.310850440 0.597419982 0.562486804
+0.311827957 0.596992424 0.562161290
+0.312805474 0.596564460 0.561835777
+0.313782991 0.596136092 0.561510264
+0.314760508 0.595707318 0.561184751
+0.315738025 0.595272860 0.560859238
+0.316715543 0.594836296 0.560533724
+0.317693060 0.594399340 0.560208211
+0.318670577 0.593961991 0.559882698
+0.319648094 0.593524248 0.559557185
+0.320625611 0.593086112 0.559231672
+0.321603128 0.592647581 0.558906158
+0.322580645 0.592208655 0.558580645
+0.323558162 0.591769334 0.558255132
+0.324535679 0.591329617 0.557929619
+0.325513196 0.590886006 0.557604106
+0.326490714 0.590438847 0.557278592
+0.327468231 0.589991307 0.556953079
+0.328445748 0.589543385 0.556627566
+0.329423265 0.589095081 0.556302053
+0.330400782 0.588646394 0.555976540
+0.331378299 0.588197324 0.555651026
+0.332355816 0.587747870 0.555325513
+0.333333333 0.587298033 0.555000000
+0.334310850 0.586847811 0.554674487
+0.335288368 0.586395337 0.554348974
+0.336265885 0.585938031 0.554023460
+0.337243402 0.585480357 0.553697947
+0.338220919 0.585022313 0.553372434
+0.339198436 0.584563900 0.553046921
+0.340175953 0.584105117 0.552721408
+0.341153470 0.583645965 0.552395894
+0.342130987 0.583186441 0.552070381
+0.343108504 0.582726546 0.551744868
+0.344086022 0.582266280 0.551419355
+0.345063539 0.581805253 0.551093842
+0.346041056 0.581338270 0.550768328
+0.347018573 0.580870934 0.550442815
+0.347996090 0.580403243 0.550117302
+0.348973607 0.579935197 0.549791789
+0.349951124 0.579466795 0.549466276
+0.350928641 0.578998038 0.549140762
+0.351906158 0.578528925 0.548815249
+0.352883675 0.578059455 0.548489736
+0.353861193 0.577589628 0.548164223
+0.354838710 0.577119444 0.547838710
+0.355816227 0.576644207 0.547513196
+0.356793744 0.576167703 0.547187683
+0.357771261 0.575690860 0.546862170
+0.358748778 0.575213679 0.546536657
+0.359726295 0.574736158 0.546211144
+0.360703812 0.574258297 0.545885630
+0.361681329 0.573780096 0.545560117
+0.362658847 0.573301554 0.545234604
+0.363636364 0.572822672 0.544909091
+0.364613881 0.572343449 0.544583578
+0.365591398 0.571860698 0.544258065
+0.366568915 0.571375542 0.543932551
+0.367546432 0.570890065 0.543607038
+0.368523949 0.570404267 0.543281525
+0.369501466 0.569918146 0.542956012
+0.370478983 0.569431703 0.542630499
+0.371456500 0.568944938 0.542304985
+0.372434018 0.568457849 0.541979472
+0.373411535 0.567970438 0.541653959
+0.374389052 0.567482703 0.541328446
+0.375366569 0.566992805 0.541002933
+0.376344086 0.566499534 0.540677419
+0.377321603 0.566005960 0.540351906
+0.378299120 0.565512083 0.540026393
+0.379276637 0.565017903 0.539700880
+0.380254154 0.564523420 0.539375367
+0.381231672 0.564028633 0.539049853
+0.382209189 0.563533542 0.538724340
+0.383186706 0.563038147 0.538398827
+0.384164223 0.562542448 0.538073314
+0.385141740 0.562045786 0.537747801
+0.386119257 0.561544954 0.537422287
+0.387096774 0.561043840 0.537096774
+0.388074291 0.560542444 0.536771261
+0.389051808 0.560040764 0.536445748
+0.390029326 0.559538801 0.536120235
+0.391006843 0.559036555 0.535794721
+0.391984360 0.558534026 0.535469208
+0.392961877 0.558031212 0.535143695
+0.393939394 0.557528114 0.534818182
+0.394916911 0.557024732 0.534492669
+0.395894428 0.556517268 0.534167155
+0.396871945 0.556009189 0.533841642
+0.397849462 0.555500848 0.533516129
+0.398826979 0.554992247 0.533190616
+0.399804497 0.554483383 0.532865103
+0.400782014 0.553974258 0.532539589
+0.401759531 0.553464870 0.532214076
+0.402737048 0.552955221 0.531888563
+0.403714565 0.552445308 0.531563050
+0.404692082 0.551935134 0.531237537
+0.405669599 0.551422112 0.530912023
+0.406647116 0.550907660 0.530586510
+0.407624633 0.550392969 0.530260997
+0.408602151 0.549878039 0.529935484
+0.409579668 0.549362870 0.529609971
+0.410557185 0.548847462 0.529284457
+0.411534702 0.548331815 0.528958944
+0.412512219 0.547815928 0.528633431
+0.413489736 0.547299802 0.528307918
+0.414467253 0.546783436 0.527982405
+0.415444770 0.546265287 0.527656891
+0.416422287 0.545745069 0.527331378
+0.417399804 0.545224637 0.527005865
+0.418377322 0.544703989 0.526680352
+0.419354839 0.544183126 0.526354839
+0.420332356 0.543662048 0.526029326
+0.421309873 0.543140754 0.525703812
+0.422287390 0.542619244 0.525378299
+0.423264907 0.542097518 0.525052786
+0.424242424 0.541575577 0.524727273
+0.425219941 0.541052744 0.524401760
+0.426197458 0.540527383 0.524076246
+0.427174976 0.540001832 0.523750733
+0.428152493 0.539476090 0.523425220
+0.429130010 0.538950158 0.523099707
+0.430107527 0.538424035 0.522774194
+0.431085044 0.537897722 0.522448680
+0.432062561 0.537371217 0.522123167
+0.433040078 0.536844521 0.521797654
+0.434017595 0.536317635 0.521472141
+0.434995112 0.535790557 0.521146628
+0.435972630 0.535260701 0.520821114
+0.436950147 0.534730668 0.520495601
+0.437927664 0.534200469 0.520170088
+0.438905181 0.533670106 0.519844575
+0.439882698 0.533139577 0.519519062
+0.440860215 0.532608883 0.519193548
+0.441837732 0.532078024 0.518868035
+0.442815249 0.531546999 0.518542522
+0.443792766 0.531015810 0.518217009
+0.444770283 0.530484454 0.517891496
+0.445747801 0.529951246 0.517565982
+0.446725318 0.529417377 0.517240469
+0.447702835 0.528883370 0.516914956
+0.448680352 0.528349224 0.516589443
+0.449657869 0.527814939 0.516263930
+0.450635386 0.527280516 0.515938416
+0.451612903 0.526745953 0.515612903
+0.452590420 0.526211252 0.515287390
+0.453567937 0.525676412 0.514961877
+0.454545455 0.525141432 0.514636364
+0.455522972 0.524605346 0.514310850
+0.456500489 0.524068300 0.513985337
+0.457478006 0.523531142 0.513659824
+0.458455523 0.522993872 0.513334311
+0.459433040 0.522456490 0.513008798
+0.460410557 0.521918997 0.512683284
+0.461388074 0.521381392 0.512357771
+0.462365591 0.520843675 0.512032258
+0.463343109 0.520305846 0.511706745
+0.464320626 0.519767905 0.511381232
+0.465298143 0.519229421 0.511055718
+0.466275660 0.518689863 0.510730205
+0.467253177 0.518150220 0.510404692
+0.468230694 0.517610493 0.510079179
+0.469208211 0.517070682 0.509753666
+0.470185728 0.516530787 0.509428152
+0.471163245 0.515990807 0.509102639
+0.472140762 0.515450743 0.508777126
+0.473118280 0.514910594 0.508451613
+0.474095797 0.514370361 0.508126100
+0.475073314 0.513829968 0.507800587
+0.476050831 0.513288569 0.507475073
+0.477028348 0.512747115 0.507149560
+0.478005865 0.512205604 0.506824047
+0.478983382 0.511664036 0.506498534
+0.479960899 0.511122412 0.506173021
+0.480938416 0.510580732 0.505847507
+0.481915934 0.510038995 0.505521994
+0.482893451 0.509497202 0.505196481
+0.483870968 0.508955352 0.504870968
+0.484848485 0.508413446 0.504545455
+0.485826002 0.507870980 0.504219941
+0.486803519 0.507328390 0.503894428
+0.487781036 0.506785773 0.503568915
+0.488758553 0.506243127 0.503243402
+0.489736070 0.505700453 0.502917889
+0.490713587 0.505157751 0.502592375
+0.491691105 0.504615020 0.502266862
+0.492668622 0.504072261 0.501941349
+0.493646139 0.503529474 0.501615836
+0.494623656 0.502986658 0.501290323
+0.495601173 0.502443695 0.500964809
+0.496578690 0.501900652 0.500639296
+0.497556207 0.501357608 0.500313783
+0.498533724 0.500814565 0.499988270
+0.499511241 0.500271522 0.499662757
+0.500488759 0.499728478 0.499337243
+0.501466276 0.499185435 0.499011730
+0.502443793 0.498642392 0.498686217
+0.503421310 0.498099348 0.498360704
+0.504398827 0.497556305 0.498035191
+0.505376344 0.497013342 0.497709677
+0.506353861 0.496470526 0.497384164
+0.507331378 0.495927739 0.497058651
+0.508308895 0.495384980 0.496733138
+0.509286413 0.494842249 0.496407625
+0.510263930 0.494299547 0.496082111
+0.511241447 0.493756873 0.495756598
+0.512218964 0.493214227 0.495431085
+0.513196481 0.492671610 0.495105572
+0.514173998 0.492129020 0.494780059
+0.515151515 0.491586554 0.494454545
+0.516129032 0.491044648 0.494129032
+0.517106549 0.490502798 0.493803519
+0.518084066 0.489961005 0.493478006
+0.519061584 0.489419268 0.493152493
+0.520039101 0.488877588 0.492826979
+0.521016618 0.488335964 0.492501466
+0.521994135 0.487794396 0.492175953
+0.522971652 0.487252885 0.491850440
+0.523949169 0.486711431 0.491524927
+0.524926686 0.486170032 0.491199413
+0.525904203 0.485629639 0.490873900
+0.526881720 0.485089406 0.490548387
+0.527859238 0.484549257 0.490222874
+0.528836755 0.484009193 0.489897361
+0.529814272 0.483469213 0.489571848
+0.530791789 0.482929318 0.489246334
+0.531769306 0.482389507 0.488920821
+0.532746823 0.481849780 0.488595308
+0.533724340 0.481310137 0.488269795
+0.534701857 0.480770579 0.487944282
+0.535679374 0.480232095 0.487618768
+0.536656891 0.479694154 0.487293255
+0.537634409 0.479156325 0.486967742
+0.538611926 0.478618608 0.486642229
+0.539589443 0.478081003 0.486316716
+0.540566960 0.477543510 0.485991202
+0.541544477 0.477006128 0.485665689
+0.542521994 0.476468858 0.485340176
+0.543499511 0.475931700 0.485014663
+0.544477028 0.475394654 0.484689150
+0.545454545 0.474858568 0.484363636
+0.546432063 0.474323588 0.484038123
+0.547409580 0.473788748 0.483712610
+0.548387097 0.473254047 0.483387097
+0.549364614 0.472719484 0.483061584
+0.550342131 0.472185061 0.482736070
+0.551319648 0.471650776 0.482410557
+0.552297165 0.471116630 0.482085044
+0.553274682 0.470582623 0.481759531
+0.554252199 0.470048754 0.481434018
+0.555229717 0.469515546 0.481108504
+0.556207234 0.468984190 0.480782991
+0.557184751 0.468453001 0.480457478
+0.558162268 0.467921976 0.480131965
+0.559139785 0.467391117 0.479806452
+0.560117302 0.466860423 0.479480938
+0.561094819 0.466329894 0.479155425
+0.562072336 0.465799531 0.478829912
+0.563049853 0.465269332 0.478504399
+0.564027370 0.464739299 0.478178886
+0.565004888 0.464209443 0.477853372
+0.565982405 0.463682365 0.477527859
+0.566959922 0.463155479 0.477202346
+0.567937439 0.462628783 0.476876833
+0.568914956 0.462102278 0.476551320
+0.569892473 0.461575965 0.476225806
+0.570869990 0.461049842 0.475900293
+0.571847507 0.460523910 0.475574780
+0.572825024 0.459998168 0.475249267
+0.573802542 0.459472617 0.474923754
+0.574780059 0.458947256 0.474598240
+0.575757576 0.458424423 0.474272727
+0.576735093 0.457902482 0.473947214
+0.577712610 0.457380756 0.473621701
+0.578690127 0.456859246 0.473296188
+0.579667644 0.456337952 0.472970674
+0.580645161 0.455816874 0.472645161
+0.581622678 0.455296011 0.472319648
+0.582600196 0.454775363 0.471994135
+0.583577713 0.454254931 0.471668622
+0.584555230 0.453734713 0.471343109
+0.585532747 0.453216564 0.471017595
+0.586510264 0.452700198 0.470692082
+0.587487781 0.452184072 0.470366569
+0.588465298 0.451668185 0.470041056
+0.589442815 0.451152538 0.469715543
+0.590420332 0.450637130 0.469390029
+0.591397849 0.450121961 0.469064516
+0.592375367 0.449607031 0.468739003
+0.593352884 0.449092340 0.468413490
+0.594330401 0.448577888 0.468087977
+0.595307918 0.448064866 0.467762463
+0.596285435 0.447554692 0.467436950
+0.597262952 0.447044779 0.467111437
+0.598240469 0.446535130 0.466785924
+0.599217986 0.446025742 0.466460411
+0.600195503 0.445516617 0.466134897
+0.601173021 0.445007753 0.465809384
+0.602150538 0.444499152 0.465483871
+0.603128055 0.443990811 0.465158358
+0.604105572 0.443482732 0.464832845
+0.605083089 0.442975268 0.464507331
+0.606060606 0.442471886 0.464181818
+0.607038123 0.441968788 0.463856305
+0.608015640 0.441465974 0.463530792
+0.608993157 0.440963445 0.463205279
+0.609970674 0.440461199 0.462879765
+0.610948192 0.439959236 0.462554252
+0.611925709 0.439457556 0.462228739
+0.612903226 0.438956160 0.461903226
+0.613880743 0.438455046 0.461577713
+0.614858260 0.437954214 0.461252199
+0.615835777 0.437457552 0.460926686
+0.616813294 0.436961853 0.460601173
+0.617790811 0.436466458 0.460275660
+0.618768328 0.435971367 0.459950147
+0.619745846 0.435476580 0.459624633
+0.620723363 0.434982097 0.459299120
+0.621700880 0.434487917 0.458973607
+0.622678397 0.433994040 0.458648094
+0.623655914 0.433500466 0.458322581
+0.624633431 0.433007195 0.457997067
+0.625610948 0.432517297 0.457671554
+0.626588465 0.432029562 0.457346041
+0.627565982 0.431542151 0.457020528
+0.628543500 0.431055062 0.456695015
+0.629521017 0.430568297 0.456369501
+0.630498534 0.430081854 0.456043988
+0.631476051 0.429595733 0.455718475
+0.632453568 0.429109935 0.455392962
+0.633431085 0.428624458 0.455067449
+0.634408602 0.428139302 0.454741935
+0.635386119 0.427656551 0.454416422
+0.636363636 0.427177328 0.454090909
+0.637341153 0.426698446 0.453765396
+0.638318671 0.426219904 0.453439883
+0.639296188 0.425741703 0.453114370
+0.640273705 0.425263842 0.452788856
+0.641251222 0.424786321 0.452463343
+0.642228739 0.424309140 0.452137830
+0.643206256 0.423832297 0.451812317
+0.644183773 0.423355793 0.451486804
+0.645161290 0.422880556 0.451161290
+0.646138807 0.422410372 0.450835777
+0.647116325 0.421940545 0.450510264
+0.648093842 0.421471075 0.450184751
+0.649071359 0.421001962 0.449859238
+0.650048876 0.420533205 0.449533724
+0.651026393 0.420064803 0.449208211
+0.652003910 0.419596757 0.448882698
+0.652981427 0.419129066 0.448557185
+0.653958944 0.418661730 0.448231672
+0.654936461 0.418194747 0.447906158
+0.655913978 0.417733720 0.447580645
+0.656891496 0.417273454 0.447255132
+0.657869013 0.416813559 0.446929619
+0.658846530 0.416354035 0.446604106
+0.659824047 0.415894883 0.446278592
+0.660801564 0.415436100 0.445953079
+0.661779081 0.414977687 0.445627566
+0.662756598 0.414519643 0.445302053
+0.663734115 0.414061969 0.444976540
+0.664711632 0.413604663 0.444651026
+0.665689150 0.413152189 0.444325513
+0.666666667 0.412701967 0.444000000
+0.667644184 0.412252130 0.443674487
+0.668621701 0.411802676 0.443348974
+0.669599218 0.411353606 0.443023460
+0.670576735 0.410904919 0.442697947
+0.671554252 0.410456615 0.442372434
+0.672531769 0.410008693 0.442046921
+0.673509286 0.409561153 0.441721408
+0.674486804 0.409113994 0.441395894
+0.675464321 0.408670383 0.441070381
+0.676441838 0.408230666 0.440744868
+0.677419355 0.407791345 0.440419355
+0.678396872 0.407352419 0.440093842
+0.679374389 0.406913888 0.439768328
+0.680351906 0.406475752 0.439442815
+0.681329423 0.406038009 0.439117302
+0.682306940 0.405600660 0.438791789
+0.683284457 0.405163704 0.438466276
+0.684261975 0.404727140 0.438140762
+0.685239492 0.404292682 0.437815249
+0.686217009 0.403863908 0.437489736
+0.687194526 0.403435540 0.437164223
+0.688172043 0.403007576 0.436838710
+0.689149560 0.402580018 0.436513196
+0.690127077 0.402152863 0.436187683
+0.691104594 0.401726112 0.435862170
+0.692082111 0.401299764 0.435536657
+0.693059629 0.400873818 0.435211144
+0.694037146 0.400448274 0.434885630
+0.695014663 0.400023241 0.434560117
+0.695992180 0.399605824 0.434234604
+0.696969697 0.399188821 0.433909091
+0.697947214 0.398772231 0.433583578
+0.698924731 0.398356053 0.433258065
+0.699902248 0.397940288 0.432932551
+0.700879765 0.397524934 0.432607038
+0.701857283 0.397109991 0.432281525
+0.702834800 0.396695458 0.431956012
+0.703812317 0.396281335 0.431630499
+0.704789834 0.395867620 0.431304985
+0.705767351 0.395460310 0.430979472
+0.706744868 0.395055060 0.430653959
+0.707722385 0.394650230 0.430328446
+0.708699902 0.394245820 0.430002933
+0.709677419 0.393841827 0.429677419
+0.710654936 0.393438252 0.429351906
+0.711632454 0.393035094 0.429026393
+0.712609971 0.392632352 0.428700880
+0.713587488 0.392230026 0.428375367
+0.714565005 0.391828114 0.428049853
+0.715542522 0.391431026 0.427724340
+0.716520039 0.391037894 0.427398827
+0.717497556 0.390645187 0.427073314
+0.718475073 0.390252903 0.426747801
+0.719452590 0.389861041 0.426422287
+0.720430108 0.389469602 0.426096774
+0.721407625 0.389078585 0.425771261
+0.722385142 0.388687988 0.425445748
+0.723362659 0.388297811 0.425120235
+0.724340176 0.387908053 0.424794721
+0.725317693 0.387521392 0.424469208
+0.726295210 0.387140718 0.424143695
+0.727272727 0.386760470 0.423818182
+0.728250244 0.386380649 0.423492669
+0.729227761 0.386001253 0.423167155
+0.730205279 0.385622282 0.422841642
+0.731182796 0.385243736 0.422516129
+0.732160313 0.384865613 0.422190616
+0.733137830 0.384487912 0.421865103
+0.734115347 0.384110634 0.421539589
+0.735092864 0.383734587 0.421214076
+0.736070381 0.383366684 0.420888563
+0.737047898 0.382999209 0.420563050
+0.738025415 0.382632161 0.420237537
+0.739002933 0.382265540 0.419912023
+0.739980450 0.381899345 0.419586510
+0.740957967 0.381533576 0.419260997
+0.741935484 0.381168231 0.418935484
+0.742913001 0.380803309 0.418609971
+0.743890518 0.380438811 0.418284457
+0.744868035 0.380074735 0.417958944
+0.745845552 0.379718703 0.417633431
+0.746823069 0.379364288 0.417307918
+0.747800587 0.379010300 0.416982405
+0.748778104 0.378656739 0.416656891
+0.749755621 0.378303602 0.416331378
+0.750733138 0.377950891 0.416005865
+0.751710655 0.377598603 0.415680352
+0.752688172 0.377246738 0.415354839
+0.753665689 0.376895296 0.415029326
+0.754643206 0.376544275 0.414703812
+0.755620723 0.376199443 0.414378299
+0.756598240 0.375858351 0.414052786
+0.757575758 0.375517684 0.413727273
+0.758553275 0.375177441 0.413401760
+0.759530792 0.374837621 0.413076246
+0.760508309 0.374498223 0.412750733
+0.761485826 0.374159247 0.412425220
+0.762463343 0.373820692 0.412099707
+0.763440860 0.373482557 0.411774194
+0.764418377 0.373144841 0.411448680
+0.765395894 0.372811329 0.411123167
+0.766373412 0.372483798 0.410797654
+0.767350929 0.372156688 0.410472141
+0.768328446 0.371829998 0.410146628
+0.769305963 0.371503728 0.409821114
+0.770283480 0.371177875 0.409495601
+0.771260997 0.370852441 0.409170088
+0.772238514 0.370527424 0.408844575
+0.773216031 0.370202822 0.408519062
+0.774193548 0.369878636 0.408193548
+0.775171065 0.369556545 0.407868035
+0.776148583 0.369242788 0.407542522
+0.777126100 0.368929447 0.407217009
+0.778103617 0.368616521 0.406891496
+0.779081134 0.368304008 0.406565982
+0.780058651 0.367991909 0.406240469
+0.781036168 0.367680221 0.405914956
+0.782013685 0.367368945 0.405589443
+0.782991202 0.367058080 0.405263930
+0.783968719 0.366747624 0.404938416
+0.784946237 0.366437577 0.404612903
+0.785923754 0.366137243 0.404287390
+0.786901271 0.365837858 0.403961877
+0.787878788 0.365538882 0.403636364
+0.788856305 0.365240312 0.403310850
+0.789833822 0.364942147 0.402985337
+0.790811339 0.364644388 0.402659824
+0.791788856 0.364347034 0.402334311
+0.792766373 0.364050082 0.402008798
+0.793743891 0.363753534 0.401683284
+0.794721408 0.363457387 0.401357771
+0.795698925 0.363168850 0.401032258
+0.796676442 0.362883585 0.400706745
+0.797653959 0.362598720 0.400381232
+0.798631476 0.362314253 0.400055718
+0.799608993 0.362030183 0.399730205
+0.800586510 0.361746510 0.399404692
+0.801564027 0.361463233 0.399079179
+0.802541544 0.361180350 0.398753666
+0.803519062 0.360897862 0.398428152
+0.804496579 0.360615767 0.398102639
+0.805474096 0.360339063 0.397777126
+0.806451613 0.360068060 0.397451613
+0.807429130 0.359797445 0.397126100
+0.808406647 0.359527218 0.396800587
+0.809384164 0.359257379 0.396475073
+0.810361681 0.358987926 0.396149560
+0.811339198 0.358718858 0.395824047
+0.812316716 0.358450176 0.395498534
+0.813294233 0.358181877 0.395173021
+0.814271750 0.357913962 0.394847507
+0.815249267 0.357649114 0.394521994
+0.816226784 0.357392487 0.394196481
+0.817204301 0.357136239 0.393870968
+0.818181818 0.356880367 0.393545455
+0.819159335 0.356624870 0.393219941
+0.820136852 0.356369749 0.392894428
+0.821114370 0.356115002 0.392568915
+0.822091887 0.355860628 0.392243402
+0.823069404 0.355606627 0.391917889
+0.824046921 0.355352998 0.391592375
+0.825024438 0.355100007 0.391266862
+0.826001955 0.354857853 0.390941349
+0.826979472 0.354616064 0.390615836
+0.827956989 0.354374639 0.390290323
+0.828934506 0.354133576 0.389964809
+0.829912023 0.353892876 0.389639296
+0.830889541 0.353652537 0.389313783
+0.831867058 0.353412559 0.388988270
+0.832844575 0.353172940 0.388662757
+0.833822092 0.352933680 0.388337243
+0.834799609 0.352694779 0.388011730
+0.835777126 0.352464927 0.387686217
+0.836754643 0.352237669 0.387360704
+0.837732160 0.352010761 0.387035191
+0.838709677 0.351784201 0.386709677
+0.839687195 0.351557989 0.386384164
+0.840664712 0.351332125 0.386058651
+0.841642229 0.351106607 0.385733138
+0.842619746 0.350881434 0.385407625
+0.843597263 0.350656607 0.385082111
+0.844574780 0.350432123 0.384756598
+0.845552297 0.350214269 0.384431085
+0.846529814 0.350001593 0.384105572
+0.847507331 0.349789250 0.383780059
+0.848484848 0.349577241 0.383454545
+0.849462366 0.349365564 0.383129032
+0.850439883 0.349154220 0.382803519
+0.851417400 0.348943206 0.382478006
+0.852394917 0.348732523 0.382152493
+0.853372434 0.348522169 0.381826979
+0.854349951 0.348312145 0.381501466
+0.855327468 0.348106237 0.381175953
+0.856304985 0.347908171 0.380850440
+0.857282502 0.347710423 0.380524927
+0.858260020 0.347512992 0.380199413
+0.859237537 0.347315877 0.379873900
+0.860215054 0.347119078 0.379548387
+0.861192571 0.346922593 0.379222874
+0.862170088 0.346726422 0.378897361
+0.863147605 0.346530564 0.378571848
+0.864125122 0.346335018 0.378246334
+0.865102639 0.346140990 0.377920821
+0.866080156 0.345957546 0.377595308
+0.867057674 0.345774402 0.377269795
+0.868035191 0.345591557 0.376944282
+0.869012708 0.345409010 0.376618768
+0.869990225 0.345226762 0.376293255
+0.870967742 0.345044810 0.375967742
+0.871945259 0.344863155 0.375642229
+0.872922776 0.344681795 0.375316716
+0.873900293 0.344500730 0.374991202
+0.874877810 0.344319959 0.374665689
+0.875855327 0.344149671 0.374340176
+0.876832845 0.343981121 0.374014663
+0.877810362 0.343812851 0.373689150
+0.878787879 0.343644861 0.373363636
+0.879765396 0.343477150 0.373038123
+0.880742913 0.343309718 0.372712610
+0.881720430 0.343142563 0.372387097
+0.882697947 0.342975685 0.372061584
+0.883675464 0.342809084 0.371736070
+0.884652981 0.342642758 0.371410557
+0.885630499 0.342484320 0.371085044
+0.886608016 0.342330335 0.370759531
+0.887585533 0.342176611 0.370434018
+0.888563050 0.342023148 0.370108504
+0.889540567 0.341869943 0.369782991
+0.890518084 0.341716998 0.369457478
+0.891495601 0.341564311 0.369131965
+0.892473118 0.341411881 0.368806452
+0.893450635 0.341259709 0.368480938
+0.894428152 0.341107792 0.368155425
+0.895405670 0.340961091 0.367829912
+0.896383187 0.340821627 0.367504399
+0.897360704 0.340682403 0.367178886
+0.898338221 0.340543418 0.366853372
+0.899315738 0.340404672 0.366527859
+0.900293255 0.340266165 0.366202346
+0.901270772 0.340127896 0.365876833
+0.902248289 0.339989864 0.365551320
+0.903225806 0.339852068 0.365225806
+0.904203324 0.339714508 0.364900293
+0.905180841 0.339579421 0.364574780
+0.906158358 0.339454415 0.364249267
+0.907135875 0.339329627 0.363923754
+0.908113392 0.339205058 0.363598240
+0.909090909 0.339080706 0.363272727
+0.910068426 0.338956572 0.362947214
+0.911045943 0.338832654 0.362621701
+0.912023460 0.338708952 0.362296188
+0.913000978 0.338585466 0.361970674
+0.913978495 0.338462194 0.361645161
+0.914956012 0.338339137 0.361319648
+0.915933529 0.338227961 0.360994135
+0.916911046 0.338117532 0.360668622
+0.917888563 0.338007299 0.360343109
+0.918866080 0.337897261 0.360017595
+0.919843597 0.337787419 0.359692082
+0.920821114 0.337677771 0.359366569
+0.921798631 0.337568317 0.359041056
+0.922776149 0.337459057 0.358715543
+0.923753666 0.337349989 0.358390029
+0.924731183 0.337241115 0.358064516
+0.925708700 0.337141380 0.357739003
+0.926686217 0.337045215 0.357413490
+0.927663734 0.336949224 0.357087977
+0.928641251 0.336853406 0.356762463
+0.929618768 0.336757760 0.356436950
+0.930596285 0.336662286 0.356111437
+0.931573803 0.336566984 0.355785924
+0.932551320 0.336471852 0.355460411
+0.933528837 0.336376891 0.355134897
+0.934506354 0.336282100 0.354809384
+0.935483871 0.336193646 0.354483871
+0.936461388 0.336111639 0.354158358
+0.937438905 0.336029782 0.353832845
+0.938416422 0.335948074 0.353507331
+0.939393939 0.335866515 0.353181818
+0.940371457 0.335785105 0.352856305
+0.941348974 0.335703844 0.352530792
+0.942326491 0.335622730 0.352205279
+0.943304008 0.335541763 0.351879765
+0.944281525 0.335460944 0.351554252
+0.945259042 0.335383602 0.351228739
+0.946236559 0.335315631 0.350903226
+0.947214076 0.335247787 0.350577713
+0.948191593 0.335180068 0.350252199
+0.949169110 0.335112475 0.349926686
+0.950146628 0.335045006 0.349601173
+0.951124145 0.334977661 0.349275660
+0.952101662 0.334910441 0.348950147
+0.953079179 0.334843345 0.348624633
+0.954056696 0.334776372 0.348299120
+0.955034213 0.334709966 0.347973607
+0.956011730 0.334655899 0.347648094
+0.956989247 0.334601934 0.347322581
+0.957966764 0.334548070 0.346997067
+0.958944282 0.334494307 0.346671554
+0.959921799 0.334440645 0.346346041
+0.960899316 0.334387083 0.346020528
+0.961876833 0.334333620 0.345695015
+0.962854350 0.334280258 0.345369501
+0.963831867 0.334226995 0.345043988
+0.964809384 0.334173831 0.344718475
+0.965786901 0.334131034 0.344392962
+0.966764418 0.334090804 0.344067449
+0.967741935 0.334050649 0.343741935
+0.968719453 0.334010571 0.343416422
+0.969696970 0.333970568 0.343090909
+0.970674487 0.333930642 0.342765396
+0.971652004 0.333890791 0.342439883
+0.972629521 0.333851014 0.342114370
+0.973607038 0.333811314 0.341788856
+0.974584555 0.333771687 0.341463343
+0.975562072 0.333739521 0.341137830
+0.976539589 0.333712869 0.340812317
+0.977517107 0.333686268 0.340486804
+0.978494624 0.333659718 0.340161290
+0.979472141 0.333633219 0.339835777
+0.980449658 0.333606771 0.339510264
+0.981427175 0.333580374 0.339184751
+0.982404692 0.333554026 0.338859238
+0.983382209 0.333527729 0.338533724
+0.984359726 0.333501482 0.338208211
+0.985337243 0.333479745 0.337882698
+0.986314761 0.333466506 0.337557185
+0.987292278 0.333453293 0.337231672
+0.988269795 0.333440106 0.336906158
+0.989247312 0.333426944 0.336580645
+0.990224829 0.333413807 0.336255132
+0.991202346 0.333400697 0.335929619
+0.992179863 0.333387611 0.335604106
+0.993157380 0.333374550 0.335278592
+0.994134897 0.333361515 0.334953079
+0.995112414 0.333350000 0.334627566
+0.996089932 0.333350000 0.334302053
+0.997067449 0.333350000 0.333976540
+0.998044966 0.333350000 0.333651026
+0.999022483 0.333350000 0.333325513
+1.000000000 0.333350000 0.333000000
diff --git a/examples/hybrid/ObstacleAvoidance.fll b/examples/hybrid/ObstacleAvoidance.fll
new file mode 100644
index 0000000..970221b
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.fll
@@ -0,0 +1,43 @@
+Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: mSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: tsSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: left Constant 0.333
+ term: right Constant 0.666
+RuleBlock: mamdani
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: AlgebraicProduct
+ activation: General
+ rule: if obstacle is left then mSteer is right
+ rule: if obstacle is right then mSteer is left
+RuleBlock: takagiSugeno
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if obstacle is left then tsSteer is right
+ rule: if obstacle is right then tsSteer is left \ No newline at end of file
diff --git a/examples/hybrid/ObstacleAvoidance.java b/examples/hybrid/ObstacleAvoidance.java
new file mode 100644
index 0000000..8196670
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.java
@@ -0,0 +1,86 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class ObstacleAvoidance{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("ObstacleAvoidance");
+engine.setDescription("");
+
+InputVariable obstacle = new InputVariable();
+obstacle.setName("obstacle");
+obstacle.setDescription("");
+obstacle.setEnabled(true);
+obstacle.setRange(0.000, 1.000);
+obstacle.setLockValueInRange(false);
+obstacle.addTerm(new Ramp("left", 1.000, 0.000));
+obstacle.addTerm(new Ramp("right", 0.000, 1.000));
+engine.addInputVariable(obstacle);
+
+OutputVariable mSteer = new OutputVariable();
+mSteer.setName("mSteer");
+mSteer.setDescription("");
+mSteer.setEnabled(true);
+mSteer.setRange(0.000, 1.000);
+mSteer.setLockValueInRange(false);
+mSteer.setAggregation(new Maximum());
+mSteer.setDefuzzifier(new Centroid(100));
+mSteer.setDefaultValue(Double.NaN);
+mSteer.setLockPreviousValue(false);
+mSteer.addTerm(new Ramp("left", 1.000, 0.000));
+mSteer.addTerm(new Ramp("right", 0.000, 1.000));
+engine.addOutputVariable(mSteer);
+
+OutputVariable tsSteer = new OutputVariable();
+tsSteer.setName("tsSteer");
+tsSteer.setDescription("");
+tsSteer.setEnabled(true);
+tsSteer.setRange(0.000, 1.000);
+tsSteer.setLockValueInRange(false);
+tsSteer.setAggregation(new Maximum());
+tsSteer.setDefuzzifier(new WeightedAverage("Automatic"));
+tsSteer.setDefaultValue(Double.NaN);
+tsSteer.setLockPreviousValue(false);
+tsSteer.addTerm(new Constant("left", 0.333));
+tsSteer.addTerm(new Constant("right", 0.666));
+engine.addOutputVariable(tsSteer);
+
+RuleBlock mamdani = new RuleBlock();
+mamdani.setName("mamdani");
+mamdani.setDescription("");
+mamdani.setEnabled(true);
+mamdani.setConjunction(null);
+mamdani.setDisjunction(null);
+mamdani.setImplication(new AlgebraicProduct());
+mamdani.setActivation(new General());
+mamdani.addRule(Rule.parse("if obstacle is left then mSteer is right", engine));
+mamdani.addRule(Rule.parse("if obstacle is right then mSteer is left", engine));
+engine.addRuleBlock(mamdani);
+
+RuleBlock takagiSugeno = new RuleBlock();
+takagiSugeno.setName("takagiSugeno");
+takagiSugeno.setDescription("");
+takagiSugeno.setEnabled(true);
+takagiSugeno.setConjunction(null);
+takagiSugeno.setDisjunction(null);
+takagiSugeno.setImplication(null);
+takagiSugeno.setActivation(new General());
+takagiSugeno.addRule(Rule.parse("if obstacle is left then tsSteer is right", engine));
+takagiSugeno.addRule(Rule.parse("if obstacle is right then tsSteer is left", engine));
+engine.addRuleBlock(takagiSugeno);
+
+
+}
+}
diff --git a/examples/hybrid/ObstacleAvoidance.pdf b/examples/hybrid/ObstacleAvoidance.pdf
new file mode 100644
index 0000000..ad74e68
--- /dev/null
+++ b/examples/hybrid/ObstacleAvoidance.pdf
Binary files differ
diff --git a/examples/hybrid/tipper.R b/examples/hybrid/tipper.R
new file mode 100644
index 0000000..ba11351
--- /dev/null
+++ b/examples/hybrid/tipper.R
@@ -0,0 +1,109 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "tipper"
+engine.description = "(service and food) -> (tip)"
+engine.fll = "Engine: tipper
+description: (service and food) -> (tip)
+InputVariable: service
+ description: quality of service
+ enabled: true
+ range: 0.000 10.000
+ lock-range: true
+ term: poor Trapezoid 0.000 0.000 2.500 5.000
+ term: good Triangle 2.500 5.000 7.500
+ term: excellent Trapezoid 5.000 7.500 10.000 10.000
+InputVariable: food
+ description: quality of food
+ enabled: true
+ range: 0.000 10.000
+ lock-range: true
+ term: rancid Trapezoid 0.000 0.000 2.500 7.500
+ term: delicious Trapezoid 2.500 7.500 10.000 10.000
+OutputVariable: mTip
+ description: tip based on Mamdani inference
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: cheap Triangle 0.000 5.000 10.000
+ term: average Triangle 10.000 15.000 20.000
+ term: generous Triangle 20.000 25.000 30.000
+OutputVariable: tsTip
+ description: tip based on Takagi-Sugeno inference
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: cheap Constant 5.000
+ term: average Constant 15.000
+ term: generous Constant 25.000
+RuleBlock: mamdani
+ description: Mamdani inference
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: AlgebraicSum
+ implication: Minimum
+ activation: General
+ rule: if service is poor or food is rancid then mTip is cheap
+ rule: if service is good then mTip is average
+ rule: if service is excellent or food is delicious then mTip is generous with 0.5
+ rule: if service is excellent and food is delicious then mTip is generous with 1.0
+RuleBlock: takagiSugeno
+ description: Takagi-Sugeno inference
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: AlgebraicSum
+ implication: none
+ activation: General
+ rule: if service is poor or food is rancid then tsTip is cheap
+ rule: if service is good then tsTip is average
+ rule: if service is excellent or food is delicious then tsTip is generous with 0.5
+ rule: if service is excellent and food is delicious then tsTip is generous with 1.0"
+
+engine.fldFile = "tipper.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(service, food)) +
+ geom_tile(aes(fill=mTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=service, y=food, z=mTip), color="black") +
+ ggtitle("(service, food) = mTip")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(food, service)) +
+ geom_tile(aes(fill=mTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=food, y=service, z=mTip), color="black") +
+ ggtitle("(food, service) = mTip")
+
+engine.plot.i1i2_o2 = ggplot(engine.df, aes(service, food)) +
+ geom_tile(aes(fill=tsTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=service, y=food, z=tsTip), color="black") +
+ ggtitle("(service, food) = tsTip")
+
+engine.plot.i2i1_o2 = ggplot(engine.df, aes(food, service)) +
+ geom_tile(aes(fill=tsTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=food, y=service, z=tsTip), color="black") +
+ ggtitle("(food, service) = tsTip")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, engine.plot.i1i2_o2, engine.plot.i2i1_o2, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/hybrid/tipper.cpp b/examples/hybrid/tipper.cpp
new file mode 100644
index 0000000..57bcc78
--- /dev/null
+++ b/examples/hybrid/tipper.cpp
@@ -0,0 +1,92 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("tipper");
+engine->setDescription("(service and food) -> (tip)");
+
+InputVariable* service = new InputVariable;
+service->setName("service");
+service->setDescription("quality of service");
+service->setEnabled(true);
+service->setRange(0.000, 10.000);
+service->setLockValueInRange(true);
+service->addTerm(new Trapezoid("poor", 0.000, 0.000, 2.500, 5.000));
+service->addTerm(new Triangle("good", 2.500, 5.000, 7.500));
+service->addTerm(new Trapezoid("excellent", 5.000, 7.500, 10.000, 10.000));
+engine->addInputVariable(service);
+
+InputVariable* food = new InputVariable;
+food->setName("food");
+food->setDescription("quality of food");
+food->setEnabled(true);
+food->setRange(0.000, 10.000);
+food->setLockValueInRange(true);
+food->addTerm(new Trapezoid("rancid", 0.000, 0.000, 2.500, 7.500));
+food->addTerm(new Trapezoid("delicious", 2.500, 7.500, 10.000, 10.000));
+engine->addInputVariable(food);
+
+OutputVariable* mTip = new OutputVariable;
+mTip->setName("mTip");
+mTip->setDescription("tip based on Mamdani inference");
+mTip->setEnabled(true);
+mTip->setRange(0.000, 30.000);
+mTip->setLockValueInRange(false);
+mTip->setAggregation(new Maximum);
+mTip->setDefuzzifier(new Centroid(100));
+mTip->setDefaultValue(fl::nan);
+mTip->setLockPreviousValue(false);
+mTip->addTerm(new Triangle("cheap", 0.000, 5.000, 10.000));
+mTip->addTerm(new Triangle("average", 10.000, 15.000, 20.000));
+mTip->addTerm(new Triangle("generous", 20.000, 25.000, 30.000));
+engine->addOutputVariable(mTip);
+
+OutputVariable* tsTip = new OutputVariable;
+tsTip->setName("tsTip");
+tsTip->setDescription("tip based on Takagi-Sugeno inference");
+tsTip->setEnabled(true);
+tsTip->setRange(0.000, 30.000);
+tsTip->setLockValueInRange(false);
+tsTip->setAggregation(fl::null);
+tsTip->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+tsTip->setDefaultValue(fl::nan);
+tsTip->setLockPreviousValue(false);
+tsTip->addTerm(new Constant("cheap", 5.000));
+tsTip->addTerm(new Constant("average", 15.000));
+tsTip->addTerm(new Constant("generous", 25.000));
+engine->addOutputVariable(tsTip);
+
+RuleBlock* mamdani = new RuleBlock;
+mamdani->setName("mamdani");
+mamdani->setDescription("Mamdani inference");
+mamdani->setEnabled(true);
+mamdani->setConjunction(new AlgebraicProduct);
+mamdani->setDisjunction(new AlgebraicSum);
+mamdani->setImplication(new Minimum);
+mamdani->setActivation(new General);
+mamdani->addRule(Rule::parse("if service is poor or food is rancid then mTip is cheap", engine));
+mamdani->addRule(Rule::parse("if service is good then mTip is average", engine));
+mamdani->addRule(Rule::parse("if service is excellent or food is delicious then mTip is generous with 0.5", engine));
+mamdani->addRule(Rule::parse("if service is excellent and food is delicious then mTip is generous with 1.0", engine));
+engine->addRuleBlock(mamdani);
+
+RuleBlock* takagiSugeno = new RuleBlock;
+takagiSugeno->setName("takagiSugeno");
+takagiSugeno->setDescription("Takagi-Sugeno inference");
+takagiSugeno->setEnabled(true);
+takagiSugeno->setConjunction(new AlgebraicProduct);
+takagiSugeno->setDisjunction(new AlgebraicSum);
+takagiSugeno->setImplication(fl::null);
+takagiSugeno->setActivation(new General);
+takagiSugeno->addRule(Rule::parse("if service is poor or food is rancid then tsTip is cheap", engine));
+takagiSugeno->addRule(Rule::parse("if service is good then tsTip is average", engine));
+takagiSugeno->addRule(Rule::parse("if service is excellent or food is delicious then tsTip is generous with 0.5", engine));
+takagiSugeno->addRule(Rule::parse("if service is excellent and food is delicious then tsTip is generous with 1.0", engine));
+engine->addRuleBlock(takagiSugeno);
+
+
+}
diff --git a/examples/hybrid/tipper.fcl b/examples/hybrid/tipper.fcl
new file mode 100644
index 0000000..299dbb8
--- /dev/null
+++ b/examples/hybrid/tipper.fcl
@@ -0,0 +1,66 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK tipper
+
+VAR_INPUT
+ service: REAL;
+ food: REAL;
+END_VAR
+
+VAR_OUTPUT
+ mTip: REAL;
+ tsTip: REAL;
+END_VAR
+
+FUZZIFY service
+ RANGE := (0.000 .. 10.000);
+ TERM poor := Trapezoid 0.000 0.000 2.500 5.000;
+ TERM good := Triangle 2.500 5.000 7.500;
+ TERM excellent := Trapezoid 5.000 7.500 10.000 10.000;
+END_FUZZIFY
+
+FUZZIFY food
+ RANGE := (0.000 .. 10.000);
+ TERM rancid := Trapezoid 0.000 0.000 2.500 7.500;
+ TERM delicious := Trapezoid 2.500 7.500 10.000 10.000;
+END_FUZZIFY
+
+DEFUZZIFY mTip
+ RANGE := (0.000 .. 30.000);
+ TERM cheap := Triangle 0.000 5.000 10.000;
+ TERM average := Triangle 10.000 15.000 20.000;
+ TERM generous := Triangle 20.000 25.000 30.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY tsTip
+ RANGE := (0.000 .. 30.000);
+ TERM cheap := 5.000;
+ TERM average := 15.000;
+ TERM generous := 25.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK mamdani
+ AND : PROD;
+ OR : ASUM;
+ ACT : MIN;
+ RULE 1 : if service is poor or food is rancid then mTip is cheap
+ RULE 2 : if service is good then mTip is average
+ RULE 3 : if service is excellent or food is delicious then mTip is generous with 0.5
+ RULE 4 : if service is excellent and food is delicious then mTip is generous with 1.0
+END_RULEBLOCK
+
+RULEBLOCK takagiSugeno
+ AND : PROD;
+ OR : ASUM;
+ RULE 1 : if service is poor or food is rancid then tsTip is cheap
+ RULE 2 : if service is good then tsTip is average
+ RULE 3 : if service is excellent or food is delicious then tsTip is generous with 0.5
+ RULE 4 : if service is excellent and food is delicious then tsTip is generous with 1.0
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/hybrid/tipper.fis b/examples/hybrid/tipper.fis
new file mode 100644
index 0000000..abd850a
--- /dev/null
+++ b/examples/hybrid/tipper.fis
@@ -0,0 +1,57 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='tipper'
+Type='hybrid'
+Version=6.0
+NumInputs=2
+NumOutputs=2
+NumRules=8
+AndMethod='prod'
+OrMethod='probor'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='service'
+Range=[0.000 10.000]
+NumMFs=3
+MF1='poor':'trapmf',[0.000 0.000 2.500 5.000]
+MF2='good':'trimf',[2.500 5.000 7.500]
+MF3='excellent':'trapmf',[5.000 7.500 10.000 10.000]
+
+[Input2]
+Name='food'
+Range=[0.000 10.000]
+NumMFs=2
+MF1='rancid':'trapmf',[0.000 0.000 2.500 7.500]
+MF2='delicious':'trapmf',[2.500 7.500 10.000 10.000]
+
+[Output1]
+Name='mTip'
+Range=[0.000 30.000]
+NumMFs=3
+MF1='cheap':'trimf',[0.000 5.000 10.000]
+MF2='average':'trimf',[10.000 15.000 20.000]
+MF3='generous':'trimf',[20.000 25.000 30.000]
+
+[Output2]
+Name='tsTip'
+Range=[0.000 30.000]
+NumMFs=3
+MF1='cheap':'constant',[5.000]
+MF2='average':'constant',[15.000]
+MF3='generous':'constant',[25.000]
+
+[Rules]
+# RuleBlock mamdani
+1.000 1.000 , 1.000 0.000 (1.000) : 2
+2.000 0.000 , 2.000 0.000 (1.000) : 1
+3.000 2.000 , 3.000 0.000 (0.500) : 2
+3.000 2.000 , 3.000 0.000 (1.000) : 1
+# RuleBlock takagiSugeno
+1.000 1.000 , 0.000 1.000 (1.000) : 2
+2.000 0.000 , 0.000 2.000 (1.000) : 1
+3.000 2.000 , 0.000 3.000 (0.500) : 2
+3.000 2.000 , 0.000 3.000 (1.000) : 1
diff --git a/examples/hybrid/tipper.fld b/examples/hybrid/tipper.fld
new file mode 100644
index 0000000..7a8e29d
--- /dev/null
+++ b/examples/hybrid/tipper.fld
@@ -0,0 +1,1025 @@
+service food mTip tsTip
+0.000000000 0.000000000 4.998950210 5.000000000
+0.000000000 0.322580645 4.998950210 5.000000000
+0.000000000 0.645161290 4.998950210 5.000000000
+0.000000000 0.967741935 4.998950210 5.000000000
+0.000000000 1.290322581 4.998950210 5.000000000
+0.000000000 1.612903226 4.998950210 5.000000000
+0.000000000 1.935483871 4.998950210 5.000000000
+0.000000000 2.258064516 4.998950210 5.000000000
+0.000000000 2.580645161 5.314026132 5.160000000
+0.000000000 2.903225806 6.467756859 5.775193798
+0.000000000 3.225806452 7.452789474 6.353383459
+0.000000000 3.548387097 8.316896407 6.897810219
+0.000000000 3.870967742 9.067963620 7.411347518
+0.000000000 4.193548387 9.734585733 7.896551724
+0.000000000 4.516129032 10.322182298 8.355704698
+0.000000000 4.838709677 10.846060307 8.790849673
+0.000000000 5.161290323 11.316227524 9.203821656
+0.000000000 5.483870968 11.733949841 9.596273292
+0.000000000 5.806451613 12.115369655 9.969696970
+0.000000000 6.129032258 12.452152483 10.325443787
+0.000000000 6.451612903 12.762450565 10.664739884
+0.000000000 6.774193548 13.037607639 10.988700565
+0.000000000 7.096774194 13.291172539 11.298342541
+0.000000000 7.419354839 13.516499633 11.594594595
+0.000000000 7.741935484 13.570706205 11.666666667
+0.000000000 8.064516129 13.570706205 11.666666667
+0.000000000 8.387096774 13.570706205 11.666666667
+0.000000000 8.709677419 13.570706205 11.666666667
+0.000000000 9.032258065 13.570706205 11.666666667
+0.000000000 9.354838710 13.570706205 11.666666667
+0.000000000 9.677419355 13.570706205 11.666666667
+0.000000000 10.000000000 13.570706205 11.666666667
+0.322580645 0.000000000 4.998950210 5.000000000
+0.322580645 0.322580645 4.998950210 5.000000000
+0.322580645 0.645161290 4.998950210 5.000000000
+0.322580645 0.967741935 4.998950210 5.000000000
+0.322580645 1.290322581 4.998950210 5.000000000
+0.322580645 1.612903226 4.998950210 5.000000000
+0.322580645 1.935483871 4.998950210 5.000000000
+0.322580645 2.258064516 4.998950210 5.000000000
+0.322580645 2.580645161 5.314026132 5.160000000
+0.322580645 2.903225806 6.467756859 5.775193798
+0.322580645 3.225806452 7.452789474 6.353383459
+0.322580645 3.548387097 8.316896407 6.897810219
+0.322580645 3.870967742 9.067963620 7.411347518
+0.322580645 4.193548387 9.734585733 7.896551724
+0.322580645 4.516129032 10.322182298 8.355704698
+0.322580645 4.838709677 10.846060307 8.790849673
+0.322580645 5.161290323 11.316227524 9.203821656
+0.322580645 5.483870968 11.733949841 9.596273292
+0.322580645 5.806451613 12.115369655 9.969696970
+0.322580645 6.129032258 12.452152483 10.325443787
+0.322580645 6.451612903 12.762450565 10.664739884
+0.322580645 6.774193548 13.037607639 10.988700565
+0.322580645 7.096774194 13.291172539 11.298342541
+0.322580645 7.419354839 13.516499633 11.594594595
+0.322580645 7.741935484 13.570706205 11.666666667
+0.322580645 8.064516129 13.570706205 11.666666667
+0.322580645 8.387096774 13.570706205 11.666666667
+0.322580645 8.709677419 13.570706205 11.666666667
+0.322580645 9.032258065 13.570706205 11.666666667
+0.322580645 9.354838710 13.570706205 11.666666667
+0.322580645 9.677419355 13.570706205 11.666666667
+0.322580645 10.000000000 13.570706205 11.666666667
+0.645161290 0.000000000 4.998950210 5.000000000
+0.645161290 0.322580645 4.998950210 5.000000000
+0.645161290 0.645161290 4.998950210 5.000000000
+0.645161290 0.967741935 4.998950210 5.000000000
+0.645161290 1.290322581 4.998950210 5.000000000
+0.645161290 1.612903226 4.998950210 5.000000000
+0.645161290 1.935483871 4.998950210 5.000000000
+0.645161290 2.258064516 4.998950210 5.000000000
+0.645161290 2.580645161 5.314026132 5.160000000
+0.645161290 2.903225806 6.467756859 5.775193798
+0.645161290 3.225806452 7.452789474 6.353383459
+0.645161290 3.548387097 8.316896407 6.897810219
+0.645161290 3.870967742 9.067963620 7.411347518
+0.645161290 4.193548387 9.734585733 7.896551724
+0.645161290 4.516129032 10.322182298 8.355704698
+0.645161290 4.838709677 10.846060307 8.790849673
+0.645161290 5.161290323 11.316227524 9.203821656
+0.645161290 5.483870968 11.733949841 9.596273292
+0.645161290 5.806451613 12.115369655 9.969696970
+0.645161290 6.129032258 12.452152483 10.325443787
+0.645161290 6.451612903 12.762450565 10.664739884
+0.645161290 6.774193548 13.037607639 10.988700565
+0.645161290 7.096774194 13.291172539 11.298342541
+0.645161290 7.419354839 13.516499633 11.594594595
+0.645161290 7.741935484 13.570706205 11.666666667
+0.645161290 8.064516129 13.570706205 11.666666667
+0.645161290 8.387096774 13.570706205 11.666666667
+0.645161290 8.709677419 13.570706205 11.666666667
+0.645161290 9.032258065 13.570706205 11.666666667
+0.645161290 9.354838710 13.570706205 11.666666667
+0.645161290 9.677419355 13.570706205 11.666666667
+0.645161290 10.000000000 13.570706205 11.666666667
+0.967741935 0.000000000 4.998950210 5.000000000
+0.967741935 0.322580645 4.998950210 5.000000000
+0.967741935 0.645161290 4.998950210 5.000000000
+0.967741935 0.967741935 4.998950210 5.000000000
+0.967741935 1.290322581 4.998950210 5.000000000
+0.967741935 1.612903226 4.998950210 5.000000000
+0.967741935 1.935483871 4.998950210 5.000000000
+0.967741935 2.258064516 4.998950210 5.000000000
+0.967741935 2.580645161 5.314026132 5.160000000
+0.967741935 2.903225806 6.467756859 5.775193798
+0.967741935 3.225806452 7.452789474 6.353383459
+0.967741935 3.548387097 8.316896407 6.897810219
+0.967741935 3.870967742 9.067963620 7.411347518
+0.967741935 4.193548387 9.734585733 7.896551724
+0.967741935 4.516129032 10.322182298 8.355704698
+0.967741935 4.838709677 10.846060307 8.790849673
+0.967741935 5.161290323 11.316227524 9.203821656
+0.967741935 5.483870968 11.733949841 9.596273292
+0.967741935 5.806451613 12.115369655 9.969696970
+0.967741935 6.129032258 12.452152483 10.325443787
+0.967741935 6.451612903 12.762450565 10.664739884
+0.967741935 6.774193548 13.037607639 10.988700565
+0.967741935 7.096774194 13.291172539 11.298342541
+0.967741935 7.419354839 13.516499633 11.594594595
+0.967741935 7.741935484 13.570706205 11.666666667
+0.967741935 8.064516129 13.570706205 11.666666667
+0.967741935 8.387096774 13.570706205 11.666666667
+0.967741935 8.709677419 13.570706205 11.666666667
+0.967741935 9.032258065 13.570706205 11.666666667
+0.967741935 9.354838710 13.570706205 11.666666667
+0.967741935 9.677419355 13.570706205 11.666666667
+0.967741935 10.000000000 13.570706205 11.666666667
+1.290322581 0.000000000 4.998950210 5.000000000
+1.290322581 0.322580645 4.998950210 5.000000000
+1.290322581 0.645161290 4.998950210 5.000000000
+1.290322581 0.967741935 4.998950210 5.000000000
+1.290322581 1.290322581 4.998950210 5.000000000
+1.290322581 1.612903226 4.998950210 5.000000000
+1.290322581 1.935483871 4.998950210 5.000000000
+1.290322581 2.258064516 4.998950210 5.000000000
+1.290322581 2.580645161 5.314026132 5.160000000
+1.290322581 2.903225806 6.467756859 5.775193798
+1.290322581 3.225806452 7.452789474 6.353383459
+1.290322581 3.548387097 8.316896407 6.897810219
+1.290322581 3.870967742 9.067963620 7.411347518
+1.290322581 4.193548387 9.734585733 7.896551724
+1.290322581 4.516129032 10.322182298 8.355704698
+1.290322581 4.838709677 10.846060307 8.790849673
+1.290322581 5.161290323 11.316227524 9.203821656
+1.290322581 5.483870968 11.733949841 9.596273292
+1.290322581 5.806451613 12.115369655 9.969696970
+1.290322581 6.129032258 12.452152483 10.325443787
+1.290322581 6.451612903 12.762450565 10.664739884
+1.290322581 6.774193548 13.037607639 10.988700565
+1.290322581 7.096774194 13.291172539 11.298342541
+1.290322581 7.419354839 13.516499633 11.594594595
+1.290322581 7.741935484 13.570706205 11.666666667
+1.290322581 8.064516129 13.570706205 11.666666667
+1.290322581 8.387096774 13.570706205 11.666666667
+1.290322581 8.709677419 13.570706205 11.666666667
+1.290322581 9.032258065 13.570706205 11.666666667
+1.290322581 9.354838710 13.570706205 11.666666667
+1.290322581 9.677419355 13.570706205 11.666666667
+1.290322581 10.000000000 13.570706205 11.666666667
+1.612903226 0.000000000 4.998950210 5.000000000
+1.612903226 0.322580645 4.998950210 5.000000000
+1.612903226 0.645161290 4.998950210 5.000000000
+1.612903226 0.967741935 4.998950210 5.000000000
+1.612903226 1.290322581 4.998950210 5.000000000
+1.612903226 1.612903226 4.998950210 5.000000000
+1.612903226 1.935483871 4.998950210 5.000000000
+1.612903226 2.258064516 4.998950210 5.000000000
+1.612903226 2.580645161 5.314026132 5.160000000
+1.612903226 2.903225806 6.467756859 5.775193798
+1.612903226 3.225806452 7.452789474 6.353383459
+1.612903226 3.548387097 8.316896407 6.897810219
+1.612903226 3.870967742 9.067963620 7.411347518
+1.612903226 4.193548387 9.734585733 7.896551724
+1.612903226 4.516129032 10.322182298 8.355704698
+1.612903226 4.838709677 10.846060307 8.790849673
+1.612903226 5.161290323 11.316227524 9.203821656
+1.612903226 5.483870968 11.733949841 9.596273292
+1.612903226 5.806451613 12.115369655 9.969696970
+1.612903226 6.129032258 12.452152483 10.325443787
+1.612903226 6.451612903 12.762450565 10.664739884
+1.612903226 6.774193548 13.037607639 10.988700565
+1.612903226 7.096774194 13.291172539 11.298342541
+1.612903226 7.419354839 13.516499633 11.594594595
+1.612903226 7.741935484 13.570706205 11.666666667
+1.612903226 8.064516129 13.570706205 11.666666667
+1.612903226 8.387096774 13.570706205 11.666666667
+1.612903226 8.709677419 13.570706205 11.666666667
+1.612903226 9.032258065 13.570706205 11.666666667
+1.612903226 9.354838710 13.570706205 11.666666667
+1.612903226 9.677419355 13.570706205 11.666666667
+1.612903226 10.000000000 13.570706205 11.666666667
+1.935483871 0.000000000 4.998950210 5.000000000
+1.935483871 0.322580645 4.998950210 5.000000000
+1.935483871 0.645161290 4.998950210 5.000000000
+1.935483871 0.967741935 4.998950210 5.000000000
+1.935483871 1.290322581 4.998950210 5.000000000
+1.935483871 1.612903226 4.998950210 5.000000000
+1.935483871 1.935483871 4.998950210 5.000000000
+1.935483871 2.258064516 4.998950210 5.000000000
+1.935483871 2.580645161 5.314026132 5.160000000
+1.935483871 2.903225806 6.467756859 5.775193798
+1.935483871 3.225806452 7.452789474 6.353383459
+1.935483871 3.548387097 8.316896407 6.897810219
+1.935483871 3.870967742 9.067963620 7.411347518
+1.935483871 4.193548387 9.734585733 7.896551724
+1.935483871 4.516129032 10.322182298 8.355704698
+1.935483871 4.838709677 10.846060307 8.790849673
+1.935483871 5.161290323 11.316227524 9.203821656
+1.935483871 5.483870968 11.733949841 9.596273292
+1.935483871 5.806451613 12.115369655 9.969696970
+1.935483871 6.129032258 12.452152483 10.325443787
+1.935483871 6.451612903 12.762450565 10.664739884
+1.935483871 6.774193548 13.037607639 10.988700565
+1.935483871 7.096774194 13.291172539 11.298342541
+1.935483871 7.419354839 13.516499633 11.594594595
+1.935483871 7.741935484 13.570706205 11.666666667
+1.935483871 8.064516129 13.570706205 11.666666667
+1.935483871 8.387096774 13.570706205 11.666666667
+1.935483871 8.709677419 13.570706205 11.666666667
+1.935483871 9.032258065 13.570706205 11.666666667
+1.935483871 9.354838710 13.570706205 11.666666667
+1.935483871 9.677419355 13.570706205 11.666666667
+1.935483871 10.000000000 13.570706205 11.666666667
+2.258064516 0.000000000 4.998950210 5.000000000
+2.258064516 0.322580645 4.998950210 5.000000000
+2.258064516 0.645161290 4.998950210 5.000000000
+2.258064516 0.967741935 4.998950210 5.000000000
+2.258064516 1.290322581 4.998950210 5.000000000
+2.258064516 1.612903226 4.998950210 5.000000000
+2.258064516 1.935483871 4.998950210 5.000000000
+2.258064516 2.258064516 4.998950210 5.000000000
+2.258064516 2.580645161 5.314026132 5.160000000
+2.258064516 2.903225806 6.467756859 5.775193798
+2.258064516 3.225806452 7.452789474 6.353383459
+2.258064516 3.548387097 8.316896407 6.897810219
+2.258064516 3.870967742 9.067963620 7.411347518
+2.258064516 4.193548387 9.734585733 7.896551724
+2.258064516 4.516129032 10.322182298 8.355704698
+2.258064516 4.838709677 10.846060307 8.790849673
+2.258064516 5.161290323 11.316227524 9.203821656
+2.258064516 5.483870968 11.733949841 9.596273292
+2.258064516 5.806451613 12.115369655 9.969696970
+2.258064516 6.129032258 12.452152483 10.325443787
+2.258064516 6.451612903 12.762450565 10.664739884
+2.258064516 6.774193548 13.037607639 10.988700565
+2.258064516 7.096774194 13.291172539 11.298342541
+2.258064516 7.419354839 13.516499633 11.594594595
+2.258064516 7.741935484 13.570706205 11.666666667
+2.258064516 8.064516129 13.570706205 11.666666667
+2.258064516 8.387096774 13.570706205 11.666666667
+2.258064516 8.709677419 13.570706205 11.666666667
+2.258064516 9.032258065 13.570706205 11.666666667
+2.258064516 9.354838710 13.570706205 11.666666667
+2.258064516 9.677419355 13.570706205 11.666666667
+2.258064516 10.000000000 13.570706205 11.666666667
+2.580645161 0.000000000 5.592761972 5.312500000
+2.580645161 0.322580645 5.592761972 5.312500000
+2.580645161 0.645161290 5.592761972 5.312500000
+2.580645161 0.967741935 5.592761972 5.312500000
+2.580645161 1.290322581 5.592761972 5.312500000
+2.580645161 1.612903226 5.592761972 5.312500000
+2.580645161 1.935483871 5.592761972 5.312500000
+2.580645161 2.258064516 5.592761972 5.312500000
+2.580645161 2.580645161 5.880621907 5.465349012
+2.580645161 2.903225806 6.939232958 6.055190858
+2.580645161 3.225806452 7.848835301 6.612674391
+2.580645161 3.548387097 8.651174558 7.140391254
+2.580645161 3.870967742 9.351975577 7.640663528
+2.580645161 4.193548387 9.976796931 8.115577889
+2.580645161 4.516129032 10.530004073 8.567014703
+2.580645161 4.838709677 11.024934815 8.996672905
+2.580645161 5.161290323 11.470583404 9.406091371
+2.580645161 5.483870968 11.867640871 9.796667328
+2.580645161 5.806451613 12.231162308 10.169672290
+2.580645161 6.129032258 12.552900008 10.526265883
+2.580645161 6.451612903 12.849986938 10.867507886
+2.580645161 6.774193548 13.113962484 11.194368756
+2.580645161 7.096774194 13.357668633 11.507738837
+2.580645161 7.419354839 13.574618159 11.808436465
+2.580645161 7.741935484 13.626860714 11.881720430
+2.580645161 8.064516129 13.626860714 11.881720430
+2.580645161 8.387096774 13.626860714 11.881720430
+2.580645161 8.709677419 13.626860714 11.881720430
+2.580645161 9.032258065 13.626860714 11.881720430
+2.580645161 9.354838710 13.626860714 11.881720430
+2.580645161 9.677419355 13.626860714 11.881720430
+2.580645161 10.000000000 13.626860714 11.881720430
+2.903225806 0.000000000 7.283786709 6.388888889
+2.903225806 0.322580645 7.283786709 6.388888889
+2.903225806 0.645161290 7.283786709 6.388888889
+2.903225806 0.967741935 7.283786709 6.388888889
+2.903225806 1.290322581 7.283786709 6.388888889
+2.903225806 1.612903226 7.283786709 6.388888889
+2.903225806 1.935483871 7.283786709 6.388888889
+2.903225806 2.258064516 7.283786709 6.388888889
+2.903225806 2.580645161 7.499955755 6.520624303
+2.903225806 2.903225806 8.305212731 7.035456336
+2.903225806 3.225806452 9.011457616 7.531699979
+2.903225806 3.548387097 9.645097856 8.010344100
+2.903225806 3.870967742 10.207136722 8.472308650
+2.903225806 4.193548387 10.715739625 8.918450561
+2.903225806 4.516129032 11.172892280 9.349569052
+2.903225806 4.838709677 11.587921940 9.766410408
+2.903225806 5.161290323 11.967183067 10.169672290
+2.903225806 5.483870968 12.308758298 10.560007632
+2.903225806 5.806451613 12.624644763 10.938028169
+2.903225806 6.129032258 12.908650399 11.304307635
+2.903225806 6.451612903 13.174140812 11.659384671
+2.903225806 6.774193548 13.414725347 12.003765465
+2.903225806 7.096774194 13.639701953 12.337926161
+2.903225806 7.419354839 13.842390029 12.662315057
+2.903225806 7.741935484 13.891460681 12.741935484
+2.903225806 8.064516129 13.891460681 12.741935484
+2.903225806 8.387096774 13.891460681 12.741935484
+2.903225806 8.709677419 13.891460681 12.741935484
+2.903225806 9.032258065 13.891460681 12.741935484
+2.903225806 9.354838710 13.891460681 12.741935484
+2.903225806 9.677419355 13.891460681 12.741935484
+2.903225806 10.000000000 13.891460681 12.741935484
+3.225806452 0.000000000 8.314651325 7.250000000
+3.225806452 0.322580645 8.314651325 7.250000000
+3.225806452 0.645161290 8.314651325 7.250000000
+3.225806452 0.967741935 8.314651325 7.250000000
+3.225806452 1.290322581 8.314651325 7.250000000
+3.225806452 1.612903226 8.314651325 7.250000000
+3.225806452 1.935483871 8.314651325 7.250000000
+3.225806452 2.258064516 8.314651325 7.250000000
+3.225806452 2.580645161 8.491360774 7.368791474
+3.225806452 2.903225806 9.156409155 7.837810945
+3.225806452 3.225806452 9.746803244 8.297222769
+3.225806452 3.548387097 10.284138020 8.747319166
+3.225806452 3.870967742 10.769427894 9.188380622
+3.225806452 4.193548387 11.214534071 9.620676476
+3.225806452 4.516129032 11.619323393 10.044465468
+3.225806452 4.838709677 11.993033266 10.459996253
+3.225806452 5.161290323 12.340224927 10.867507886
+3.225806452 5.483870968 12.657043434 11.267230289
+3.225806452 5.806451613 12.956823683 11.659384671
+3.225806452 6.129032258 13.232890780 12.044183950
+3.225806452 6.451612903 13.493168128 12.421833125
+3.225806452 6.774193548 13.734211054 12.792529651
+3.225806452 7.096774194 13.966630648 13.156463778
+3.225806452 7.419354839 14.180445683 13.513818877
+3.225806452 7.741935484 14.232664470 13.602150538
+3.225806452 8.064516129 14.232664470 13.602150538
+3.225806452 8.387096774 14.232664470 13.602150538
+3.225806452 8.709677419 14.232664470 13.602150538
+3.225806452 9.032258065 14.232664470 13.602150538
+3.225806452 9.354838710 14.232664470 13.602150538
+3.225806452 9.677419355 14.232664470 13.602150538
+3.225806452 10.000000000 14.232664470 13.602150538
+3.548387097 0.000000000 8.985030201 7.954545455
+3.548387097 0.322580645 8.985030201 7.954545455
+3.548387097 0.645161290 8.985030201 7.954545455
+3.548387097 0.967741935 8.985030201 7.954545455
+3.548387097 1.290322581 8.985030201 7.954545455
+3.548387097 1.612903226 8.985030201 7.954545455
+3.548387097 1.935483871 8.985030201 7.954545455
+3.548387097 2.258064516 8.985030201 7.954545455
+3.548387097 2.580645161 9.137812976 8.065372642
+3.548387097 2.903225806 9.717703976 8.506659369
+3.548387097 3.225806452 10.238351404 8.944737320
+3.548387097 3.548387097 10.720683414 9.379641369
+3.548387097 3.870967742 11.160003933 9.811405883
+3.548387097 4.193548387 11.571126024 10.240064737
+3.548387097 4.516129032 11.950914620 10.665651317
+3.548387097 4.838709677 12.307875007 11.088198536
+3.548387097 5.161290323 12.645356184 11.507738837
+3.548387097 5.483870968 12.960313946 11.924304201
+3.548387097 5.806451613 13.266478726 12.337926161
+3.548387097 6.129032258 13.551156560 12.748635804
+3.548387097 6.451612903 13.831439195 13.156463778
+3.548387097 6.774193548 14.095225315 13.561440308
+3.548387097 7.096774194 14.356367336 13.963595192
+3.548387097 7.419354839 14.605377743 14.362957820
+3.548387097 7.741935484 14.667921566 14.462365591
+3.548387097 8.064516129 14.667921566 14.462365591
+3.548387097 8.387096774 14.667921566 14.462365591
+3.548387097 8.709677419 14.667921566 14.462365591
+3.548387097 9.032258065 14.667921566 14.462365591
+3.548387097 9.354838710 14.667921566 14.462365591
+3.548387097 9.677419355 14.667921566 14.462365591
+3.548387097 10.000000000 14.667921566 14.462365591
+3.870967742 0.000000000 9.432393054 8.541666667
+3.870967742 0.322580645 9.432393054 8.541666667
+3.870967742 0.645161290 9.432393054 8.541666667
+3.870967742 0.967741935 9.432393054 8.541666667
+3.870967742 1.290322581 9.432393054 8.541666667
+3.870967742 1.612903226 9.432393054 8.541666667
+3.870967742 1.935483871 9.432393054 8.541666667
+3.870967742 2.258064516 9.432393054 8.541666667
+3.870967742 2.580645161 9.569971811 8.647671878
+3.870967742 2.903225806 10.095984031 9.072764022
+3.870967742 3.225806452 10.575695895 9.499578059
+3.870967742 3.548387097 11.024096907 9.928124472
+3.870967742 3.870967742 11.442347059 10.358413828
+3.870967742 4.193548387 11.836700132 10.790456784
+3.870967742 4.516129032 12.211639878 11.224264080
+3.870967742 4.838709677 12.568786873 11.659846547
+3.870967742 5.161290323 12.913995839 12.097215103
+3.870967742 5.483870968 13.247084242 12.536380757
+3.870967742 5.806451613 13.573370226 12.977354606
+3.870967742 6.129032258 13.891165979 13.420147843
+3.870967742 6.451612903 14.206686830 13.864771748
+3.870967742 6.774193548 14.518152082 14.311237701
+3.870967742 7.096774194 14.833264590 14.759557170
+3.870967742 7.419354839 15.145455566 15.209741723
+3.870967742 7.741935484 15.224455159 15.322580645
+3.870967742 8.064516129 15.224455159 15.322580645
+3.870967742 8.387096774 15.224455159 15.322580645
+3.870967742 8.709677419 15.224455159 15.322580645
+3.870967742 9.032258065 15.224455159 15.322580645
+3.870967742 9.354838710 15.224455159 15.322580645
+3.870967742 9.677419355 15.224455159 15.322580645
+3.870967742 10.000000000 15.224455159 15.322580645
+4.193548387 0.000000000 9.724829800 9.038461538
+4.193548387 0.322580645 9.724829800 9.038461538
+4.193548387 0.645161290 9.724829800 9.038461538
+4.193548387 0.967741935 9.724829800 9.038461538
+4.193548387 1.290322581 9.724829800 9.038461538
+4.193548387 1.612903226 9.724829800 9.038461538
+4.193548387 1.935483871 9.724829800 9.038461538
+4.193548387 2.258064516 9.724829800 9.038461538
+4.193548387 2.580645161 9.852943138 9.141680907
+4.193548387 2.903225806 10.345918352 9.558110433
+4.193548387 3.225806452 10.802543542 9.980311860
+4.193548387 3.548387097 11.235827387 10.408406027
+4.193548387 3.870967742 11.644759742 10.842517170
+4.193548387 4.193548387 12.040733478 11.282773042
+4.193548387 4.516129032 12.424030547 11.729305038
+4.193548387 4.838709677 12.796980884 12.182248328
+4.193548387 5.161290323 13.166426475 12.641741988
+4.193548387 5.483870968 13.531922324 13.107929151
+4.193548387 5.806451613 13.901663971 13.580957145
+4.193548387 6.129032258 14.268117073 14.060977658
+4.193548387 6.451612903 14.647562125 14.548146895
+4.193548387 6.774193548 15.033372347 15.042625746
+4.193548387 7.096774194 15.433721197 15.544579969
+4.193548387 7.419354839 15.846288602 16.054180370
+4.193548387 7.741935484 15.954652850 16.182795699
+4.193548387 8.064516129 15.954652850 16.182795699
+4.193548387 8.387096774 15.954652850 16.182795699
+4.193548387 8.709677419 15.954652850 16.182795699
+4.193548387 9.032258065 15.954652850 16.182795699
+4.193548387 9.354838710 15.954652850 16.182795699
+4.193548387 9.677419355 15.954652850 16.182795699
+4.193548387 10.000000000 15.954652850 16.182795699
+4.516129032 0.000000000 9.902963105 9.464285714
+4.516129032 0.322580645 9.902963105 9.464285714
+4.516129032 0.645161290 9.902963105 9.464285714
+4.516129032 0.967741935 9.902963105 9.464285714
+4.516129032 1.290322581 9.902963105 9.464285714
+4.516129032 1.612903226 9.902963105 9.464285714
+4.516129032 1.935483871 9.902963105 9.464285714
+4.516129032 2.258064516 9.902963105 9.464285714
+4.516129032 2.580645161 10.025672736 9.566064982
+4.516129032 2.903225806 10.500507438 9.978829026
+4.516129032 3.225806452 10.946239871 10.400856341
+4.516129032 3.548387097 11.376703200 10.832462297
+4.516129032 3.870967742 11.792259146 11.273976741
+4.516129032 4.193548387 12.201356693 11.725744843
+4.516129032 4.516129032 12.604952096 12.188127995
+4.516129032 4.838709677 13.008602620 12.661504771
+4.516129032 5.161290323 13.417792712 13.146271965
+4.516129032 5.483870968 13.834555987 13.642845698
+4.516129032 5.806451613 14.267444692 14.151662612
+4.516129032 6.129032258 14.713512788 14.673181146
+4.516129032 6.451612903 15.186143246 15.207882920
+4.516129032 6.774193548 15.682677037 15.756274213
+4.516129032 7.096774194 16.216113014 16.318887562
+4.516129032 7.419354839 16.788339244 16.896283492
+4.516129032 7.741935484 16.942283864 17.043010753
+4.516129032 8.064516129 16.942283864 17.043010753
+4.516129032 8.387096774 16.942283864 17.043010753
+4.516129032 8.709677419 16.942283864 17.043010753
+4.516129032 9.032258065 16.942283864 17.043010753
+4.516129032 9.354838710 16.942283864 17.043010753
+4.516129032 9.677419355 16.942283864 17.043010753
+4.516129032 10.000000000 16.942283864 17.043010753
+4.838709677 0.000000000 9.987593227 9.833333333
+4.838709677 0.322580645 9.987593227 9.833333333
+4.838709677 0.645161290 9.987593227 9.833333333
+4.838709677 0.967741935 9.987593227 9.833333333
+4.838709677 1.290322581 9.987593227 9.833333333
+4.838709677 1.612903226 9.987593227 9.833333333
+4.838709677 1.935483871 9.987593227 9.833333333
+4.838709677 2.258064516 9.987593227 9.833333333
+4.838709677 2.580645161 10.107937367 9.934574396
+4.838709677 2.903225806 10.576746882 10.347022587
+4.838709677 3.225806452 11.023190342 10.771849382
+4.838709677 3.548387097 11.461860178 11.209620539
+4.838709677 3.870967742 11.892974885 11.660936829
+4.838709677 4.193548387 12.326836015 12.126436782
+4.838709677 4.516129032 12.765557275 12.606799704
+4.838709677 4.838709677 13.215984335 13.102748986
+4.838709677 5.161290323 13.685165434 13.615055734
+4.838709677 5.483870968 14.175297225 14.144542773
+4.838709677 5.806451613 14.699676483 14.692089057
+4.838709677 6.129032258 15.258066385 15.258634538
+4.838709677 6.451612903 15.868732072 15.845185548
+4.838709677 6.774193548 16.535753191 16.452820769
+4.838709677 7.096774194 17.280236196 17.082697848
+4.838709677 7.419354839 18.115344324 17.736060763
+4.838709677 7.741935484 18.343399565 17.903225806
+4.838709677 8.064516129 18.343399565 17.903225806
+4.838709677 8.387096774 18.343399565 17.903225806
+4.838709677 8.709677419 18.343399565 17.903225806
+4.838709677 9.032258065 18.343399565 17.903225806
+4.838709677 9.354838710 18.343399565 17.903225806
+4.838709677 9.677419355 18.343399565 17.903225806
+4.838709677 10.000000000 18.343399565 17.903225806
+5.161290323 0.000000000 10.453438845 10.081967213
+5.161290323 0.322580645 10.453438845 10.081967213
+5.161290323 0.645161290 10.453438845 10.081967213
+5.161290323 0.967741935 10.453438845 10.081967213
+5.161290323 1.290322581 10.453438845 10.081967213
+5.161290323 1.612903226 10.453438845 10.081967213
+5.161290323 1.935483871 10.453438845 10.081967213
+5.161290323 2.258064516 10.453438845 10.081967213
+5.161290323 2.580645161 10.555334150 10.189117452
+5.161290323 2.903225806 10.957766893 10.626095161
+5.161290323 3.225806452 11.358194134 11.076954676
+5.161290323 3.548387097 11.754612081 11.542368165
+5.161290323 3.870967742 12.159885021 12.023051902
+5.161290323 4.193548387 12.572343139 12.519769950
+5.161290323 4.516129032 13.004157242 13.033338207
+5.161290323 4.838709677 13.454843261 13.564628886
+5.161290323 5.161290323 13.937409133 14.114575450
+5.161290323 5.483870968 14.453623313 14.684178093
+5.161290323 5.806451613 15.017597606 15.274509804
+5.161290323 6.129032258 15.634903956 15.886723119
+5.161290323 6.451612903 16.324245881 16.522057627
+5.161290323 6.774193548 17.100135640 17.181848349
+5.161290323 7.096774194 17.987899976 17.867535104
+5.161290323 7.419354839 19.013798273 18.580672994
+5.161290323 7.741935484 19.297725710 18.763440860
+5.161290323 8.064516129 19.297725710 18.763440860
+5.161290323 8.387096774 19.297725710 18.763440860
+5.161290323 8.709677419 19.297725710 18.763440860
+5.161290323 9.032258065 19.297725710 18.763440860
+5.161290323 9.354838710 19.297725710 18.763440860
+5.161290323 9.677419355 19.297725710 18.763440860
+5.161290323 10.000000000 19.297725710 18.763440860
+5.483870968 0.000000000 11.200371425 10.254237288
+5.483870968 0.322580645 11.200371425 10.254237288
+5.483870968 0.645161290 11.200371425 10.254237288
+5.483870968 0.967741935 11.200371425 10.254237288
+5.483870968 1.290322581 11.200371425 10.254237288
+5.483870968 1.612903226 11.200371425 10.254237288
+5.483870968 1.935483871 11.200371425 10.254237288
+5.483870968 2.258064516 11.200371425 10.254237288
+5.483870968 2.580645161 11.275744351 10.373748457
+5.483870968 2.903225806 11.579276776 10.860102906
+5.483870968 3.225806452 11.893660170 11.360174870
+5.483870968 3.548387097 12.214119876 11.874552997
+5.483870968 3.870967742 12.553283322 12.403860107
+5.483870968 4.193548387 12.907426182 12.948755706
+5.483870968 4.516129032 13.285781482 13.509938724
+5.483870968 4.838709677 13.693069775 14.088150508
+5.483870968 5.161290323 14.133110626 14.684178093
+5.483870968 5.483870968 14.617921843 15.298857769
+5.483870968 5.806451613 15.149780175 15.933079002
+5.483870968 6.129032258 15.746811487 16.587788726
+5.483870968 6.451612903 16.415017186 17.263996060
+5.483870968 6.774193548 17.180595436 17.962777500
+5.483870968 7.096774194 18.063069240 18.685282635
+5.483870968 7.419354839 19.094026165 19.432740459
+5.483870968 7.741935484 19.380891828 19.623655914
+5.483870968 8.064516129 19.380891828 19.623655914
+5.483870968 8.387096774 19.380891828 19.623655914
+5.483870968 8.709677419 19.380891828 19.623655914
+5.483870968 9.032258065 19.380891828 19.623655914
+5.483870968 9.354838710 19.380891828 19.623655914
+5.483870968 9.677419355 19.380891828 19.623655914
+5.483870968 10.000000000 19.380891828 19.623655914
+5.806451613 0.000000000 11.792304026 10.438596491
+5.806451613 0.322580645 11.792304026 10.438596491
+5.806451613 0.645161290 11.792304026 10.438596491
+5.806451613 0.967741935 11.792304026 10.438596491
+5.806451613 1.290322581 11.792304026 10.438596491
+5.806451613 1.612903226 11.792304026 10.438596491
+5.806451613 1.935483871 11.792304026 10.438596491
+5.806451613 2.258064516 11.792304026 10.438596491
+5.806451613 2.580645161 11.848083932 10.571165035
+5.806451613 2.903225806 12.077812184 11.109435588
+5.806451613 3.225806452 12.327537589 11.660851868
+5.806451613 3.548387097 12.590635013 12.225901398
+5.806451613 3.870967742 12.875627326 12.805096111
+5.806451613 4.193548387 13.187716001 13.398973895
+5.806451613 4.516129032 13.525122531 14.008100260
+5.806451613 4.838709677 13.897938757 14.633070135
+5.806451613 5.161290323 14.310798618 15.274509804
+5.806451613 5.483870968 14.768759505 15.933079002
+5.806451613 5.806451613 15.285527581 16.609473175
+5.806451613 6.129032258 15.867812510 17.304425935
+5.806451613 6.451612903 16.531661050 18.018711707
+5.806451613 6.774193548 17.302903875 18.753148615
+5.806451613 7.096774194 18.198839735 19.508601601
+5.806451613 7.419354839 19.260035649 20.285985830
+5.806451613 7.741935484 19.557269007 20.483870968
+5.806451613 8.064516129 19.557269007 20.483870968
+5.806451613 8.387096774 19.557269007 20.483870968
+5.806451613 8.709677419 19.557269007 20.483870968
+5.806451613 9.032258065 19.557269007 20.483870968
+5.806451613 9.354838710 19.557269007 20.483870968
+5.806451613 9.677419355 19.557269007 20.483870968
+5.806451613 10.000000000 19.557269007 20.483870968
+6.129032258 0.000000000 12.272218993 10.636363636
+6.129032258 0.322580645 12.272218993 10.636363636
+6.129032258 0.645161290 12.272218993 10.636363636
+6.129032258 0.967741935 12.272218993 10.636363636
+6.129032258 1.290322581 12.272218993 10.636363636
+6.129032258 1.612903226 12.272218993 10.636363636
+6.129032258 1.935483871 12.272218993 10.636363636
+6.129032258 2.258064516 12.272218993 10.636363636
+6.129032258 2.580645161 12.312912957 10.782742908
+6.129032258 2.903225806 12.485719838 11.375649592
+6.129032258 3.225806452 12.683802558 11.980650967
+6.129032258 3.548387097 12.903346192 12.598120927
+6.129032258 3.870967742 13.148207675 13.228448936
+6.129032258 4.193548387 13.424397092 13.872040848
+6.129032258 4.516129032 13.734709260 14.529319781
+6.129032258 4.838709677 14.081175133 15.200727043
+6.129032258 5.161290323 14.472910716 15.886723119
+6.129032258 5.483870968 14.920581746 16.587788726
+6.129032258 5.806451613 15.427041299 17.304425935
+6.129032258 6.129032258 16.008438809 18.037159372
+6.129032258 6.451612903 16.684191565 18.786537498
+6.129032258 6.774193548 17.475450862 19.553133975
+6.129032258 7.096774194 18.410291448 20.337549137
+6.129032258 7.419354839 19.533529202 21.140411551
+6.129032258 7.741935484 19.850782228 21.344086022
+6.129032258 8.064516129 19.850782228 21.344086022
+6.129032258 8.387096774 19.850782228 21.344086022
+6.129032258 8.709677419 19.850782228 21.344086022
+6.129032258 9.032258065 19.850782228 21.344086022
+6.129032258 9.354838710 19.850782228 21.344086022
+6.129032258 9.677419355 19.850782228 21.344086022
+6.129032258 10.000000000 19.850782228 21.344086022
+6.451612903 0.000000000 12.667715960 10.849056604
+6.451612903 0.322580645 12.667715960 10.849056604
+6.451612903 0.645161290 12.667715960 10.849056604
+6.451612903 0.967741935 12.667715960 10.849056604
+6.451612903 1.290322581 12.667715960 10.849056604
+6.451612903 1.612903226 12.667715960 10.849056604
+6.451612903 1.935483871 12.667715960 10.849056604
+6.451612903 2.258064516 12.667715960 10.849056604
+6.451612903 2.580645161 12.695732249 11.010062510
+6.451612903 2.903225806 12.824135659 11.660519441
+6.451612903 3.225806452 12.981327533 12.321456235
+6.451612903 3.548387097 13.167148134 12.993128221
+6.451612903 3.870967742 13.381921080 13.675799087
+6.451612903 4.193548387 13.630079770 14.369741229
+6.451612903 4.516129032 13.917888750 15.075236113
+6.451612903 4.838709677 14.251097627 15.792574657
+6.451612903 5.161290323 14.632147614 16.522057627
+6.451612903 5.483870968 15.072735735 17.263996060
+6.451612903 5.806451613 15.583881738 18.018711707
+6.451612903 6.129032258 16.182136955 18.786537498
+6.451612903 6.451612903 16.899235777 19.567818029
+6.451612903 6.774193548 17.840675551 20.362910080
+6.451612903 7.096774194 18.923022827 21.172183159
+6.451612903 7.419354839 20.191498874 21.996020073
+6.451612903 7.741935484 20.543702253 22.204301075
+6.451612903 8.064516129 20.543702253 22.204301075
+6.451612903 8.387096774 20.543702253 22.204301075
+6.451612903 8.709677419 20.543702253 22.204301075
+6.451612903 9.032258065 20.543702253 22.204301075
+6.451612903 9.354838710 20.543702253 22.204301075
+6.451612903 9.677419355 20.543702253 22.204301075
+6.451612903 10.000000000 20.543702253 22.204301075
+6.774193548 0.000000000 12.998209351 11.078431373
+6.774193548 0.322580645 12.998209351 11.078431373
+6.774193548 0.645161290 12.998209351 11.078431373
+6.774193548 0.967741935 12.998209351 11.078431373
+6.774193548 1.290322581 12.998209351 11.078431373
+6.774193548 1.612903226 12.998209351 11.078431373
+6.774193548 1.935483871 12.998209351 11.078431373
+6.774193548 2.258064516 12.998209351 11.078431373
+6.774193548 2.580645161 13.016700861 11.254948535
+6.774193548 2.903225806 13.109051400 11.966077401
+6.774193548 3.225806452 13.233524203 12.685407657
+6.774193548 3.548387097 13.391742155 13.413082004
+6.774193548 3.870967742 13.584206097 14.149246475
+6.774193548 4.193548387 13.814318448 14.894050530
+6.774193548 4.516129032 14.087835159 15.647647155
+6.774193548 4.838709677 14.410179185 16.410192974
+6.774193548 5.161290323 14.791181858 17.181848349
+6.774193548 5.483870968 15.241218368 17.962777500
+6.774193548 5.806451613 15.875517713 18.753148615
+6.774193548 6.129032258 16.681146859 19.553133975
+6.774193548 6.451612903 17.569488681 20.362910080
+6.774193548 6.774193548 18.574163704 21.182657773
+6.774193548 7.096774194 19.734151545 22.012562382
+6.774193548 7.419354839 21.103510509 22.852813853
+6.774193548 7.741935484 21.487304165 23.064516129
+6.774193548 8.064516129 21.487304165 23.064516129
+6.774193548 8.387096774 21.487304165 23.064516129
+6.774193548 8.709677419 21.487304165 23.064516129
+6.774193548 9.032258065 21.487304165 23.064516129
+6.774193548 9.354838710 21.487304165 23.064516129
+6.774193548 9.677419355 21.487304165 23.064516129
+6.774193548 10.000000000 21.487304165 23.064516129
+7.096774194 0.000000000 13.277885841 11.326530612
+7.096774194 0.322580645 13.277885841 11.326530612
+7.096774194 0.645161290 13.277885841 11.326530612
+7.096774194 0.967741935 13.277885841 11.326530612
+7.096774194 1.290322581 13.277885841 11.326530612
+7.096774194 1.612903226 13.277885841 11.326530612
+7.096774194 1.935483871 13.277885841 11.326530612
+7.096774194 2.258064516 13.277885841 11.326530612
+7.096774194 2.580645161 13.288352640 11.519519025
+7.096774194 2.903225806 13.350771800 12.294662039
+7.096774194 3.225806452 13.448963305 13.074946112
+7.096774194 3.548387097 13.584671491 13.860422559
+7.096774194 3.870967742 13.760664445 14.651143382
+7.096774194 4.193548387 13.980902626 15.447161280
+7.096774194 4.516129032 14.249972519 16.248529659
+7.096774194 4.838709677 14.574475539 17.055302647
+7.096774194 5.161290323 14.966122630 17.867535104
+7.096774194 5.483870968 15.630163357 18.685282635
+7.096774194 5.806451613 16.437215216 19.508601601
+7.096774194 6.129032258 17.309323446 20.337549137
+7.096774194 6.451612903 18.275865243 21.172183159
+7.096774194 6.774193548 19.378378532 22.012562382
+7.096774194 7.096774194 20.668439101 22.858746331
+7.096774194 7.419354839 22.225144822 23.710795356
+7.096774194 7.741935484 22.668948283 23.924731183
+7.096774194 8.064516129 22.668948283 23.924731183
+7.096774194 8.387096774 22.668948283 23.924731183
+7.096774194 8.709677419 22.668948283 23.924731183
+7.096774194 9.032258065 22.668948283 23.924731183
+7.096774194 9.354838710 22.668948283 23.924731183
+7.096774194 9.677419355 22.668948283 23.924731183
+7.096774194 10.000000000 22.668948283 23.924731183
+7.419354839 0.000000000 13.515825784 11.595744681
+7.419354839 0.322580645 13.515825784 11.595744681
+7.419354839 0.645161290 13.515825784 11.595744681
+7.419354839 0.967741935 13.515825784 11.595744681
+7.419354839 1.290322581 13.515825784 11.595744681
+7.419354839 1.612903226 13.515825784 11.595744681
+7.419354839 1.935483871 13.515825784 11.595744681
+7.419354839 2.258064516 13.515825784 11.595744681
+7.419354839 2.580645161 13.519282293 11.806246782
+7.419354839 2.903225806 13.556279203 12.648978190
+7.419354839 3.225806452 13.633565239 13.492868190
+7.419354839 3.548387097 13.753168201 14.337919175
+7.419354839 3.870967742 13.918417774 15.184133540
+7.419354839 4.193548387 14.134193279 16.031513690
+7.419354839 4.516129032 14.407312339 16.880062037
+7.419354839 4.838709677 14.747121823 17.729780997
+7.419354839 5.161290323 15.312289393 18.580672994
+7.419354839 5.483870968 16.162307388 19.432740459
+7.419354839 5.806451613 17.055699946 20.285985830
+7.419354839 6.129032258 18.025108663 21.140411551
+7.419354839 6.451612903 19.112532086 21.996020073
+7.419354839 6.774193548 20.379272817 22.852813853
+7.419354839 7.096774194 21.908521849 23.710795356
+7.419354839 7.419354839 23.837396065 24.569967054
+7.419354839 7.741935484 24.406429743 24.784946237
+7.419354839 8.064516129 24.406429743 24.784946237
+7.419354839 8.387096774 24.406429743 24.784946237
+7.419354839 8.709677419 24.406429743 24.784946237
+7.419354839 9.032258065 24.406429743 24.784946237
+7.419354839 9.354838710 24.406429743 24.784946237
+7.419354839 9.677419355 24.406429743 24.784946237
+7.419354839 10.000000000 24.406429743 24.784946237
+7.741935484 0.000000000 13.570706205 11.666666667
+7.741935484 0.322580645 13.570706205 11.666666667
+7.741935484 0.645161290 13.570706205 11.666666667
+7.741935484 0.967741935 13.570706205 11.666666667
+7.741935484 1.290322581 13.570706205 11.666666667
+7.741935484 1.612903226 13.570706205 11.666666667
+7.741935484 1.935483871 13.570706205 11.666666667
+7.741935484 2.258064516 13.570706205 11.666666667
+7.741935484 2.580645161 13.572517919 11.881720430
+7.741935484 2.903225806 13.603707815 12.741935484
+7.741935484 3.225806452 13.676532623 13.602150538
+7.741935484 3.548387097 13.793124575 14.462365591
+7.741935484 3.870967742 13.957010447 15.322580645
+7.741935484 4.193548387 14.173387937 16.182795699
+7.741935484 4.516129032 14.449561083 17.043010753
+7.741935484 4.838709677 14.795606896 17.903225806
+7.741935484 5.161290323 15.430252399 18.763440860
+7.741935484 5.483870968 16.305345082 19.623655914
+7.741935484 5.806451613 17.225621817 20.483870968
+7.741935484 6.129032258 18.227035950 21.344086022
+7.741935484 6.451612903 19.356366279 22.204301075
+7.741935484 6.774193548 20.682807170 23.064516129
+7.741935484 7.096774194 22.303013754 23.924731183
+7.741935484 7.419354839 24.380408194 24.784946237
+7.741935484 7.741935484 25.001049790 25.000000000
+7.741935484 8.064516129 25.001049790 25.000000000
+7.741935484 8.387096774 25.001049790 25.000000000
+7.741935484 8.709677419 25.001049790 25.000000000
+7.741935484 9.032258065 25.001049790 25.000000000
+7.741935484 9.354838710 25.001049790 25.000000000
+7.741935484 9.677419355 25.001049790 25.000000000
+7.741935484 10.000000000 25.001049790 25.000000000
+8.064516129 0.000000000 13.570706205 11.666666667
+8.064516129 0.322580645 13.570706205 11.666666667
+8.064516129 0.645161290 13.570706205 11.666666667
+8.064516129 0.967741935 13.570706205 11.666666667
+8.064516129 1.290322581 13.570706205 11.666666667
+8.064516129 1.612903226 13.570706205 11.666666667
+8.064516129 1.935483871 13.570706205 11.666666667
+8.064516129 2.258064516 13.570706205 11.666666667
+8.064516129 2.580645161 13.572517919 11.881720430
+8.064516129 2.903225806 13.603707815 12.741935484
+8.064516129 3.225806452 13.676532623 13.602150538
+8.064516129 3.548387097 13.793124575 14.462365591
+8.064516129 3.870967742 13.957010447 15.322580645
+8.064516129 4.193548387 14.173387937 16.182795699
+8.064516129 4.516129032 14.449561083 17.043010753
+8.064516129 4.838709677 14.795606896 17.903225806
+8.064516129 5.161290323 15.430252399 18.763440860
+8.064516129 5.483870968 16.305345082 19.623655914
+8.064516129 5.806451613 17.225621817 20.483870968
+8.064516129 6.129032258 18.227035950 21.344086022
+8.064516129 6.451612903 19.356366279 22.204301075
+8.064516129 6.774193548 20.682807170 23.064516129
+8.064516129 7.096774194 22.303013754 23.924731183
+8.064516129 7.419354839 24.380408194 24.784946237
+8.064516129 7.741935484 25.001049790 25.000000000
+8.064516129 8.064516129 25.001049790 25.000000000
+8.064516129 8.387096774 25.001049790 25.000000000
+8.064516129 8.709677419 25.001049790 25.000000000
+8.064516129 9.032258065 25.001049790 25.000000000
+8.064516129 9.354838710 25.001049790 25.000000000
+8.064516129 9.677419355 25.001049790 25.000000000
+8.064516129 10.000000000 25.001049790 25.000000000
+8.387096774 0.000000000 13.570706205 11.666666667
+8.387096774 0.322580645 13.570706205 11.666666667
+8.387096774 0.645161290 13.570706205 11.666666667
+8.387096774 0.967741935 13.570706205 11.666666667
+8.387096774 1.290322581 13.570706205 11.666666667
+8.387096774 1.612903226 13.570706205 11.666666667
+8.387096774 1.935483871 13.570706205 11.666666667
+8.387096774 2.258064516 13.570706205 11.666666667
+8.387096774 2.580645161 13.572517919 11.881720430
+8.387096774 2.903225806 13.603707815 12.741935484
+8.387096774 3.225806452 13.676532623 13.602150538
+8.387096774 3.548387097 13.793124575 14.462365591
+8.387096774 3.870967742 13.957010447 15.322580645
+8.387096774 4.193548387 14.173387937 16.182795699
+8.387096774 4.516129032 14.449561083 17.043010753
+8.387096774 4.838709677 14.795606896 17.903225806
+8.387096774 5.161290323 15.430252399 18.763440860
+8.387096774 5.483870968 16.305345082 19.623655914
+8.387096774 5.806451613 17.225621817 20.483870968
+8.387096774 6.129032258 18.227035950 21.344086022
+8.387096774 6.451612903 19.356366279 22.204301075
+8.387096774 6.774193548 20.682807170 23.064516129
+8.387096774 7.096774194 22.303013754 23.924731183
+8.387096774 7.419354839 24.380408194 24.784946237
+8.387096774 7.741935484 25.001049790 25.000000000
+8.387096774 8.064516129 25.001049790 25.000000000
+8.387096774 8.387096774 25.001049790 25.000000000
+8.387096774 8.709677419 25.001049790 25.000000000
+8.387096774 9.032258065 25.001049790 25.000000000
+8.387096774 9.354838710 25.001049790 25.000000000
+8.387096774 9.677419355 25.001049790 25.000000000
+8.387096774 10.000000000 25.001049790 25.000000000
+8.709677419 0.000000000 13.570706205 11.666666667
+8.709677419 0.322580645 13.570706205 11.666666667
+8.709677419 0.645161290 13.570706205 11.666666667
+8.709677419 0.967741935 13.570706205 11.666666667
+8.709677419 1.290322581 13.570706205 11.666666667
+8.709677419 1.612903226 13.570706205 11.666666667
+8.709677419 1.935483871 13.570706205 11.666666667
+8.709677419 2.258064516 13.570706205 11.666666667
+8.709677419 2.580645161 13.572517919 11.881720430
+8.709677419 2.903225806 13.603707815 12.741935484
+8.709677419 3.225806452 13.676532623 13.602150538
+8.709677419 3.548387097 13.793124575 14.462365591
+8.709677419 3.870967742 13.957010447 15.322580645
+8.709677419 4.193548387 14.173387937 16.182795699
+8.709677419 4.516129032 14.449561083 17.043010753
+8.709677419 4.838709677 14.795606896 17.903225806
+8.709677419 5.161290323 15.430252399 18.763440860
+8.709677419 5.483870968 16.305345082 19.623655914
+8.709677419 5.806451613 17.225621817 20.483870968
+8.709677419 6.129032258 18.227035950 21.344086022
+8.709677419 6.451612903 19.356366279 22.204301075
+8.709677419 6.774193548 20.682807170 23.064516129
+8.709677419 7.096774194 22.303013754 23.924731183
+8.709677419 7.419354839 24.380408194 24.784946237
+8.709677419 7.741935484 25.001049790 25.000000000
+8.709677419 8.064516129 25.001049790 25.000000000
+8.709677419 8.387096774 25.001049790 25.000000000
+8.709677419 8.709677419 25.001049790 25.000000000
+8.709677419 9.032258065 25.001049790 25.000000000
+8.709677419 9.354838710 25.001049790 25.000000000
+8.709677419 9.677419355 25.001049790 25.000000000
+8.709677419 10.000000000 25.001049790 25.000000000
+9.032258065 0.000000000 13.570706205 11.666666667
+9.032258065 0.322580645 13.570706205 11.666666667
+9.032258065 0.645161290 13.570706205 11.666666667
+9.032258065 0.967741935 13.570706205 11.666666667
+9.032258065 1.290322581 13.570706205 11.666666667
+9.032258065 1.612903226 13.570706205 11.666666667
+9.032258065 1.935483871 13.570706205 11.666666667
+9.032258065 2.258064516 13.570706205 11.666666667
+9.032258065 2.580645161 13.572517919 11.881720430
+9.032258065 2.903225806 13.603707815 12.741935484
+9.032258065 3.225806452 13.676532623 13.602150538
+9.032258065 3.548387097 13.793124575 14.462365591
+9.032258065 3.870967742 13.957010447 15.322580645
+9.032258065 4.193548387 14.173387937 16.182795699
+9.032258065 4.516129032 14.449561083 17.043010753
+9.032258065 4.838709677 14.795606896 17.903225806
+9.032258065 5.161290323 15.430252399 18.763440860
+9.032258065 5.483870968 16.305345082 19.623655914
+9.032258065 5.806451613 17.225621817 20.483870968
+9.032258065 6.129032258 18.227035950 21.344086022
+9.032258065 6.451612903 19.356366279 22.204301075
+9.032258065 6.774193548 20.682807170 23.064516129
+9.032258065 7.096774194 22.303013754 23.924731183
+9.032258065 7.419354839 24.380408194 24.784946237
+9.032258065 7.741935484 25.001049790 25.000000000
+9.032258065 8.064516129 25.001049790 25.000000000
+9.032258065 8.387096774 25.001049790 25.000000000
+9.032258065 8.709677419 25.001049790 25.000000000
+9.032258065 9.032258065 25.001049790 25.000000000
+9.032258065 9.354838710 25.001049790 25.000000000
+9.032258065 9.677419355 25.001049790 25.000000000
+9.032258065 10.000000000 25.001049790 25.000000000
+9.354838710 0.000000000 13.570706205 11.666666667
+9.354838710 0.322580645 13.570706205 11.666666667
+9.354838710 0.645161290 13.570706205 11.666666667
+9.354838710 0.967741935 13.570706205 11.666666667
+9.354838710 1.290322581 13.570706205 11.666666667
+9.354838710 1.612903226 13.570706205 11.666666667
+9.354838710 1.935483871 13.570706205 11.666666667
+9.354838710 2.258064516 13.570706205 11.666666667
+9.354838710 2.580645161 13.572517919 11.881720430
+9.354838710 2.903225806 13.603707815 12.741935484
+9.354838710 3.225806452 13.676532623 13.602150538
+9.354838710 3.548387097 13.793124575 14.462365591
+9.354838710 3.870967742 13.957010447 15.322580645
+9.354838710 4.193548387 14.173387937 16.182795699
+9.354838710 4.516129032 14.449561083 17.043010753
+9.354838710 4.838709677 14.795606896 17.903225806
+9.354838710 5.161290323 15.430252399 18.763440860
+9.354838710 5.483870968 16.305345082 19.623655914
+9.354838710 5.806451613 17.225621817 20.483870968
+9.354838710 6.129032258 18.227035950 21.344086022
+9.354838710 6.451612903 19.356366279 22.204301075
+9.354838710 6.774193548 20.682807170 23.064516129
+9.354838710 7.096774194 22.303013754 23.924731183
+9.354838710 7.419354839 24.380408194 24.784946237
+9.354838710 7.741935484 25.001049790 25.000000000
+9.354838710 8.064516129 25.001049790 25.000000000
+9.354838710 8.387096774 25.001049790 25.000000000
+9.354838710 8.709677419 25.001049790 25.000000000
+9.354838710 9.032258065 25.001049790 25.000000000
+9.354838710 9.354838710 25.001049790 25.000000000
+9.354838710 9.677419355 25.001049790 25.000000000
+9.354838710 10.000000000 25.001049790 25.000000000
+9.677419355 0.000000000 13.570706205 11.666666667
+9.677419355 0.322580645 13.570706205 11.666666667
+9.677419355 0.645161290 13.570706205 11.666666667
+9.677419355 0.967741935 13.570706205 11.666666667
+9.677419355 1.290322581 13.570706205 11.666666667
+9.677419355 1.612903226 13.570706205 11.666666667
+9.677419355 1.935483871 13.570706205 11.666666667
+9.677419355 2.258064516 13.570706205 11.666666667
+9.677419355 2.580645161 13.572517919 11.881720430
+9.677419355 2.903225806 13.603707815 12.741935484
+9.677419355 3.225806452 13.676532623 13.602150538
+9.677419355 3.548387097 13.793124575 14.462365591
+9.677419355 3.870967742 13.957010447 15.322580645
+9.677419355 4.193548387 14.173387937 16.182795699
+9.677419355 4.516129032 14.449561083 17.043010753
+9.677419355 4.838709677 14.795606896 17.903225806
+9.677419355 5.161290323 15.430252399 18.763440860
+9.677419355 5.483870968 16.305345082 19.623655914
+9.677419355 5.806451613 17.225621817 20.483870968
+9.677419355 6.129032258 18.227035950 21.344086022
+9.677419355 6.451612903 19.356366279 22.204301075
+9.677419355 6.774193548 20.682807170 23.064516129
+9.677419355 7.096774194 22.303013754 23.924731183
+9.677419355 7.419354839 24.380408194 24.784946237
+9.677419355 7.741935484 25.001049790 25.000000000
+9.677419355 8.064516129 25.001049790 25.000000000
+9.677419355 8.387096774 25.001049790 25.000000000
+9.677419355 8.709677419 25.001049790 25.000000000
+9.677419355 9.032258065 25.001049790 25.000000000
+9.677419355 9.354838710 25.001049790 25.000000000
+9.677419355 9.677419355 25.001049790 25.000000000
+9.677419355 10.000000000 25.001049790 25.000000000
+10.000000000 0.000000000 13.570706205 11.666666667
+10.000000000 0.322580645 13.570706205 11.666666667
+10.000000000 0.645161290 13.570706205 11.666666667
+10.000000000 0.967741935 13.570706205 11.666666667
+10.000000000 1.290322581 13.570706205 11.666666667
+10.000000000 1.612903226 13.570706205 11.666666667
+10.000000000 1.935483871 13.570706205 11.666666667
+10.000000000 2.258064516 13.570706205 11.666666667
+10.000000000 2.580645161 13.572517919 11.881720430
+10.000000000 2.903225806 13.603707815 12.741935484
+10.000000000 3.225806452 13.676532623 13.602150538
+10.000000000 3.548387097 13.793124575 14.462365591
+10.000000000 3.870967742 13.957010447 15.322580645
+10.000000000 4.193548387 14.173387937 16.182795699
+10.000000000 4.516129032 14.449561083 17.043010753
+10.000000000 4.838709677 14.795606896 17.903225806
+10.000000000 5.161290323 15.430252399 18.763440860
+10.000000000 5.483870968 16.305345082 19.623655914
+10.000000000 5.806451613 17.225621817 20.483870968
+10.000000000 6.129032258 18.227035950 21.344086022
+10.000000000 6.451612903 19.356366279 22.204301075
+10.000000000 6.774193548 20.682807170 23.064516129
+10.000000000 7.096774194 22.303013754 23.924731183
+10.000000000 7.419354839 24.380408194 24.784946237
+10.000000000 7.741935484 25.001049790 25.000000000
+10.000000000 8.064516129 25.001049790 25.000000000
+10.000000000 8.387096774 25.001049790 25.000000000
+10.000000000 8.709677419 25.001049790 25.000000000
+10.000000000 9.032258065 25.001049790 25.000000000
+10.000000000 9.354838710 25.001049790 25.000000000
+10.000000000 9.677419355 25.001049790 25.000000000
+10.000000000 10.000000000 25.001049790 25.000000000
diff --git a/examples/hybrid/tipper.fll b/examples/hybrid/tipper.fll
new file mode 100644
index 0000000..cb8803f
--- /dev/null
+++ b/examples/hybrid/tipper.fll
@@ -0,0 +1,63 @@
+Engine: tipper
+description: (service and food) -> (tip)
+InputVariable: service
+ description: quality of service
+ enabled: true
+ range: 0.000 10.000
+ lock-range: true
+ term: poor Trapezoid 0.000 0.000 2.500 5.000
+ term: good Triangle 2.500 5.000 7.500
+ term: excellent Trapezoid 5.000 7.500 10.000 10.000
+InputVariable: food
+ description: quality of food
+ enabled: true
+ range: 0.000 10.000
+ lock-range: true
+ term: rancid Trapezoid 0.000 0.000 2.500 7.500
+ term: delicious Trapezoid 2.500 7.500 10.000 10.000
+OutputVariable: mTip
+ description: tip based on Mamdani inference
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: cheap Triangle 0.000 5.000 10.000
+ term: average Triangle 10.000 15.000 20.000
+ term: generous Triangle 20.000 25.000 30.000
+OutputVariable: tsTip
+ description: tip based on Takagi-Sugeno inference
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: cheap Constant 5.000
+ term: average Constant 15.000
+ term: generous Constant 25.000
+RuleBlock: mamdani
+ description: Mamdani inference
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: AlgebraicSum
+ implication: Minimum
+ activation: General
+ rule: if service is poor or food is rancid then mTip is cheap
+ rule: if service is good then mTip is average
+ rule: if service is excellent or food is delicious then mTip is generous with 0.5
+ rule: if service is excellent and food is delicious then mTip is generous with 1.0
+RuleBlock: takagiSugeno
+ description: Takagi-Sugeno inference
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: AlgebraicSum
+ implication: none
+ activation: General
+ rule: if service is poor or food is rancid then tsTip is cheap
+ rule: if service is good then tsTip is average
+ rule: if service is excellent or food is delicious then tsTip is generous with 0.5
+ rule: if service is excellent and food is delicious then tsTip is generous with 1.0 \ No newline at end of file
diff --git a/examples/hybrid/tipper.java b/examples/hybrid/tipper.java
new file mode 100644
index 0000000..e0578ca
--- /dev/null
+++ b/examples/hybrid/tipper.java
@@ -0,0 +1,103 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class tipper{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("tipper");
+engine.setDescription("(service and food) -> (tip)");
+
+InputVariable service = new InputVariable();
+service.setName("service");
+service.setDescription("quality of service");
+service.setEnabled(true);
+service.setRange(0.000, 10.000);
+service.setLockValueInRange(true);
+service.addTerm(new Trapezoid("poor", 0.000, 0.000, 2.500, 5.000));
+service.addTerm(new Triangle("good", 2.500, 5.000, 7.500));
+service.addTerm(new Trapezoid("excellent", 5.000, 7.500, 10.000, 10.000));
+engine.addInputVariable(service);
+
+InputVariable food = new InputVariable();
+food.setName("food");
+food.setDescription("quality of food");
+food.setEnabled(true);
+food.setRange(0.000, 10.000);
+food.setLockValueInRange(true);
+food.addTerm(new Trapezoid("rancid", 0.000, 0.000, 2.500, 7.500));
+food.addTerm(new Trapezoid("delicious", 2.500, 7.500, 10.000, 10.000));
+engine.addInputVariable(food);
+
+OutputVariable mTip = new OutputVariable();
+mTip.setName("mTip");
+mTip.setDescription("tip based on Mamdani inference");
+mTip.setEnabled(true);
+mTip.setRange(0.000, 30.000);
+mTip.setLockValueInRange(false);
+mTip.setAggregation(new Maximum());
+mTip.setDefuzzifier(new Centroid(100));
+mTip.setDefaultValue(Double.NaN);
+mTip.setLockPreviousValue(false);
+mTip.addTerm(new Triangle("cheap", 0.000, 5.000, 10.000));
+mTip.addTerm(new Triangle("average", 10.000, 15.000, 20.000));
+mTip.addTerm(new Triangle("generous", 20.000, 25.000, 30.000));
+engine.addOutputVariable(mTip);
+
+OutputVariable tsTip = new OutputVariable();
+tsTip.setName("tsTip");
+tsTip.setDescription("tip based on Takagi-Sugeno inference");
+tsTip.setEnabled(true);
+tsTip.setRange(0.000, 30.000);
+tsTip.setLockValueInRange(false);
+tsTip.setAggregation(null);
+tsTip.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+tsTip.setDefaultValue(Double.NaN);
+tsTip.setLockPreviousValue(false);
+tsTip.addTerm(new Constant("cheap", 5.000));
+tsTip.addTerm(new Constant("average", 15.000));
+tsTip.addTerm(new Constant("generous", 25.000));
+engine.addOutputVariable(tsTip);
+
+RuleBlock mamdani = new RuleBlock();
+mamdani.setName("mamdani");
+mamdani.setDescription("Mamdani inference");
+mamdani.setEnabled(true);
+mamdani.setConjunction(new AlgebraicProduct());
+mamdani.setDisjunction(new AlgebraicSum());
+mamdani.setImplication(new Minimum());
+mamdani.setActivation(new General());
+mamdani.addRule(Rule.parse("if service is poor or food is rancid then mTip is cheap", engine));
+mamdani.addRule(Rule.parse("if service is good then mTip is average", engine));
+mamdani.addRule(Rule.parse("if service is excellent or food is delicious then mTip is generous with 0.5", engine));
+mamdani.addRule(Rule.parse("if service is excellent and food is delicious then mTip is generous with 1.0", engine));
+engine.addRuleBlock(mamdani);
+
+RuleBlock takagiSugeno = new RuleBlock();
+takagiSugeno.setName("takagiSugeno");
+takagiSugeno.setDescription("Takagi-Sugeno inference");
+takagiSugeno.setEnabled(true);
+takagiSugeno.setConjunction(new AlgebraicProduct());
+takagiSugeno.setDisjunction(new AlgebraicSum());
+takagiSugeno.setImplication(null);
+takagiSugeno.setActivation(new General());
+takagiSugeno.addRule(Rule.parse("if service is poor or food is rancid then tsTip is cheap", engine));
+takagiSugeno.addRule(Rule.parse("if service is good then tsTip is average", engine));
+takagiSugeno.addRule(Rule.parse("if service is excellent or food is delicious then tsTip is generous with 0.5", engine));
+takagiSugeno.addRule(Rule.parse("if service is excellent and food is delicious then tsTip is generous with 1.0", engine));
+engine.addRuleBlock(takagiSugeno);
+
+
+}
+}
diff --git a/examples/hybrid/tipper.pdf b/examples/hybrid/tipper.pdf
new file mode 100644
index 0000000..482e9cc
--- /dev/null
+++ b/examples/hybrid/tipper.pdf
Binary files differ
diff --git a/examples/mamdani/AllTerms.R b/examples/mamdani/AllTerms.R
new file mode 100644
index 0000000..1b17463
--- /dev/null
+++ b/examples/mamdani/AllTerms.R
@@ -0,0 +1,111 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "AllTerms"
+engine.fll = "Engine: AllTerms
+InputVariable: AllInputTerms
+ enabled: true
+ range: 0.000 6.500
+ lock-range: false
+ term: A Sigmoid 0.500 -20.000
+ term: B ZShape 0.000 1.000
+ term: C Ramp 1.000 0.000
+ term: D Triangle 0.500 1.000 1.500
+ term: E Trapezoid 1.000 1.250 1.750 2.000
+ term: F Concave 0.850 0.250
+ term: G Rectangle 1.750 2.250
+ term: H Discrete 2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000
+ term: I Gaussian 3.000 0.200
+ term: J Cosine 3.250 0.650
+ term: K GaussianProduct 3.500 0.100 3.300 0.300
+ term: L Spike 3.640 1.040
+ term: M Bell 4.000 0.250 3.000
+ term: N PiShape 4.000 4.500 4.500 5.000
+ term: O Concave 5.650 6.250
+ term: P SigmoidDifference 4.750 10.000 30.000 5.250
+ term: Q SigmoidProduct 5.250 20.000 -10.000 5.750
+ term: R Ramp 5.500 6.500
+ term: S SShape 5.500 6.500
+ term: T Sigmoid 6.000 20.000
+OutputVariable: AllOutputTerms
+ enabled: true
+ range: 0.000 6.500
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: A Sigmoid 0.500 -20.000
+ term: B ZShape 0.000 1.000
+ term: C Ramp 1.000 0.000
+ term: D Triangle 0.500 1.000 1.500
+ term: E Trapezoid 1.000 1.250 1.750 2.000
+ term: F Concave 0.850 0.250
+ term: G Rectangle 1.750 2.250
+ term: H Discrete 2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000
+ term: I Gaussian 3.000 0.200
+ term: J Cosine 3.250 0.650
+ term: K GaussianProduct 3.500 0.100 3.300 0.300
+ term: L Spike 3.640 1.040
+ term: M Bell 4.000 0.250 3.000
+ term: N PiShape 4.000 4.500 4.500 5.000
+ term: O Concave 5.650 6.250
+ term: P SigmoidDifference 4.750 10.000 30.000 5.250
+ term: Q SigmoidProduct 5.250 20.000 -10.000 5.750
+ term: R Ramp 5.500 6.500
+ term: S SShape 5.500 6.500
+ term: T Sigmoid 6.000 20.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if AllInputTerms is A then AllOutputTerms is T
+ rule: if AllInputTerms is B then AllOutputTerms is S
+ rule: if AllInputTerms is C then AllOutputTerms is R
+ rule: if AllInputTerms is D then AllOutputTerms is Q
+ rule: if AllInputTerms is E then AllOutputTerms is P
+ rule: if AllInputTerms is F then AllOutputTerms is O
+ rule: if AllInputTerms is G then AllOutputTerms is N
+ rule: if AllInputTerms is H then AllOutputTerms is M
+ rule: if AllInputTerms is I then AllOutputTerms is L
+ rule: if AllInputTerms is J then AllOutputTerms is K
+ rule: if AllInputTerms is K then AllOutputTerms is J
+ rule: if AllInputTerms is L then AllOutputTerms is I
+ rule: if AllInputTerms is M then AllOutputTerms is H
+ rule: if AllInputTerms is N then AllOutputTerms is G
+ rule: if AllInputTerms is O then AllOutputTerms is F
+ rule: if AllInputTerms is P then AllOutputTerms is E
+ rule: if AllInputTerms is Q then AllOutputTerms is D
+ rule: if AllInputTerms is R then AllOutputTerms is C
+ rule: if AllInputTerms is S then AllOutputTerms is B
+ rule: if AllInputTerms is T then AllOutputTerms is A"
+
+engine.fldFile = "AllTerms.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(AllInputTerms, AllOutputTerms)) +
+ geom_line(aes(color=AllOutputTerms), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("AllInputTerms vs AllOutputTerms")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(AllInputTerms, AllOutputTerms)) +
+ geom_line(aes(color=AllOutputTerms), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("AllOutputTerms vs AllInputTerms")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/AllTerms.cpp b/examples/mamdani/AllTerms.cpp
new file mode 100644
index 0000000..3d96ef5
--- /dev/null
+++ b/examples/mamdani/AllTerms.cpp
@@ -0,0 +1,103 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("AllTerms");
+engine->setDescription("");
+
+InputVariable* AllInputTerms = new InputVariable;
+AllInputTerms->setName("AllInputTerms");
+AllInputTerms->setDescription("");
+AllInputTerms->setEnabled(true);
+AllInputTerms->setRange(0.000, 6.500);
+AllInputTerms->setLockValueInRange(false);
+AllInputTerms->addTerm(new Sigmoid("A", 0.500, -20.000));
+AllInputTerms->addTerm(new ZShape("B", 0.000, 1.000));
+AllInputTerms->addTerm(new Ramp("C", 1.000, 0.000));
+AllInputTerms->addTerm(new Triangle("D", 0.500, 1.000, 1.500));
+AllInputTerms->addTerm(new Trapezoid("E", 1.000, 1.250, 1.750, 2.000));
+AllInputTerms->addTerm(new Concave("F", 0.850, 0.250));
+AllInputTerms->addTerm(new Rectangle("G", 1.750, 2.250));
+AllInputTerms->addTerm(Discrete::create("H", 10, 2.000, 0.000, 2.250, 1.000, 2.500, 0.500, 2.750, 1.000, 3.000, 0.000));
+AllInputTerms->addTerm(new Gaussian("I", 3.000, 0.200));
+AllInputTerms->addTerm(new Cosine("J", 3.250, 0.650));
+AllInputTerms->addTerm(new GaussianProduct("K", 3.500, 0.100, 3.300, 0.300));
+AllInputTerms->addTerm(new Spike("L", 3.640, 1.040));
+AllInputTerms->addTerm(new Bell("M", 4.000, 0.250, 3.000));
+AllInputTerms->addTerm(new PiShape("N", 4.000, 4.500, 4.500, 5.000));
+AllInputTerms->addTerm(new Concave("O", 5.650, 6.250));
+AllInputTerms->addTerm(new SigmoidDifference("P", 4.750, 10.000, 30.000, 5.250));
+AllInputTerms->addTerm(new SigmoidProduct("Q", 5.250, 20.000, -10.000, 5.750));
+AllInputTerms->addTerm(new Ramp("R", 5.500, 6.500));
+AllInputTerms->addTerm(new SShape("S", 5.500, 6.500));
+AllInputTerms->addTerm(new Sigmoid("T", 6.000, 20.000));
+engine->addInputVariable(AllInputTerms);
+
+OutputVariable* AllOutputTerms = new OutputVariable;
+AllOutputTerms->setName("AllOutputTerms");
+AllOutputTerms->setDescription("");
+AllOutputTerms->setEnabled(true);
+AllOutputTerms->setRange(0.000, 6.500);
+AllOutputTerms->setLockValueInRange(false);
+AllOutputTerms->setAggregation(new Maximum);
+AllOutputTerms->setDefuzzifier(new Centroid(200));
+AllOutputTerms->setDefaultValue(fl::nan);
+AllOutputTerms->setLockPreviousValue(false);
+AllOutputTerms->addTerm(new Sigmoid("A", 0.500, -20.000));
+AllOutputTerms->addTerm(new ZShape("B", 0.000, 1.000));
+AllOutputTerms->addTerm(new Ramp("C", 1.000, 0.000));
+AllOutputTerms->addTerm(new Triangle("D", 0.500, 1.000, 1.500));
+AllOutputTerms->addTerm(new Trapezoid("E", 1.000, 1.250, 1.750, 2.000));
+AllOutputTerms->addTerm(new Concave("F", 0.850, 0.250));
+AllOutputTerms->addTerm(new Rectangle("G", 1.750, 2.250));
+AllOutputTerms->addTerm(Discrete::create("H", 10, 2.000, 0.000, 2.250, 1.000, 2.500, 0.500, 2.750, 1.000, 3.000, 0.000));
+AllOutputTerms->addTerm(new Gaussian("I", 3.000, 0.200));
+AllOutputTerms->addTerm(new Cosine("J", 3.250, 0.650));
+AllOutputTerms->addTerm(new GaussianProduct("K", 3.500, 0.100, 3.300, 0.300));
+AllOutputTerms->addTerm(new Spike("L", 3.640, 1.040));
+AllOutputTerms->addTerm(new Bell("M", 4.000, 0.250, 3.000));
+AllOutputTerms->addTerm(new PiShape("N", 4.000, 4.500, 4.500, 5.000));
+AllOutputTerms->addTerm(new Concave("O", 5.650, 6.250));
+AllOutputTerms->addTerm(new SigmoidDifference("P", 4.750, 10.000, 30.000, 5.250));
+AllOutputTerms->addTerm(new SigmoidProduct("Q", 5.250, 20.000, -10.000, 5.750));
+AllOutputTerms->addTerm(new Ramp("R", 5.500, 6.500));
+AllOutputTerms->addTerm(new SShape("S", 5.500, 6.500));
+AllOutputTerms->addTerm(new Sigmoid("T", 6.000, 20.000));
+engine->addOutputVariable(AllOutputTerms);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new Minimum);
+ruleBlock->setDisjunction(new Maximum);
+ruleBlock->setImplication(new Minimum);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if AllInputTerms is A then AllOutputTerms is T", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is B then AllOutputTerms is S", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is C then AllOutputTerms is R", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is D then AllOutputTerms is Q", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is E then AllOutputTerms is P", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is F then AllOutputTerms is O", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is G then AllOutputTerms is N", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is H then AllOutputTerms is M", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is I then AllOutputTerms is L", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is J then AllOutputTerms is K", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is K then AllOutputTerms is J", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is L then AllOutputTerms is I", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is M then AllOutputTerms is H", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is N then AllOutputTerms is G", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is O then AllOutputTerms is F", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is P then AllOutputTerms is E", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is Q then AllOutputTerms is D", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is R then AllOutputTerms is C", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is S then AllOutputTerms is B", engine));
+ruleBlock->addRule(Rule::parse("if AllInputTerms is T then AllOutputTerms is A", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/AllTerms.fcl b/examples/mamdani/AllTerms.fcl
new file mode 100644
index 0000000..0c56fd6
--- /dev/null
+++ b/examples/mamdani/AllTerms.fcl
@@ -0,0 +1,90 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK AllTerms
+
+VAR_INPUT
+ AllInputTerms: REAL;
+END_VAR
+
+VAR_OUTPUT
+ AllOutputTerms: REAL;
+END_VAR
+
+FUZZIFY AllInputTerms
+ RANGE := (0.000 .. 6.500);
+ TERM A := Sigmoid 0.500 -20.000;
+ TERM B := ZShape 0.000 1.000;
+ TERM C := Ramp 1.000 0.000;
+ TERM D := Triangle 0.500 1.000 1.500;
+ TERM E := Trapezoid 1.000 1.250 1.750 2.000;
+ TERM F := Concave 0.850 0.250;
+ TERM G := Rectangle 1.750 2.250;
+ TERM H := (2.000, 0.000) (2.250, 1.000) (2.500, 0.500) (2.750, 1.000) (3.000, 0.000);
+ TERM I := Gaussian 3.000 0.200;
+ TERM J := Cosine 3.250 0.650;
+ TERM K := GaussianProduct 3.500 0.100 3.300 0.300;
+ TERM L := Spike 3.640 1.040;
+ TERM M := Bell 4.000 0.250 3.000;
+ TERM N := PiShape 4.000 4.500 4.500 5.000;
+ TERM O := Concave 5.650 6.250;
+ TERM P := SigmoidDifference 4.750 10.000 30.000 5.250;
+ TERM Q := SigmoidProduct 5.250 20.000 -10.000 5.750;
+ TERM R := Ramp 5.500 6.500;
+ TERM S := SShape 5.500 6.500;
+ TERM T := Sigmoid 6.000 20.000;
+END_FUZZIFY
+
+DEFUZZIFY AllOutputTerms
+ RANGE := (0.000 .. 6.500);
+ TERM A := Sigmoid 0.500 -20.000;
+ TERM B := ZShape 0.000 1.000;
+ TERM C := Ramp 1.000 0.000;
+ TERM D := Triangle 0.500 1.000 1.500;
+ TERM E := Trapezoid 1.000 1.250 1.750 2.000;
+ TERM F := Concave 0.850 0.250;
+ TERM G := Rectangle 1.750 2.250;
+ TERM H := (2.000, 0.000) (2.250, 1.000) (2.500, 0.500) (2.750, 1.000) (3.000, 0.000);
+ TERM I := Gaussian 3.000 0.200;
+ TERM J := Cosine 3.250 0.650;
+ TERM K := GaussianProduct 3.500 0.100 3.300 0.300;
+ TERM L := Spike 3.640 1.040;
+ TERM M := Bell 4.000 0.250 3.000;
+ TERM N := PiShape 4.000 4.500 4.500 5.000;
+ TERM O := Concave 5.650 6.250;
+ TERM P := SigmoidDifference 4.750 10.000 30.000 5.250;
+ TERM Q := SigmoidProduct 5.250 20.000 -10.000 5.750;
+ TERM R := Ramp 5.500 6.500;
+ TERM S := SShape 5.500 6.500;
+ TERM T := Sigmoid 6.000 20.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : MIN;
+ OR : MAX;
+ ACT : MIN;
+ RULE 1 : if AllInputTerms is A then AllOutputTerms is T
+ RULE 2 : if AllInputTerms is B then AllOutputTerms is S
+ RULE 3 : if AllInputTerms is C then AllOutputTerms is R
+ RULE 4 : if AllInputTerms is D then AllOutputTerms is Q
+ RULE 5 : if AllInputTerms is E then AllOutputTerms is P
+ RULE 6 : if AllInputTerms is F then AllOutputTerms is O
+ RULE 7 : if AllInputTerms is G then AllOutputTerms is N
+ RULE 8 : if AllInputTerms is H then AllOutputTerms is M
+ RULE 9 : if AllInputTerms is I then AllOutputTerms is L
+ RULE 10 : if AllInputTerms is J then AllOutputTerms is K
+ RULE 11 : if AllInputTerms is K then AllOutputTerms is J
+ RULE 12 : if AllInputTerms is L then AllOutputTerms is I
+ RULE 13 : if AllInputTerms is M then AllOutputTerms is H
+ RULE 14 : if AllInputTerms is N then AllOutputTerms is G
+ RULE 15 : if AllInputTerms is O then AllOutputTerms is F
+ RULE 16 : if AllInputTerms is P then AllOutputTerms is E
+ RULE 17 : if AllInputTerms is Q then AllOutputTerms is D
+ RULE 18 : if AllInputTerms is R then AllOutputTerms is C
+ RULE 19 : if AllInputTerms is S then AllOutputTerms is B
+ RULE 20 : if AllInputTerms is T then AllOutputTerms is A
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/AllTerms.fis b/examples/mamdani/AllTerms.fis
new file mode 100644
index 0000000..d34e487
--- /dev/null
+++ b/examples/mamdani/AllTerms.fis
@@ -0,0 +1,86 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='AllTerms'
+Type='mamdani'
+Version=6.0
+NumInputs=1
+NumOutputs=1
+NumRules=20
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='AllInputTerms'
+Range=[0.000 6.500]
+NumMFs=20
+MF1='A':'sigmf',[-20.000 0.500]
+MF2='B':'zmf',[0.000 1.000]
+MF3='C':'rampmf',[1.000 0.000]
+MF4='D':'trimf',[0.500 1.000 1.500]
+MF5='E':'trapmf',[1.000 1.250 1.750 2.000]
+MF6='F':'concavemf',[0.850 0.250]
+MF7='G':'rectmf',[1.750 2.250]
+MF8='H':'discretemf',[2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000]
+MF9='I':'gaussmf',[0.200 3.000]
+MF10='J':'cosinemf',[3.250 0.650]
+MF11='K':'gauss2mf',[0.100 3.500 0.300 3.300]
+MF12='L':'spikemf',[3.640 1.040]
+MF13='M':'gbellmf',[0.250 3.000 4.000]
+MF14='N':'pimf',[4.000 4.500 4.500 5.000]
+MF15='O':'concavemf',[5.650 6.250]
+MF16='P':'dsigmf',[10.000 4.750 30.000 5.250]
+MF17='Q':'psigmf',[20.000 5.250 -10.000 5.750]
+MF18='R':'rampmf',[5.500 6.500]
+MF19='S':'smf',[5.500 6.500]
+MF20='T':'sigmf',[20.000 6.000]
+
+[Output1]
+Name='AllOutputTerms'
+Range=[0.000 6.500]
+NumMFs=20
+MF1='A':'sigmf',[-20.000 0.500]
+MF2='B':'zmf',[0.000 1.000]
+MF3='C':'rampmf',[1.000 0.000]
+MF4='D':'trimf',[0.500 1.000 1.500]
+MF5='E':'trapmf',[1.000 1.250 1.750 2.000]
+MF6='F':'concavemf',[0.850 0.250]
+MF7='G':'rectmf',[1.750 2.250]
+MF8='H':'discretemf',[2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000]
+MF9='I':'gaussmf',[0.200 3.000]
+MF10='J':'cosinemf',[3.250 0.650]
+MF11='K':'gauss2mf',[0.100 3.500 0.300 3.300]
+MF12='L':'spikemf',[3.640 1.040]
+MF13='M':'gbellmf',[0.250 3.000 4.000]
+MF14='N':'pimf',[4.000 4.500 4.500 5.000]
+MF15='O':'concavemf',[5.650 6.250]
+MF16='P':'dsigmf',[10.000 4.750 30.000 5.250]
+MF17='Q':'psigmf',[20.000 5.250 -10.000 5.750]
+MF18='R':'rampmf',[5.500 6.500]
+MF19='S':'smf',[5.500 6.500]
+MF20='T':'sigmf',[20.000 6.000]
+
+[Rules]
+1.000 , 20.000 (1.000) : 1
+2.000 , 19.000 (1.000) : 1
+3.000 , 18.000 (1.000) : 1
+4.000 , 17.000 (1.000) : 1
+5.000 , 16.000 (1.000) : 1
+6.000 , 15.000 (1.000) : 1
+7.000 , 14.000 (1.000) : 1
+8.000 , 13.000 (1.000) : 1
+9.000 , 12.000 (1.000) : 1
+10.000 , 11.000 (1.000) : 1
+11.000 , 10.000 (1.000) : 1
+12.000 , 9.000 (1.000) : 1
+13.000 , 8.000 (1.000) : 1
+14.000 , 7.000 (1.000) : 1
+15.000 , 6.000 (1.000) : 1
+16.000 , 5.000 (1.000) : 1
+17.000 , 4.000 (1.000) : 1
+18.000 , 3.000 (1.000) : 1
+19.000 , 2.000 (1.000) : 1
+20.000 , 1.000 (1.000) : 1
diff --git a/examples/mamdani/AllTerms.fld b/examples/mamdani/AllTerms.fld
new file mode 100644
index 0000000..b765a5b
--- /dev/null
+++ b/examples/mamdani/AllTerms.fld
@@ -0,0 +1,1025 @@
+AllInputTerms AllOutputTerms
+0.000000000 4.599895277
+0.006353861 4.599895277
+0.012707722 4.599895277
+0.019061584 4.599892153
+0.025415445 4.599885084
+0.031769306 4.599878001
+0.038123167 4.599870905
+0.044477028 4.599863796
+0.050830890 4.599854356
+0.057184751 4.599840135
+0.063538612 4.599825888
+0.069892473 4.599811614
+0.076246334 4.599797313
+0.082600196 4.599781479
+0.088954057 4.599760024
+0.095307918 4.599738529
+0.101661779 4.599716994
+0.108015640 4.599695418
+0.114369501 4.599673109
+0.120723363 4.599644337
+0.127077224 4.599615510
+0.133431085 4.599586630
+0.139784946 4.599557695
+0.146138807 4.599528705
+0.152492669 4.599492655
+0.158846530 4.599456412
+0.165200391 4.599420101
+0.171554252 4.599383721
+0.177908113 4.599347272
+0.184261975 4.599304555
+0.190615836 4.599260809
+0.196969697 4.599216981
+0.203323558 4.599173070
+0.209677419 4.599129075
+0.216031281 4.599079607
+0.222385142 4.599028272
+0.228739003 4.598976839
+0.235092864 4.598925308
+0.241446725 4.598873679
+0.247800587 4.598817377
+0.254154448 4.596919174
+0.260508309 4.596493440
+0.266862170 4.596137632
+0.273216031 4.595742200
+0.279569892 4.595274723
+0.285923754 4.594727219
+0.292277615 4.594116008
+0.298631476 4.593432922
+0.304985337 4.592668807
+0.311339198 4.591776911
+0.317693060 4.590721701
+0.324046921 4.589539310
+0.330400782 4.588214154
+0.336754643 4.586728981
+0.343108504 4.585019129
+0.349462366 4.582986784
+0.355816227 4.580711102
+0.362170088 4.578164818
+0.368523949 4.575318436
+0.374877810 4.572092534
+0.381231672 4.568261237
+0.387585533 4.563994780
+0.393939394 4.559252552
+0.400293255 4.553992732
+0.406647116 4.548144994
+0.413000978 4.541249632
+0.419354839 4.533659657
+0.425708700 4.525333057
+0.432062561 4.516232199
+0.438416422 4.506325696
+0.444770283 4.496794792
+0.451124145 4.493710135
+0.457478006 4.490662106
+0.463831867 4.487650020
+0.470185728 4.484673209
+0.476539589 4.481579293
+0.482893451 4.478490131
+0.489247312 4.475435736
+0.495601173 4.472415487
+0.501955034 4.469428781
+0.508308895 4.466353820
+0.514662757 4.463264545
+0.521016618 4.460208273
+0.527370479 4.457184444
+0.533724340 4.454192506
+0.540078201 4.451137323
+0.546432063 4.448051381
+0.552785924 4.444996778
+0.559139785 4.441973003
+0.565493646 4.438979556
+0.571847507 4.435944616
+0.578201369 4.432864702
+0.584555230 4.429814557
+0.590909091 4.426793715
+0.597262952 4.423801721
+0.603616813 4.420787213
+0.609970674 4.417715418
+0.616324536 4.414671913
+0.622678397 4.411656273
+0.629032258 4.408668084
+0.635386119 4.405673984
+0.641739980 4.402611914
+0.648093842 4.399576742
+0.654447703 4.396568080
+0.660801564 4.393585550
+0.667155425 4.390611667
+0.673509286 4.387560536
+0.679863148 4.384534993
+0.686217009 4.381534685
+0.692570870 4.378803034
+0.698924731 4.376475128
+0.705278592 4.374472509
+0.711632454 4.372876293
+0.717986315 4.371667843
+0.724340176 4.370882078
+0.730694037 4.370495109
+0.737047898 4.370388857
+0.743401760 4.370642624
+0.749755621 4.371087594
+0.756109482 4.371809708
+0.762463343 4.372860066
+0.768817204 4.374172697
+0.775171065 4.375519338
+0.781524927 4.376944539
+0.787878788 4.378390691
+0.794232649 4.379857111
+0.800586510 4.381337853
+0.806940371 4.382825703
+0.813294233 4.383995232
+0.819648094 4.385184747
+0.826001955 4.386272381
+0.832355816 4.387263153
+0.838709677 4.388270397
+0.845063539 4.389218723
+0.851417400 4.389931993
+0.857771261 4.390665144
+0.864125122 4.391414233
+0.870478983 4.392178065
+0.876832845 4.392925336
+0.883186706 4.393405489
+0.889540567 4.393768439
+0.895894428 4.394047827
+0.902248289 4.394341121
+0.908602151 4.394414128
+0.914956012 4.394434726
+0.921309873 4.394473933
+0.927663734 4.394455866
+0.934017595 4.394023022
+0.940371457 4.393565645
+0.946725318 4.392979180
+0.953079179 4.392264873
+0.959433040 4.391194008
+0.965786901 4.389891155
+0.972140762 4.387967116
+0.978494624 4.386008929
+0.984848485 4.384078347
+0.991202346 4.382159658
+0.997556207 4.380245187
+1.003910068 4.378342248
+1.010263930 4.376450758
+1.016617791 4.374570582
+1.022971652 4.372701585
+1.029325513 4.370836957
+1.035679374 4.368777798
+1.042033236 4.366100940
+1.048387097 4.363131178
+1.054740958 4.359902890
+1.061094819 4.356444999
+1.067448680 4.352898808
+1.073802542 4.349689538
+1.080156403 4.347161282
+1.086510264 4.346117831
+1.092864125 4.346638603
+1.099217986 4.347588660
+1.105571848 4.348367496
+1.111925709 4.349145305
+1.118279570 4.349580392
+1.124633431 4.350038990
+1.130987292 4.350146966
+1.137341153 4.350021415
+1.143695015 4.349874085
+1.150048876 4.349738316
+1.156402737 4.349455770
+1.162756598 4.348792090
+1.169110459 4.348140830
+1.175464321 4.347318692
+1.181818182 4.346244887
+1.188172043 4.344696513
+1.194525904 4.342885325
+1.200879765 4.340822753
+1.207233627 4.338510265
+1.213587488 4.336156649
+1.219941349 4.333355362
+1.226295210 4.330137299
+1.232649071 4.326641602
+1.239002933 4.321989008
+1.245356794 4.316169893
+1.251710655 4.310255005
+1.258064516 4.304334601
+1.264418377 4.298371995
+1.270772239 4.292366629
+1.277126100 4.286098146
+1.283479961 4.279628008
+1.289833822 4.273099795
+1.296187683 4.266519469
+1.302541544 4.259886618
+1.308895406 4.253200509
+1.315249267 4.246299266
+1.321603128 4.240059447
+1.327956989 4.237953162
+1.334310850 4.235855128
+1.340664712 4.233765267
+1.347018573 4.231683504
+1.353372434 4.229604349
+1.359726295 4.227531097
+1.366080156 4.225465702
+1.372434018 4.223408091
+1.378787879 4.221358193
+1.385141740 4.219311371
+1.391495601 4.217269217
+1.397849462 4.215234545
+1.404203324 4.213207286
+1.410557185 4.211187374
+1.416911046 4.209171028
+1.423264907 4.207158130
+1.429618768 4.205152358
+1.435972630 4.203153647
+1.442326491 4.201161932
+1.448680352 4.199174293
+1.455034213 4.197188899
+1.461388074 4.195210291
+1.467741935 4.193238408
+1.474095797 4.191273188
+1.480449658 4.189312571
+1.486803519 4.187353011
+1.493157380 4.185399915
+1.499511241 4.183453221
+1.505865103 4.181512872
+1.512218964 4.179577670
+1.518572825 4.177642355
+1.524926686 4.175713192
+1.531280547 4.173790126
+1.537634409 4.171873100
+1.543988270 4.169961779
+1.550342131 4.168049188
+1.556695992 4.166142455
+1.563049853 4.164241525
+1.569403715 4.162346345
+1.575757576 4.160456860
+1.582111437 4.158566124
+1.588465298 4.156680384
+1.594819159 4.154800166
+1.601173021 4.152925419
+1.607526882 4.151056092
+1.613880743 4.149186104
+1.620234604 4.147319983
+1.626588465 4.145459116
+1.632942326 4.143603453
+1.639296188 4.141752946
+1.645650049 4.139902380
+1.652003910 4.138054566
+1.658357771 4.136211747
+1.664711632 4.134373878
+1.671065494 4.132540910
+1.677419355 4.130708496
+1.683773216 4.128877732
+1.690127077 4.127051717
+1.696480938 4.125230405
+1.702834800 4.123413751
+1.709188661 4.121598273
+1.715542522 4.119783356
+1.721896383 4.117972950
+1.728250244 4.116167012
+1.734604106 4.114365499
+1.740957967 4.112565790
+1.747311828 4.110765567
+1.753665689 4.168153884
+1.760019550 4.166675537
+1.766373412 4.164106453
+1.772727273 4.160437753
+1.779081134 4.156385975
+1.785434995 4.151833303
+1.791788856 4.146677771
+1.798142717 4.141366376
+1.804496579 4.135700681
+1.810850440 4.129929818
+1.817204301 4.123874560
+1.823558162 4.117266592
+1.829912023 4.110423379
+1.836265885 4.103170947
+1.842619746 4.095818864
+1.848973607 4.088323358
+1.855327468 4.080426295
+1.861681329 4.072417514
+1.868035191 4.064291322
+1.874389052 4.055685721
+1.880742913 4.046336936
+1.887096774 4.036896117
+1.893450635 4.027612078
+1.899804497 4.018179925
+1.906158358 4.008590765
+1.912512219 3.998844491
+1.918866080 3.989206249
+1.925219941 3.979582314
+1.931573803 3.969730626
+1.937927664 3.963998992
+1.944281525 3.962015501
+1.950635386 3.960035623
+1.956989247 3.958059326
+1.963343109 3.956086577
+1.969696970 3.954113625
+1.976050831 3.952141011
+1.982404692 3.950171837
+1.988758553 3.948206070
+1.995112414 3.946243679
+2.001466276 3.944281718
+2.007820137 3.942319159
+2.014173998 3.940359871
+2.020527859 3.938403822
+2.026881720 3.936450982
+2.033235582 3.934499204
+2.039589443 3.932545907
+2.045943304 3.930595717
+2.052297165 3.928321055
+2.058651026 3.926276349
+2.065004888 3.924475266
+2.071358749 3.922774809
+2.077712610 3.921104727
+2.084066471 3.919464304
+2.090420332 3.918010740
+2.096774194 3.916680680
+2.103128055 3.915368777
+2.109481916 3.914080307
+2.115835777 3.912814724
+2.122189638 3.911723968
+2.128543500 3.910668734
+2.134897361 3.909680634
+2.141251222 3.908669775
+2.147605083 3.907587992
+2.153958944 3.906523952
+2.160312805 3.905477277
+2.166666667 3.904442682
+2.173020528 3.903423931
+2.179374389 3.902421528
+2.185728250 3.901486449
+2.192082111 3.900445921
+2.198435973 3.899393150
+2.204789834 3.898353233
+2.211143695 3.897327377
+2.217497556 3.896315330
+2.223851417 3.895323424
+2.230205279 3.894239779
+2.236559140 3.893166259
+2.242913001 3.892085629
+2.249266862 3.890921186
+2.255620723 3.763373136
+2.261974585 3.760810581
+2.268328446 3.758220845
+2.274682307 3.755515096
+2.281036168 3.752787836
+2.287390029 3.750049993
+2.293743891 3.747296167
+2.300097752 3.744524926
+2.306451613 3.741705721
+2.312805474 3.738783159
+2.319159335 3.735822614
+2.325513196 3.732839473
+2.331867058 3.729832989
+2.338220919 3.726807130
+2.344574780 3.723761656
+2.350928641 3.720696322
+2.357282502 3.717609935
+2.363636364 3.714498281
+2.369990225 3.711365982
+2.376344086 3.708212779
+2.382697947 3.704895960
+2.389051808 3.701549104
+2.395405670 3.698151488
+2.401759531 3.694720822
+2.408113392 3.691262237
+2.414467253 3.687775337
+2.420821114 3.684259719
+2.427174976 3.680709529
+2.433528837 3.677129365
+2.439882698 3.673519197
+2.446236559 3.669878595
+2.452590420 3.666207121
+2.458944282 3.662499570
+2.465298143 3.658759155
+2.471652004 3.654986475
+2.478005865 3.651045967
+2.484359726 3.647017997
+2.490713587 3.642936519
+2.497067449 3.638788673
+2.503421310 3.636596731
+2.509775171 3.636113994
+2.516129032 3.635610934
+2.522482893 3.635103238
+2.528836755 3.634534439
+2.535190616 3.633850040
+2.541544477 3.633174274
+2.547898338 3.632506997
+2.554252199 3.631845503
+2.560606061 3.631189380
+2.566959922 3.630541357
+2.573313783 3.629901299
+2.579667644 3.629269072
+2.586021505 3.628642677
+2.592375367 3.628020518
+2.598729228 3.627405830
+2.605083089 3.626798488
+2.611436950 3.626184131
+2.617790811 3.625542149
+2.624144673 3.624883923
+2.630498534 3.624060753
+2.636852395 3.623189558
+2.643206256 3.622327417
+2.649560117 3.621478017
+2.655913978 3.620645245
+2.662267840 3.619821076
+2.668621701 3.619029171
+2.674975562 3.618259835
+2.681329423 3.617499446
+2.687683284 3.616733785
+2.694037146 3.615929936
+2.700391007 3.615010095
+2.706744868 3.614080723
+2.713098729 3.613215121
+2.719452590 3.612358954
+2.725806452 3.611513289
+2.732160313 3.610643258
+2.738514174 3.609617457
+2.744868035 3.608593932
+2.751221896 3.607027619
+2.757575758 3.603513978
+2.763929619 3.599607885
+2.770283480 3.595554668
+2.776637341 3.591470975
+2.782991202 3.587039699
+2.789345064 3.582427638
+2.795698925 3.577769876
+2.802052786 3.573065578
+2.808406647 3.568294094
+2.814760508 3.563340228
+2.821114370 3.558021643
+2.827468231 3.552516327
+2.833822092 3.546930677
+2.840175953 3.541262601
+2.846529814 3.535508239
+2.852883675 3.529664792
+2.859237537 3.523731944
+2.865591398 3.517440754
+2.871945259 3.510815250
+2.878299120 3.503981681
+2.884652981 3.497018115
+2.891006843 3.489873772
+2.897360704 3.482525406
+2.903714565 3.475027943
+2.910068426 3.467225386
+2.916422287 3.458886336
+2.922776149 3.450555637
+2.929130010 3.442048766
+2.935483871 3.433360109
+2.941837732 3.424602968
+2.948191593 3.415281614
+2.954545455 3.405651752
+2.960899316 3.403007137
+2.967253177 3.400434512
+2.973607038 3.397862391
+2.979960899 3.395287917
+2.986314761 3.392713887
+2.992668622 3.390140357
+2.999022483 3.387568883
+3.005376344 3.385000338
+3.011730205 3.382430013
+3.018084066 3.380077653
+3.024437928 3.377875015
+3.030791789 3.375524943
+3.037145650 3.373402036
+3.043499511 3.371116711
+3.049853372 3.368824184
+3.056207234 3.366623179
+3.062561095 3.364503845
+3.068914956 3.362409804
+3.075268817 3.360336018
+3.081622678 3.358353454
+3.087976540 3.356478896
+3.094330401 3.354622474
+3.100684262 3.352771569
+3.107038123 3.350907341
+3.113391984 3.348993885
+3.119745846 3.346909885
+3.126099707 3.344819531
+3.132453568 3.342598890
+3.138807429 3.340275375
+3.145161290 3.337883015
+3.151515152 3.335412086
+3.157869013 3.332875386
+3.164222874 3.330208393
+3.170576735 3.327532743
+3.176930596 3.324848544
+3.183284457 3.322157198
+3.189638319 3.319459305
+3.195992180 3.316677427
+3.202346041 3.313783765
+3.208699902 3.310881781
+3.215053763 3.307973034
+3.221407625 3.305194923
+3.227761486 3.302433058
+3.234115347 3.299669163
+3.240469208 3.296983598
+3.246823069 3.294388917
+3.253176931 3.291694941
+3.259530792 3.288912681
+3.265884653 3.286303511
+3.272238514 3.283696099
+3.278592375 3.281090518
+3.284946237 3.278608571
+3.291300098 3.276193408
+3.297653959 3.273722220
+3.304007820 3.271161759
+3.310361681 3.268747744
+3.316715543 3.265966787
+3.323069404 3.263085323
+3.329423265 3.260199447
+3.335777126 3.257347210
+3.342130987 3.254581221
+3.348484848 3.251727316
+3.354838710 3.248792146
+3.361192571 3.245765662
+3.367546432 3.242718518
+3.373900293 3.239619271
+3.380254154 3.236414055
+3.386608016 3.233211207
+3.392961877 3.229760188
+3.399315738 3.226378097
+3.405669599 3.222796617
+3.412023460 3.219154408
+3.418377322 3.215272481
+3.424731183 3.211297617
+3.431085044 3.207131367
+3.437438905 3.202926988
+3.443792766 3.198418272
+3.450146628 3.193810749
+3.456500489 3.188860538
+3.462854350 3.183359238
+3.469208211 3.177024226
+3.475562072 3.170496818
+3.481915934 3.163778038
+3.488269795 3.156835795
+3.494623656 3.151777246
+3.500977517 3.148035721
+3.507331378 3.144197746
+3.513685239 3.140446705
+3.520039101 3.136655740
+3.526392962 3.132806200
+3.532746823 3.128899648
+3.539100684 3.125129471
+3.545454545 3.121261384
+3.551808407 3.117323246
+3.558162268 3.113378774
+3.564516129 3.109556905
+3.570869990 3.105689954
+3.577223851 3.101812687
+3.583577713 3.098113304
+3.589931574 3.094386990
+3.596285435 3.090861319
+3.602639296 3.087515615
+3.608993157 3.084155158
+3.615347019 3.080990618
+3.621700880 3.077760997
+3.628054741 3.074689575
+3.634408602 3.071762524
+3.640762463 3.069078509
+3.647116325 3.066888906
+3.653470186 3.064848343
+3.659824047 3.062841076
+3.666177908 3.060943162
+3.672531769 3.058946649
+3.678885630 3.057033237
+3.685239492 3.051646773
+3.691593353 3.043638574
+3.697947214 3.034716407
+3.704301075 3.025432082
+3.710654936 3.015899291
+3.717008798 3.005532233
+3.723362659 2.994631745
+3.729716520 2.983257966
+3.736070381 2.971645362
+3.742424242 2.959138446
+3.748778104 2.946656184
+3.755131965 2.934768336
+3.761485826 2.924011690
+3.767839687 2.913972946
+3.774193548 2.905005829
+3.780547410 2.897395635
+3.786901271 2.890239940
+3.793255132 2.883864707
+3.799608993 2.878146427
+3.805962854 2.873338916
+3.812316716 2.868774397
+3.818670577 2.864691316
+3.825024438 2.860941683
+3.831378299 2.857473629
+3.837732160 2.854395833
+3.844086022 2.851449698
+3.850439883 2.848549478
+3.856793744 2.845695513
+3.863147605 2.842933383
+3.869501466 2.840390382
+3.875855327 2.838187245
+3.882209189 2.836282288
+3.888563050 2.834395205
+3.894916911 2.832513363
+3.901270772 2.830630910
+3.907624633 2.828747302
+3.913978495 2.826862520
+3.920332356 2.824979616
+3.926686217 2.823097208
+3.933040078 2.821213567
+3.939393939 2.819328674
+3.945747801 2.817442508
+3.952101662 2.815557626
+3.958455523 2.813673739
+3.964809384 2.811788518
+3.971163245 2.809901944
+3.977517107 2.808013996
+3.983870968 2.806126709
+3.990224829 2.804240935
+3.996578690 2.802353725
+4.002932551 2.800465058
+4.009286413 2.798574913
+4.015640274 2.796684781
+4.021994135 2.794796696
+4.028347996 2.792907069
+4.034701857 2.791015880
+4.041055718 2.789123106
+4.047409580 2.787229672
+4.053763441 2.785338834
+4.060117302 2.783446347
+4.066471163 2.781552188
+4.072825024 2.779656337
+4.079178886 2.777759126
+4.085532747 2.775865077
+4.091886608 2.773969268
+4.098240469 2.772071676
+4.104594330 2.770172279
+4.110948192 2.768271094
+4.117302053 2.766374342
+4.123655914 2.764476074
+4.130009775 2.762595767
+4.136363636 2.760758819
+4.142717498 2.758935172
+4.149071359 2.757131514
+4.155425220 2.755346309
+4.161779081 2.753580657
+4.168132942 2.751482072
+4.174486804 2.747379566
+4.180840665 2.743285748
+4.187194526 2.739040821
+4.193548387 2.735000453
+4.199902248 2.730956631
+4.206256109 2.727306104
+4.212609971 2.723853682
+4.218963832 2.720650398
+4.225317693 2.717215725
+4.231671554 2.714264925
+4.238025415 2.711377668
+4.244379277 2.708456312
+4.250733138 2.705502047
+4.257086999 2.699963796
+4.263440860 2.694404754
+4.269794721 2.688818075
+4.276148583 2.683152932
+4.282502444 2.677352841
+4.288856305 2.671534472
+4.295210166 2.665710188
+4.301564027 2.659894532
+4.307917889 2.653904808
+4.314271750 2.647082281
+4.320625611 2.640376703
+4.326979472 2.634383466
+4.333333333 2.628611333
+4.339687195 2.623045257
+4.346041056 2.617682590
+4.352394917 2.612510659
+4.358748778 2.607522940
+4.365102639 2.602713283
+4.371456500 2.598076108
+4.377810362 2.593612156
+4.384164223 2.589309799
+4.390518084 2.585164176
+4.396871945 2.581170702
+4.403225806 2.577325054
+4.409579668 2.573629224
+4.415933529 2.570073814
+4.422287390 2.566654660
+4.428641251 2.563368355
+4.434995112 2.560211698
+4.441348974 2.557186973
+4.447702835 2.554287333
+4.454056696 2.551508820
+4.460410557 2.548848951
+4.466764418 2.546305402
+4.473118280 2.543880553
+4.479472141 2.541569889
+4.485826002 2.539369471
+4.492179863 2.537277567
+4.498533724 2.535292581
+4.504887586 2.533416848
+4.511241447 2.531648061
+4.517595308 2.529982170
+4.523949169 2.528418089
+4.530303030 2.526954850
+4.536656891 2.525594665
+4.543010753 2.524337371
+4.549364614 2.523178724
+4.555718475 2.522118228
+4.562072336 2.521155495
+4.568426197 2.520292572
+4.574780059 2.519531438
+4.581133920 2.518867611
+4.587487781 2.518301166
+4.593841642 2.517832298
+4.600195503 2.517462875
+4.606549365 2.517197081
+4.612903226 2.517030180
+4.619257087 2.516962853
+4.625610948 2.516995911
+4.631964809 2.517131080
+4.638318671 2.517374868
+4.644672532 2.517722312
+4.651026393 2.518174779
+4.657380254 2.513659123
+4.663734115 2.508125388
+4.670087977 2.502541173
+4.676441838 2.496905848
+4.682795699 2.491226658
+4.689149560 2.485511648
+4.695503421 2.480131931
+4.701857283 2.474823139
+4.708211144 2.469510489
+4.714565005 2.464202984
+4.720918866 2.458910899
+4.727272727 2.453644854
+4.733626588 2.448421318
+4.739980450 2.443247453
+4.746334311 2.438299314
+4.752688172 2.432763745
+4.759042033 2.425949005
+4.765395894 2.419291750
+4.771749756 2.412669897
+4.778103617 2.406055580
+4.784457478 2.399250324
+4.790811339 2.392507300
+4.797165200 2.385862943
+4.803519062 2.379674845
+4.809872923 2.373569532
+4.816226784 2.367608901
+4.822580645 2.361641330
+4.828934506 2.355218813
+4.835288368 2.348730271
+4.841642229 2.342430330
+4.847996090 2.336320662
+4.854349951 2.330399039
+4.860703812 2.324816922
+4.867057674 2.319535672
+4.873411535 2.314418752
+4.879765396 2.309466791
+4.886119257 2.304772174
+4.892473118 2.300224661
+4.898826979 2.295824445
+4.905180841 2.291561381
+4.911534702 2.287430967
+4.917888563 2.283428598
+4.924242424 2.279550153
+4.930596285 2.275796879
+4.936950147 2.272157536
+4.943304008 2.268627457
+4.949657869 2.265309212
+4.956011730 2.262113657
+4.962365591 2.259012750
+4.968719453 2.255996077
+4.975073314 2.253059604
+4.981427175 2.250199716
+4.987781036 2.247412981
+4.994134897 2.244742103
+5.000488759 2.242138547
+5.006842620 2.239596260
+5.013196481 2.237112902
+5.019550342 2.234686436
+5.025904203 2.232320228
+5.032258065 2.230009725
+5.038611926 2.227752196
+5.044965787 2.225547264
+5.051319648 2.223395128
+5.057673509 2.221300911
+5.064027370 2.219264613
+5.070381232 2.217286135
+5.076735093 2.215369071
+5.083088954 2.213518254
+5.089442815 2.211743418
+5.095796676 2.210052495
+5.102150538 2.208452035
+5.108504399 2.206954343
+5.114858260 2.205574451
+5.121212121 2.204333209
+5.127565982 2.203253997
+5.133919844 2.202358615
+5.140273705 2.201677808
+5.146627566 2.201247601
+5.152981427 2.201111684
+5.159335288 2.201321192
+5.165689150 2.201934041
+5.172043011 2.203072413
+5.178396872 2.204753575
+5.184750733 2.207267944
+5.191104594 2.210672693
+5.197458456 2.214918459
+5.203812317 2.220084262
+5.210166178 2.226462979
+5.216520039 2.234421744
+5.222873900 2.243852944
+5.229227761 2.245519207
+5.235581623 2.248153515
+5.241935484 2.252005561
+5.248289345 2.257143573
+5.254643206 2.257242365
+5.260997067 2.256166494
+5.267350929 2.255207844
+5.273704790 2.252488099
+5.280058651 2.245489169
+5.286412512 2.236180770
+5.292766373 2.227509962
+5.299120235 2.219830899
+5.305474096 2.213176464
+5.311827957 2.207156013
+5.318181818 2.201791510
+5.324535679 2.197217425
+5.330889541 2.192942201
+5.337243402 2.189263625
+5.343597263 2.185763709
+5.349951124 2.182747581
+5.356304985 2.179878809
+5.362658847 2.177132825
+5.369012708 2.174685668
+5.375366569 2.172338745
+5.381720430 2.170065527
+5.388074291 2.167860085
+5.394428152 2.165799070
+5.400782014 2.163806303
+5.407135875 2.161840938
+5.413489736 2.159902531
+5.419843597 2.157990461
+5.426197458 2.156097125
+5.432551320 2.154220179
+5.438905181 2.152357531
+5.445259042 2.150509149
+5.451612903 2.148677415
+5.457966764 2.146855019
+5.464320626 2.145040704
+5.470674487 2.143233382
+5.477028348 2.141433054
+5.483382209 2.139644701
+5.489736070 2.137860906
+5.496089932 2.136081099
+5.502443793 2.134328107
+5.508797654 2.132649534
+5.515151515 2.130989142
+5.521505376 2.129339036
+5.527859238 2.127699011
+5.534213099 2.126068931
+5.540566960 2.124448719
+5.546920821 2.122971692
+5.553274682 2.121511010
+5.559628543 2.120008961
+5.565982405 2.118523744
+5.572336266 2.117055449
+5.578690127 2.115765674
+5.585043988 2.114537858
+5.591397849 2.113335881
+5.597751711 2.112209154
+5.604105572 2.111254423
+5.610459433 2.110338185
+5.616813294 2.109457677
+5.623167155 2.108794683
+5.629521017 2.108250774
+5.635874878 2.107747754
+5.642228739 2.107523978
+5.648582600 2.107351345
+5.654936461 2.107260660
+5.661290323 2.107503323
+5.667644184 2.107795601
+5.673998045 2.108357990
+5.680351906 2.109020431
+5.686705767 2.109846004
+5.693059629 2.110979040
+5.699413490 2.112228755
+5.705767351 2.113736512
+5.712121212 2.115288377
+5.718475073 2.117188508
+5.724828935 2.119140287
+5.731182796 2.121406844
+5.737536657 2.123709219
+5.743890518 2.125864421
+5.750244379 2.127533697
+5.756598240 2.128951976
+5.762952102 2.129814768
+5.769305963 2.130111253
+5.775659824 2.129941914
+5.782013685 2.129332824
+5.788367546 2.128201102
+5.794721408 2.126466974
+5.801075269 2.124123331
+5.807429130 2.121438142
+5.813782991 2.118465315
+5.820136852 2.115465007
+5.826490714 2.112439464
+5.832844575 2.109388333
+5.839198436 2.106414450
+5.845552297 2.103431920
+5.851906158 2.100423258
+5.858260020 2.097388086
+5.864613881 2.094326016
+5.870967742 2.091331916
+5.877321603 2.088343727
+5.883675464 2.085328087
+5.890029326 2.082284582
+5.896383187 2.079212787
+5.902737048 2.076198279
+5.909090909 2.073206285
+5.915444770 2.070185443
+5.921798631 2.067135298
+5.928152493 2.064055384
+5.934506354 2.061020444
+5.940860215 2.058026997
+5.947214076 2.055003222
+5.953567937 2.051948619
+5.959921799 2.048862677
+5.966275660 2.045807494
+5.972629521 2.042815556
+5.978983382 2.039791727
+5.985337243 2.036735455
+5.991691105 2.033646180
+5.998044966 2.030571219
+6.004398827 2.027584513
+6.010752688 2.024564264
+6.017106549 2.021509869
+6.023460411 2.018420707
+6.029814272 2.015326791
+6.036168133 2.012349980
+6.042521994 2.009337894
+6.048875855 2.006289865
+6.055229717 2.003205208
+6.061583578 1.993674304
+6.067937439 1.983767801
+6.074291300 1.974666943
+6.080645161 1.966340343
+6.086999022 1.958750368
+6.093352884 1.951855006
+6.099706745 1.946007268
+6.106060606 1.940747448
+6.112414467 1.936005220
+6.118768328 1.931738763
+6.125122190 1.927907466
+6.131476051 1.924681564
+6.137829912 1.921835182
+6.144183773 1.919288898
+6.150537634 1.917013216
+6.156891496 1.914980871
+6.163245357 1.913271019
+6.169599218 1.911785846
+6.175953079 1.910460690
+6.182306940 1.909278299
+6.188660802 1.908223089
+6.195014663 1.907331193
+6.201368524 1.906567078
+6.207722385 1.905883992
+6.214076246 1.905272781
+6.220430108 1.904725277
+6.226783969 1.904257800
+6.233137830 1.903862368
+6.239491691 1.903506560
+6.245845552 1.903080826
+6.252199413 1.901182623
+6.258553275 1.901126321
+6.264907136 1.901074692
+6.271260997 1.901023161
+6.277614858 1.900971728
+6.283968719 1.900920393
+6.290322581 1.900870925
+6.296676442 1.900826930
+6.303030303 1.900783019
+6.309384164 1.900739191
+6.315738025 1.900695445
+6.322091887 1.900652728
+6.328445748 1.900616279
+6.334799609 1.900579899
+6.341153470 1.900543588
+6.347507331 1.900507345
+6.353861193 1.900471295
+6.360215054 1.900442305
+6.366568915 1.900413370
+6.372922776 1.900384490
+6.379276637 1.900355663
+6.385630499 1.900326891
+6.391984360 1.900304582
+6.398338221 1.900283006
+6.404692082 1.900261471
+6.411045943 1.900239976
+6.417399804 1.900218521
+6.423753666 1.900202687
+6.430107527 1.900188386
+6.436461388 1.900174112
+6.442815249 1.900159865
+6.449169110 1.900145644
+6.455522972 1.900136204
+6.461876833 1.900129095
+6.468230694 1.900121999
+6.474584555 1.900114916
+6.480938416 1.900107847
+6.487292278 1.900104723
+6.493646139 1.900104723
+6.500000000 1.900104723
diff --git a/examples/mamdani/AllTerms.fll b/examples/mamdani/AllTerms.fll
new file mode 100644
index 0000000..4db1b32
--- /dev/null
+++ b/examples/mamdani/AllTerms.fll
@@ -0,0 +1,79 @@
+Engine: AllTerms
+InputVariable: AllInputTerms
+ enabled: true
+ range: 0.000 6.500
+ lock-range: false
+ term: A Sigmoid 0.500 -20.000
+ term: B ZShape 0.000 1.000
+ term: C Ramp 1.000 0.000
+ term: D Triangle 0.500 1.000 1.500
+ term: E Trapezoid 1.000 1.250 1.750 2.000
+ term: F Concave 0.850 0.250
+ term: G Rectangle 1.750 2.250
+ term: H Discrete 2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000
+ term: I Gaussian 3.000 0.200
+ term: J Cosine 3.250 0.650
+ term: K GaussianProduct 3.500 0.100 3.300 0.300
+ term: L Spike 3.640 1.040
+ term: M Bell 4.000 0.250 3.000
+ term: N PiShape 4.000 4.500 4.500 5.000
+ term: O Concave 5.650 6.250
+ term: P SigmoidDifference 4.750 10.000 30.000 5.250
+ term: Q SigmoidProduct 5.250 20.000 -10.000 5.750
+ term: R Ramp 5.500 6.500
+ term: S SShape 5.500 6.500
+ term: T Sigmoid 6.000 20.000
+OutputVariable: AllOutputTerms
+ enabled: true
+ range: 0.000 6.500
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: A Sigmoid 0.500 -20.000
+ term: B ZShape 0.000 1.000
+ term: C Ramp 1.000 0.000
+ term: D Triangle 0.500 1.000 1.500
+ term: E Trapezoid 1.000 1.250 1.750 2.000
+ term: F Concave 0.850 0.250
+ term: G Rectangle 1.750 2.250
+ term: H Discrete 2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000
+ term: I Gaussian 3.000 0.200
+ term: J Cosine 3.250 0.650
+ term: K GaussianProduct 3.500 0.100 3.300 0.300
+ term: L Spike 3.640 1.040
+ term: M Bell 4.000 0.250 3.000
+ term: N PiShape 4.000 4.500 4.500 5.000
+ term: O Concave 5.650 6.250
+ term: P SigmoidDifference 4.750 10.000 30.000 5.250
+ term: Q SigmoidProduct 5.250 20.000 -10.000 5.750
+ term: R Ramp 5.500 6.500
+ term: S SShape 5.500 6.500
+ term: T Sigmoid 6.000 20.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if AllInputTerms is A then AllOutputTerms is T
+ rule: if AllInputTerms is B then AllOutputTerms is S
+ rule: if AllInputTerms is C then AllOutputTerms is R
+ rule: if AllInputTerms is D then AllOutputTerms is Q
+ rule: if AllInputTerms is E then AllOutputTerms is P
+ rule: if AllInputTerms is F then AllOutputTerms is O
+ rule: if AllInputTerms is G then AllOutputTerms is N
+ rule: if AllInputTerms is H then AllOutputTerms is M
+ rule: if AllInputTerms is I then AllOutputTerms is L
+ rule: if AllInputTerms is J then AllOutputTerms is K
+ rule: if AllInputTerms is K then AllOutputTerms is J
+ rule: if AllInputTerms is L then AllOutputTerms is I
+ rule: if AllInputTerms is M then AllOutputTerms is H
+ rule: if AllInputTerms is N then AllOutputTerms is G
+ rule: if AllInputTerms is O then AllOutputTerms is F
+ rule: if AllInputTerms is P then AllOutputTerms is E
+ rule: if AllInputTerms is Q then AllOutputTerms is D
+ rule: if AllInputTerms is R then AllOutputTerms is C
+ rule: if AllInputTerms is S then AllOutputTerms is B
+ rule: if AllInputTerms is T then AllOutputTerms is A \ No newline at end of file
diff --git a/examples/mamdani/AllTerms.java b/examples/mamdani/AllTerms.java
new file mode 100644
index 0000000..6d4651d
--- /dev/null
+++ b/examples/mamdani/AllTerms.java
@@ -0,0 +1,114 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class AllTerms{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("AllTerms");
+engine.setDescription("");
+
+InputVariable AllInputTerms = new InputVariable();
+AllInputTerms.setName("AllInputTerms");
+AllInputTerms.setDescription("");
+AllInputTerms.setEnabled(true);
+AllInputTerms.setRange(0.000, 6.500);
+AllInputTerms.setLockValueInRange(false);
+AllInputTerms.addTerm(new Sigmoid("A", 0.500, -20.000));
+AllInputTerms.addTerm(new ZShape("B", 0.000, 1.000));
+AllInputTerms.addTerm(new Ramp("C", 1.000, 0.000));
+AllInputTerms.addTerm(new Triangle("D", 0.500, 1.000, 1.500));
+AllInputTerms.addTerm(new Trapezoid("E", 1.000, 1.250, 1.750, 2.000));
+AllInputTerms.addTerm(new Concave("F", 0.850, 0.250));
+AllInputTerms.addTerm(new Rectangle("G", 1.750, 2.250));
+AllInputTerms.addTerm(Discrete.create("H", 2.000, 0.000, 2.250, 1.000, 2.500, 0.500, 2.750, 1.000, 3.000, 0.000));
+AllInputTerms.addTerm(new Gaussian("I", 3.000, 0.200));
+AllInputTerms.addTerm(new Cosine("J", 3.250, 0.650));
+AllInputTerms.addTerm(new GaussianProduct("K", 3.500, 0.100, 3.300, 0.300));
+AllInputTerms.addTerm(new Spike("L", 3.640, 1.040));
+AllInputTerms.addTerm(new Bell("M", 4.000, 0.250, 3.000));
+AllInputTerms.addTerm(new PiShape("N", 4.000, 4.500, 4.500, 5.000));
+AllInputTerms.addTerm(new Concave("O", 5.650, 6.250));
+AllInputTerms.addTerm(new SigmoidDifference("P", 4.750, 10.000, 30.000, 5.250));
+AllInputTerms.addTerm(new SigmoidProduct("Q", 5.250, 20.000, -10.000, 5.750));
+AllInputTerms.addTerm(new Ramp("R", 5.500, 6.500));
+AllInputTerms.addTerm(new SShape("S", 5.500, 6.500));
+AllInputTerms.addTerm(new Sigmoid("T", 6.000, 20.000));
+engine.addInputVariable(AllInputTerms);
+
+OutputVariable AllOutputTerms = new OutputVariable();
+AllOutputTerms.setName("AllOutputTerms");
+AllOutputTerms.setDescription("");
+AllOutputTerms.setEnabled(true);
+AllOutputTerms.setRange(0.000, 6.500);
+AllOutputTerms.setLockValueInRange(false);
+AllOutputTerms.setAggregation(new Maximum());
+AllOutputTerms.setDefuzzifier(new Centroid(200));
+AllOutputTerms.setDefaultValue(Double.NaN);
+AllOutputTerms.setLockPreviousValue(false);
+AllOutputTerms.addTerm(new Sigmoid("A", 0.500, -20.000));
+AllOutputTerms.addTerm(new ZShape("B", 0.000, 1.000));
+AllOutputTerms.addTerm(new Ramp("C", 1.000, 0.000));
+AllOutputTerms.addTerm(new Triangle("D", 0.500, 1.000, 1.500));
+AllOutputTerms.addTerm(new Trapezoid("E", 1.000, 1.250, 1.750, 2.000));
+AllOutputTerms.addTerm(new Concave("F", 0.850, 0.250));
+AllOutputTerms.addTerm(new Rectangle("G", 1.750, 2.250));
+AllOutputTerms.addTerm(Discrete.create("H", 2.000, 0.000, 2.250, 1.000, 2.500, 0.500, 2.750, 1.000, 3.000, 0.000));
+AllOutputTerms.addTerm(new Gaussian("I", 3.000, 0.200));
+AllOutputTerms.addTerm(new Cosine("J", 3.250, 0.650));
+AllOutputTerms.addTerm(new GaussianProduct("K", 3.500, 0.100, 3.300, 0.300));
+AllOutputTerms.addTerm(new Spike("L", 3.640, 1.040));
+AllOutputTerms.addTerm(new Bell("M", 4.000, 0.250, 3.000));
+AllOutputTerms.addTerm(new PiShape("N", 4.000, 4.500, 4.500, 5.000));
+AllOutputTerms.addTerm(new Concave("O", 5.650, 6.250));
+AllOutputTerms.addTerm(new SigmoidDifference("P", 4.750, 10.000, 30.000, 5.250));
+AllOutputTerms.addTerm(new SigmoidProduct("Q", 5.250, 20.000, -10.000, 5.750));
+AllOutputTerms.addTerm(new Ramp("R", 5.500, 6.500));
+AllOutputTerms.addTerm(new SShape("S", 5.500, 6.500));
+AllOutputTerms.addTerm(new Sigmoid("T", 6.000, 20.000));
+engine.addOutputVariable(AllOutputTerms);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new Minimum());
+ruleBlock.setDisjunction(new Maximum());
+ruleBlock.setImplication(new Minimum());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if AllInputTerms is A then AllOutputTerms is T", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is B then AllOutputTerms is S", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is C then AllOutputTerms is R", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is D then AllOutputTerms is Q", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is E then AllOutputTerms is P", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is F then AllOutputTerms is O", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is G then AllOutputTerms is N", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is H then AllOutputTerms is M", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is I then AllOutputTerms is L", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is J then AllOutputTerms is K", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is K then AllOutputTerms is J", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is L then AllOutputTerms is I", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is M then AllOutputTerms is H", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is N then AllOutputTerms is G", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is O then AllOutputTerms is F", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is P then AllOutputTerms is E", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is Q then AllOutputTerms is D", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is R then AllOutputTerms is C", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is S then AllOutputTerms is B", engine));
+ruleBlock.addRule(Rule.parse("if AllInputTerms is T then AllOutputTerms is A", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/AllTerms.pdf b/examples/mamdani/AllTerms.pdf
new file mode 100644
index 0000000..ed71111
--- /dev/null
+++ b/examples/mamdani/AllTerms.pdf
Binary files differ
diff --git a/examples/mamdani/Laundry.R b/examples/mamdani/Laundry.R
new file mode 100644
index 0000000..ca7d73d
--- /dev/null
+++ b/examples/mamdani/Laundry.R
@@ -0,0 +1,91 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "Laundry"
+engine.fll = "Engine: Laundry
+InputVariable: Load
+ enabled: true
+ range: 0.000 6.000
+ lock-range: false
+ term: small Discrete 0.000 1.000 1.000 1.000 2.000 0.800 5.000 0.000
+ term: normal Discrete 3.000 0.000 4.000 1.000 6.000 0.000
+InputVariable: Dirt
+ enabled: true
+ range: 0.000 6.000
+ lock-range: false
+ term: low Discrete 0.000 1.000 2.000 0.800 5.000 0.000
+ term: high Discrete 1.000 0.000 2.000 0.200 4.000 0.800 6.000 1.000
+OutputVariable: Detergent
+ enabled: true
+ range: 0.000 80.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: MeanOfMaximum 500
+ default: nan
+ lock-previous: false
+ term: less_than_usual Discrete 10.000 0.000 40.000 1.000 50.000 0.000
+ term: usual Discrete 40.000 0.000 50.000 1.000 60.000 1.000 80.000 0.000
+ term: more_than_usual Discrete 50.000 0.000 80.000 1.000
+OutputVariable: Cycle
+ enabled: true
+ range: 0.000 20.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: MeanOfMaximum 500
+ default: nan
+ lock-previous: false
+ term: short Discrete 0.000 1.000 10.000 1.000 20.000 0.000
+ term: long Discrete 10.000 0.000 20.000 1.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if Load is small and Dirt is not high then Detergent is less_than_usual
+ rule: if Load is small and Dirt is high then Detergent is usual
+ rule: if Load is normal and Dirt is low then Detergent is less_than_usual
+ rule: if Load is normal and Dirt is high then Detergent is more_than_usual
+ rule: if Detergent is usual or Detergent is less_than_usual then Cycle is short
+ rule: if Detergent is more_than_usual then Cycle is long"
+
+engine.fldFile = "Laundry.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(Load, Dirt)) +
+ geom_tile(aes(fill=Detergent)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Load, y=Dirt, z=Detergent), color="black") +
+ ggtitle("(Load, Dirt) = Detergent")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(Dirt, Load)) +
+ geom_tile(aes(fill=Detergent)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Dirt, y=Load, z=Detergent), color="black") +
+ ggtitle("(Dirt, Load) = Detergent")
+
+engine.plot.i1i2_o2 = ggplot(engine.df, aes(Load, Dirt)) +
+ geom_tile(aes(fill=Cycle)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Load, y=Dirt, z=Cycle), color="black") +
+ ggtitle("(Load, Dirt) = Cycle")
+
+engine.plot.i2i1_o2 = ggplot(engine.df, aes(Dirt, Load)) +
+ geom_tile(aes(fill=Cycle)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Dirt, y=Load, z=Cycle), color="black") +
+ ggtitle("(Dirt, Load) = Cycle")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, engine.plot.i1i2_o2, engine.plot.i2i1_o2, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/Laundry.cpp b/examples/mamdani/Laundry.cpp
new file mode 100644
index 0000000..cc7492c
--- /dev/null
+++ b/examples/mamdani/Laundry.cpp
@@ -0,0 +1,78 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("Laundry");
+engine->setDescription("");
+
+InputVariable* Load = new InputVariable;
+Load->setName("Load");
+Load->setDescription("");
+Load->setEnabled(true);
+Load->setRange(0.000, 6.000);
+Load->setLockValueInRange(false);
+Load->addTerm(Discrete::create("small", 8, 0.000, 1.000, 1.000, 1.000, 2.000, 0.800, 5.000, 0.000));
+Load->addTerm(Discrete::create("normal", 6, 3.000, 0.000, 4.000, 1.000, 6.000, 0.000));
+engine->addInputVariable(Load);
+
+InputVariable* Dirt = new InputVariable;
+Dirt->setName("Dirt");
+Dirt->setDescription("");
+Dirt->setEnabled(true);
+Dirt->setRange(0.000, 6.000);
+Dirt->setLockValueInRange(false);
+Dirt->addTerm(Discrete::create("low", 6, 0.000, 1.000, 2.000, 0.800, 5.000, 0.000));
+Dirt->addTerm(Discrete::create("high", 8, 1.000, 0.000, 2.000, 0.200, 4.000, 0.800, 6.000, 1.000));
+engine->addInputVariable(Dirt);
+
+OutputVariable* Detergent = new OutputVariable;
+Detergent->setName("Detergent");
+Detergent->setDescription("");
+Detergent->setEnabled(true);
+Detergent->setRange(0.000, 80.000);
+Detergent->setLockValueInRange(false);
+Detergent->setAggregation(new Maximum);
+Detergent->setDefuzzifier(new MeanOfMaximum(500));
+Detergent->setDefaultValue(fl::nan);
+Detergent->setLockPreviousValue(false);
+Detergent->addTerm(Discrete::create("less_than_usual", 6, 10.000, 0.000, 40.000, 1.000, 50.000, 0.000));
+Detergent->addTerm(Discrete::create("usual", 8, 40.000, 0.000, 50.000, 1.000, 60.000, 1.000, 80.000, 0.000));
+Detergent->addTerm(Discrete::create("more_than_usual", 4, 50.000, 0.000, 80.000, 1.000));
+engine->addOutputVariable(Detergent);
+
+OutputVariable* Cycle = new OutputVariable;
+Cycle->setName("Cycle");
+Cycle->setDescription("");
+Cycle->setEnabled(true);
+Cycle->setRange(0.000, 20.000);
+Cycle->setLockValueInRange(false);
+Cycle->setAggregation(new Maximum);
+Cycle->setDefuzzifier(new MeanOfMaximum(500));
+Cycle->setDefaultValue(fl::nan);
+Cycle->setLockPreviousValue(false);
+Cycle->addTerm(Discrete::create("short", 6, 0.000, 1.000, 10.000, 1.000, 20.000, 0.000));
+Cycle->addTerm(Discrete::create("long", 4, 10.000, 0.000, 20.000, 1.000));
+engine->addOutputVariable(Cycle);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new Minimum);
+ruleBlock->setDisjunction(new Maximum);
+ruleBlock->setImplication(new Minimum);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if Load is small and Dirt is not high then Detergent is less_than_usual", engine));
+ruleBlock->addRule(Rule::parse("if Load is small and Dirt is high then Detergent is usual", engine));
+ruleBlock->addRule(Rule::parse("if Load is normal and Dirt is low then Detergent is less_than_usual", engine));
+ruleBlock->addRule(Rule::parse("if Load is normal and Dirt is high then Detergent is more_than_usual", engine));
+ruleBlock->addRule(Rule::parse("if Detergent is usual or Detergent is less_than_usual then Cycle is short", engine));
+ruleBlock->addRule(Rule::parse("if Detergent is more_than_usual then Cycle is long", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/Laundry.fcl b/examples/mamdani/Laundry.fcl
new file mode 100644
index 0000000..9a34532
--- /dev/null
+++ b/examples/mamdani/Laundry.fcl
@@ -0,0 +1,58 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK Laundry
+
+VAR_INPUT
+ Load: REAL;
+ Dirt: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Detergent: REAL;
+ Cycle: REAL;
+END_VAR
+
+FUZZIFY Load
+ RANGE := (0.000 .. 6.000);
+ TERM small := (0.000, 1.000) (1.000, 1.000) (2.000, 0.800) (5.000, 0.000);
+ TERM normal := (3.000, 0.000) (4.000, 1.000) (6.000, 0.000);
+END_FUZZIFY
+
+FUZZIFY Dirt
+ RANGE := (0.000 .. 6.000);
+ TERM low := (0.000, 1.000) (2.000, 0.800) (5.000, 0.000);
+ TERM high := (1.000, 0.000) (2.000, 0.200) (4.000, 0.800) (6.000, 1.000);
+END_FUZZIFY
+
+DEFUZZIFY Detergent
+ RANGE := (0.000 .. 80.000);
+ TERM less_than_usual := (10.000, 0.000) (40.000, 1.000) (50.000, 0.000);
+ TERM usual := (40.000, 0.000) (50.000, 1.000) (60.000, 1.000) (80.000, 0.000);
+ TERM more_than_usual := (50.000, 0.000) (80.000, 1.000);
+ METHOD : MM;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY Cycle
+ RANGE := (0.000 .. 20.000);
+ TERM short := (0.000, 1.000) (10.000, 1.000) (20.000, 0.000);
+ TERM long := (10.000, 0.000) (20.000, 1.000);
+ METHOD : MM;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : MIN;
+ OR : MAX;
+ ACT : MIN;
+ RULE 1 : if Load is small and Dirt is not high then Detergent is less_than_usual
+ RULE 2 : if Load is small and Dirt is high then Detergent is usual
+ RULE 3 : if Load is normal and Dirt is low then Detergent is less_than_usual
+ RULE 4 : if Load is normal and Dirt is high then Detergent is more_than_usual
+ RULE 5 : if Detergent is usual or Detergent is less_than_usual then Cycle is short
+ RULE 6 : if Detergent is more_than_usual then Cycle is long
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/Laundry.fis b/examples/mamdani/Laundry.fis
new file mode 100644
index 0000000..7f1c31d
--- /dev/null
+++ b/examples/mamdani/Laundry.fis
@@ -0,0 +1,51 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='Laundry'
+Type='mamdani'
+Version=6.0
+NumInputs=2
+NumOutputs=2
+NumRules=6
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='mom'
+
+[Input1]
+Name='Load'
+Range=[0.000 6.000]
+NumMFs=2
+MF1='small':'discretemf',[0.000 1.000 1.000 1.000 2.000 0.800 5.000 0.000]
+MF2='normal':'discretemf',[3.000 0.000 4.000 1.000 6.000 0.000]
+
+[Input2]
+Name='Dirt'
+Range=[0.000 6.000]
+NumMFs=2
+MF1='low':'discretemf',[0.000 1.000 2.000 0.800 5.000 0.000]
+MF2='high':'discretemf',[1.000 0.000 2.000 0.200 4.000 0.800 6.000 1.000]
+
+[Output1]
+Name='Detergent'
+Range=[0.000 80.000]
+NumMFs=3
+MF1='less_than_usual':'discretemf',[10.000 0.000 40.000 1.000 50.000 0.000]
+MF2='usual':'discretemf',[40.000 0.000 50.000 1.000 60.000 1.000 80.000 0.000]
+MF3='more_than_usual':'discretemf',[50.000 0.000 80.000 1.000]
+
+[Output2]
+Name='Cycle'
+Range=[0.000 20.000]
+NumMFs=2
+MF1='short':'discretemf',[0.000 1.000 10.000 1.000 20.000 0.000]
+MF2='long':'discretemf',[10.000 0.000 20.000 1.000]
+
+[Rules]
+1.000 -2.000 , 1.000 0.000 (1.000) : 1
+1.000 2.000 , 2.000 0.000 (1.000) : 1
+2.000 1.000 , 1.000 0.000 (1.000) : 1
+2.000 2.000 , 3.000 0.000 (1.000) : 1
+0.000 0.000 , 0.000 1.000 (1.000) : 2
+0.000 0.000 , 0.000 2.000 (1.000) : 1
diff --git a/examples/mamdani/Laundry.fld b/examples/mamdani/Laundry.fld
new file mode 100644
index 0000000..a8f27dd
--- /dev/null
+++ b/examples/mamdani/Laundry.fld
@@ -0,0 +1,1025 @@
+Load Dirt Detergent Cycle
+0.000000000 0.000000000 39.920000000 5.000000000
+0.000000000 0.193548387 39.920000000 5.000000000
+0.000000000 0.387096774 39.920000000 5.000000000
+0.000000000 0.580645161 39.920000000 5.000000000
+0.000000000 0.774193548 39.920000000 5.000000000
+0.000000000 0.967741935 39.920000000 5.000000000
+0.000000000 1.161290323 39.680000000 5.160000000
+0.000000000 1.354838710 39.280000000 5.360000000
+0.000000000 1.548387097 38.880000000 5.540000000
+0.000000000 1.741935484 38.480000000 5.740000000
+0.000000000 1.935483871 38.160000000 5.940000000
+0.000000000 2.129032258 37.600000000 6.200000000
+0.000000000 2.322580645 37.040000000 6.480000000
+0.000000000 2.516129032 36.400000000 6.780000000
+0.000000000 2.709677419 35.920000000 7.060000000
+0.000000000 2.903225806 35.280000000 7.360000000
+0.000000000 3.096774194 57.360000000 7.360000000
+0.000000000 3.290322581 57.120000000 7.060000000
+0.000000000 3.483870968 56.720000000 6.780000000
+0.000000000 3.677419355 56.480000000 6.480000000
+0.000000000 3.870967742 56.240000000 6.200000000
+0.000000000 4.064516129 55.920000000 5.960000000
+0.000000000 4.258064516 55.920000000 5.880000000
+0.000000000 4.451612903 55.760000000 5.780000000
+0.000000000 4.645161290 55.680000000 5.680000000
+0.000000000 4.838709677 55.600000000 5.580000000
+0.000000000 5.032258065 55.440000000 5.480000000
+0.000000000 5.225806452 55.440000000 5.380000000
+0.000000000 5.419354839 55.280000000 5.300000000
+0.000000000 5.612903226 55.200000000 5.200000000
+0.000000000 5.806451613 55.040000000 5.100000000
+0.000000000 6.000000000 54.960000000 5.000000000
+0.193548387 0.000000000 39.920000000 5.000000000
+0.193548387 0.193548387 39.920000000 5.000000000
+0.193548387 0.387096774 39.920000000 5.000000000
+0.193548387 0.580645161 39.920000000 5.000000000
+0.193548387 0.774193548 39.920000000 5.000000000
+0.193548387 0.967741935 39.920000000 5.000000000
+0.193548387 1.161290323 39.680000000 5.160000000
+0.193548387 1.354838710 39.280000000 5.360000000
+0.193548387 1.548387097 38.880000000 5.540000000
+0.193548387 1.741935484 38.480000000 5.740000000
+0.193548387 1.935483871 38.160000000 5.940000000
+0.193548387 2.129032258 37.600000000 6.200000000
+0.193548387 2.322580645 37.040000000 6.480000000
+0.193548387 2.516129032 36.400000000 6.780000000
+0.193548387 2.709677419 35.920000000 7.060000000
+0.193548387 2.903225806 35.280000000 7.360000000
+0.193548387 3.096774194 57.360000000 7.360000000
+0.193548387 3.290322581 57.120000000 7.060000000
+0.193548387 3.483870968 56.720000000 6.780000000
+0.193548387 3.677419355 56.480000000 6.480000000
+0.193548387 3.870967742 56.240000000 6.200000000
+0.193548387 4.064516129 55.920000000 5.960000000
+0.193548387 4.258064516 55.920000000 5.880000000
+0.193548387 4.451612903 55.760000000 5.780000000
+0.193548387 4.645161290 55.680000000 5.680000000
+0.193548387 4.838709677 55.600000000 5.580000000
+0.193548387 5.032258065 55.440000000 5.480000000
+0.193548387 5.225806452 55.440000000 5.380000000
+0.193548387 5.419354839 55.280000000 5.300000000
+0.193548387 5.612903226 55.200000000 5.200000000
+0.193548387 5.806451613 55.040000000 5.100000000
+0.193548387 6.000000000 54.960000000 5.000000000
+0.387096774 0.000000000 39.920000000 5.000000000
+0.387096774 0.193548387 39.920000000 5.000000000
+0.387096774 0.387096774 39.920000000 5.000000000
+0.387096774 0.580645161 39.920000000 5.000000000
+0.387096774 0.774193548 39.920000000 5.000000000
+0.387096774 0.967741935 39.920000000 5.000000000
+0.387096774 1.161290323 39.680000000 5.160000000
+0.387096774 1.354838710 39.280000000 5.360000000
+0.387096774 1.548387097 38.880000000 5.540000000
+0.387096774 1.741935484 38.480000000 5.740000000
+0.387096774 1.935483871 38.160000000 5.940000000
+0.387096774 2.129032258 37.600000000 6.200000000
+0.387096774 2.322580645 37.040000000 6.480000000
+0.387096774 2.516129032 36.400000000 6.780000000
+0.387096774 2.709677419 35.920000000 7.060000000
+0.387096774 2.903225806 35.280000000 7.360000000
+0.387096774 3.096774194 57.360000000 7.360000000
+0.387096774 3.290322581 57.120000000 7.060000000
+0.387096774 3.483870968 56.720000000 6.780000000
+0.387096774 3.677419355 56.480000000 6.480000000
+0.387096774 3.870967742 56.240000000 6.200000000
+0.387096774 4.064516129 55.920000000 5.960000000
+0.387096774 4.258064516 55.920000000 5.880000000
+0.387096774 4.451612903 55.760000000 5.780000000
+0.387096774 4.645161290 55.680000000 5.680000000
+0.387096774 4.838709677 55.600000000 5.580000000
+0.387096774 5.032258065 55.440000000 5.480000000
+0.387096774 5.225806452 55.440000000 5.380000000
+0.387096774 5.419354839 55.280000000 5.300000000
+0.387096774 5.612903226 55.200000000 5.200000000
+0.387096774 5.806451613 55.040000000 5.100000000
+0.387096774 6.000000000 54.960000000 5.000000000
+0.580645161 0.000000000 39.920000000 5.000000000
+0.580645161 0.193548387 39.920000000 5.000000000
+0.580645161 0.387096774 39.920000000 5.000000000
+0.580645161 0.580645161 39.920000000 5.000000000
+0.580645161 0.774193548 39.920000000 5.000000000
+0.580645161 0.967741935 39.920000000 5.000000000
+0.580645161 1.161290323 39.680000000 5.160000000
+0.580645161 1.354838710 39.280000000 5.360000000
+0.580645161 1.548387097 38.880000000 5.540000000
+0.580645161 1.741935484 38.480000000 5.740000000
+0.580645161 1.935483871 38.160000000 5.940000000
+0.580645161 2.129032258 37.600000000 6.200000000
+0.580645161 2.322580645 37.040000000 6.480000000
+0.580645161 2.516129032 36.400000000 6.780000000
+0.580645161 2.709677419 35.920000000 7.060000000
+0.580645161 2.903225806 35.280000000 7.360000000
+0.580645161 3.096774194 57.360000000 7.360000000
+0.580645161 3.290322581 57.120000000 7.060000000
+0.580645161 3.483870968 56.720000000 6.780000000
+0.580645161 3.677419355 56.480000000 6.480000000
+0.580645161 3.870967742 56.240000000 6.200000000
+0.580645161 4.064516129 55.920000000 5.960000000
+0.580645161 4.258064516 55.920000000 5.880000000
+0.580645161 4.451612903 55.760000000 5.780000000
+0.580645161 4.645161290 55.680000000 5.680000000
+0.580645161 4.838709677 55.600000000 5.580000000
+0.580645161 5.032258065 55.440000000 5.480000000
+0.580645161 5.225806452 55.440000000 5.380000000
+0.580645161 5.419354839 55.280000000 5.300000000
+0.580645161 5.612903226 55.200000000 5.200000000
+0.580645161 5.806451613 55.040000000 5.100000000
+0.580645161 6.000000000 54.960000000 5.000000000
+0.774193548 0.000000000 39.920000000 5.000000000
+0.774193548 0.193548387 39.920000000 5.000000000
+0.774193548 0.387096774 39.920000000 5.000000000
+0.774193548 0.580645161 39.920000000 5.000000000
+0.774193548 0.774193548 39.920000000 5.000000000
+0.774193548 0.967741935 39.920000000 5.000000000
+0.774193548 1.161290323 39.680000000 5.160000000
+0.774193548 1.354838710 39.280000000 5.360000000
+0.774193548 1.548387097 38.880000000 5.540000000
+0.774193548 1.741935484 38.480000000 5.740000000
+0.774193548 1.935483871 38.160000000 5.940000000
+0.774193548 2.129032258 37.600000000 6.200000000
+0.774193548 2.322580645 37.040000000 6.480000000
+0.774193548 2.516129032 36.400000000 6.780000000
+0.774193548 2.709677419 35.920000000 7.060000000
+0.774193548 2.903225806 35.280000000 7.360000000
+0.774193548 3.096774194 57.360000000 7.360000000
+0.774193548 3.290322581 57.120000000 7.060000000
+0.774193548 3.483870968 56.720000000 6.780000000
+0.774193548 3.677419355 56.480000000 6.480000000
+0.774193548 3.870967742 56.240000000 6.200000000
+0.774193548 4.064516129 55.920000000 5.960000000
+0.774193548 4.258064516 55.920000000 5.880000000
+0.774193548 4.451612903 55.760000000 5.780000000
+0.774193548 4.645161290 55.680000000 5.680000000
+0.774193548 4.838709677 55.600000000 5.580000000
+0.774193548 5.032258065 55.440000000 5.480000000
+0.774193548 5.225806452 55.440000000 5.380000000
+0.774193548 5.419354839 55.280000000 5.300000000
+0.774193548 5.612903226 55.200000000 5.200000000
+0.774193548 5.806451613 55.040000000 5.100000000
+0.774193548 6.000000000 54.960000000 5.000000000
+0.967741935 0.000000000 39.920000000 5.000000000
+0.967741935 0.193548387 39.920000000 5.000000000
+0.967741935 0.387096774 39.920000000 5.000000000
+0.967741935 0.580645161 39.920000000 5.000000000
+0.967741935 0.774193548 39.920000000 5.000000000
+0.967741935 0.967741935 39.920000000 5.000000000
+0.967741935 1.161290323 39.680000000 5.160000000
+0.967741935 1.354838710 39.280000000 5.360000000
+0.967741935 1.548387097 38.880000000 5.540000000
+0.967741935 1.741935484 38.480000000 5.740000000
+0.967741935 1.935483871 38.160000000 5.940000000
+0.967741935 2.129032258 37.600000000 6.200000000
+0.967741935 2.322580645 37.040000000 6.480000000
+0.967741935 2.516129032 36.400000000 6.780000000
+0.967741935 2.709677419 35.920000000 7.060000000
+0.967741935 2.903225806 35.280000000 7.360000000
+0.967741935 3.096774194 57.360000000 7.360000000
+0.967741935 3.290322581 57.120000000 7.060000000
+0.967741935 3.483870968 56.720000000 6.780000000
+0.967741935 3.677419355 56.480000000 6.480000000
+0.967741935 3.870967742 56.240000000 6.200000000
+0.967741935 4.064516129 55.920000000 5.960000000
+0.967741935 4.258064516 55.920000000 5.880000000
+0.967741935 4.451612903 55.760000000 5.780000000
+0.967741935 4.645161290 55.680000000 5.680000000
+0.967741935 4.838709677 55.600000000 5.580000000
+0.967741935 5.032258065 55.440000000 5.480000000
+0.967741935 5.225806452 55.440000000 5.380000000
+0.967741935 5.419354839 55.280000000 5.300000000
+0.967741935 5.612903226 55.200000000 5.200000000
+0.967741935 5.806451613 55.040000000 5.100000000
+0.967741935 6.000000000 54.960000000 5.000000000
+1.161290323 0.000000000 39.680000000 5.160000000
+1.161290323 0.193548387 39.680000000 5.160000000
+1.161290323 0.387096774 39.680000000 5.160000000
+1.161290323 0.580645161 39.680000000 5.160000000
+1.161290323 0.774193548 39.680000000 5.160000000
+1.161290323 0.967741935 39.680000000 5.160000000
+1.161290323 1.161290323 39.680000000 5.160000000
+1.161290323 1.354838710 39.280000000 5.360000000
+1.161290323 1.548387097 38.880000000 5.540000000
+1.161290323 1.741935484 38.480000000 5.740000000
+1.161290323 1.935483871 38.160000000 5.940000000
+1.161290323 2.129032258 37.600000000 6.200000000
+1.161290323 2.322580645 37.040000000 6.480000000
+1.161290323 2.516129032 36.400000000 6.780000000
+1.161290323 2.709677419 35.920000000 7.060000000
+1.161290323 2.903225806 35.280000000 7.360000000
+1.161290323 3.096774194 57.360000000 7.360000000
+1.161290323 3.290322581 57.120000000 7.060000000
+1.161290323 3.483870968 56.720000000 6.780000000
+1.161290323 3.677419355 56.480000000 6.480000000
+1.161290323 3.870967742 56.240000000 6.200000000
+1.161290323 4.064516129 55.920000000 5.960000000
+1.161290323 4.258064516 55.920000000 5.880000000
+1.161290323 4.451612903 55.760000000 5.780000000
+1.161290323 4.645161290 55.680000000 5.680000000
+1.161290323 4.838709677 55.600000000 5.580000000
+1.161290323 5.032258065 55.440000000 5.480000000
+1.161290323 5.225806452 55.440000000 5.380000000
+1.161290323 5.419354839 55.280000000 5.300000000
+1.161290323 5.612903226 55.200000000 5.200000000
+1.161290323 5.806451613 55.120000000 5.160000000
+1.161290323 6.000000000 55.120000000 5.160000000
+1.354838710 0.000000000 39.280000000 5.360000000
+1.354838710 0.193548387 39.280000000 5.360000000
+1.354838710 0.387096774 39.280000000 5.360000000
+1.354838710 0.580645161 39.280000000 5.360000000
+1.354838710 0.774193548 39.280000000 5.360000000
+1.354838710 0.967741935 39.280000000 5.360000000
+1.354838710 1.161290323 39.280000000 5.360000000
+1.354838710 1.354838710 39.280000000 5.360000000
+1.354838710 1.548387097 38.880000000 5.540000000
+1.354838710 1.741935484 38.480000000 5.740000000
+1.354838710 1.935483871 38.160000000 5.940000000
+1.354838710 2.129032258 37.600000000 6.200000000
+1.354838710 2.322580645 37.040000000 6.480000000
+1.354838710 2.516129032 36.400000000 6.780000000
+1.354838710 2.709677419 35.920000000 7.060000000
+1.354838710 2.903225806 35.280000000 7.360000000
+1.354838710 3.096774194 57.360000000 7.360000000
+1.354838710 3.290322581 57.120000000 7.060000000
+1.354838710 3.483870968 56.720000000 6.780000000
+1.354838710 3.677419355 56.480000000 6.480000000
+1.354838710 3.870967742 56.240000000 6.200000000
+1.354838710 4.064516129 55.920000000 5.960000000
+1.354838710 4.258064516 55.920000000 5.880000000
+1.354838710 4.451612903 55.760000000 5.780000000
+1.354838710 4.645161290 55.680000000 5.680000000
+1.354838710 4.838709677 55.600000000 5.580000000
+1.354838710 5.032258065 55.440000000 5.480000000
+1.354838710 5.225806452 55.440000000 5.380000000
+1.354838710 5.419354839 55.360000000 5.360000000
+1.354838710 5.612903226 55.360000000 5.360000000
+1.354838710 5.806451613 55.360000000 5.360000000
+1.354838710 6.000000000 55.360000000 5.360000000
+1.548387097 0.000000000 38.880000000 5.540000000
+1.548387097 0.193548387 38.880000000 5.540000000
+1.548387097 0.387096774 38.880000000 5.540000000
+1.548387097 0.580645161 38.880000000 5.540000000
+1.548387097 0.774193548 38.880000000 5.540000000
+1.548387097 0.967741935 38.880000000 5.540000000
+1.548387097 1.161290323 38.880000000 5.540000000
+1.548387097 1.354838710 38.880000000 5.540000000
+1.548387097 1.548387097 38.880000000 5.540000000
+1.548387097 1.741935484 38.480000000 5.740000000
+1.548387097 1.935483871 38.160000000 5.940000000
+1.548387097 2.129032258 37.600000000 6.200000000
+1.548387097 2.322580645 37.040000000 6.480000000
+1.548387097 2.516129032 36.400000000 6.780000000
+1.548387097 2.709677419 35.920000000 7.060000000
+1.548387097 2.903225806 35.280000000 7.360000000
+1.548387097 3.096774194 57.360000000 7.360000000
+1.548387097 3.290322581 57.120000000 7.060000000
+1.548387097 3.483870968 56.720000000 6.780000000
+1.548387097 3.677419355 56.480000000 6.480000000
+1.548387097 3.870967742 56.240000000 6.200000000
+1.548387097 4.064516129 55.920000000 5.960000000
+1.548387097 4.258064516 55.920000000 5.880000000
+1.548387097 4.451612903 55.760000000 5.780000000
+1.548387097 4.645161290 55.680000000 5.680000000
+1.548387097 4.838709677 55.600000000 5.580000000
+1.548387097 5.032258065 55.600000000 5.540000000
+1.548387097 5.225806452 55.600000000 5.540000000
+1.548387097 5.419354839 55.600000000 5.540000000
+1.548387097 5.612903226 55.600000000 5.540000000
+1.548387097 5.806451613 55.600000000 5.540000000
+1.548387097 6.000000000 55.600000000 5.540000000
+1.741935484 0.000000000 38.480000000 5.740000000
+1.741935484 0.193548387 38.480000000 5.740000000
+1.741935484 0.387096774 38.480000000 5.740000000
+1.741935484 0.580645161 38.480000000 5.740000000
+1.741935484 0.774193548 38.480000000 5.740000000
+1.741935484 0.967741935 38.480000000 5.740000000
+1.741935484 1.161290323 38.480000000 5.740000000
+1.741935484 1.354838710 38.480000000 5.740000000
+1.741935484 1.548387097 38.480000000 5.740000000
+1.741935484 1.741935484 38.480000000 5.740000000
+1.741935484 1.935483871 38.160000000 5.940000000
+1.741935484 2.129032258 37.600000000 6.200000000
+1.741935484 2.322580645 37.040000000 6.480000000
+1.741935484 2.516129032 36.400000000 6.780000000
+1.741935484 2.709677419 35.920000000 7.060000000
+1.741935484 2.903225806 35.280000000 7.360000000
+1.741935484 3.096774194 57.360000000 7.360000000
+1.741935484 3.290322581 57.120000000 7.060000000
+1.741935484 3.483870968 56.720000000 6.780000000
+1.741935484 3.677419355 56.480000000 6.480000000
+1.741935484 3.870967742 56.240000000 6.200000000
+1.741935484 4.064516129 55.920000000 5.960000000
+1.741935484 4.258064516 55.920000000 5.880000000
+1.741935484 4.451612903 55.760000000 5.780000000
+1.741935484 4.645161290 55.760000000 5.740000000
+1.741935484 4.838709677 55.760000000 5.740000000
+1.741935484 5.032258065 55.760000000 5.740000000
+1.741935484 5.225806452 55.760000000 5.740000000
+1.741935484 5.419354839 55.760000000 5.740000000
+1.741935484 5.612903226 55.760000000 5.740000000
+1.741935484 5.806451613 55.760000000 5.740000000
+1.741935484 6.000000000 55.760000000 5.740000000
+1.935483871 0.000000000 38.160000000 5.940000000
+1.935483871 0.193548387 38.160000000 5.940000000
+1.935483871 0.387096774 38.160000000 5.940000000
+1.935483871 0.580645161 38.160000000 5.940000000
+1.935483871 0.774193548 38.160000000 5.940000000
+1.935483871 0.967741935 38.160000000 5.940000000
+1.935483871 1.161290323 38.160000000 5.940000000
+1.935483871 1.354838710 38.160000000 5.940000000
+1.935483871 1.548387097 38.160000000 5.940000000
+1.935483871 1.741935484 38.160000000 5.940000000
+1.935483871 1.935483871 38.160000000 5.940000000
+1.935483871 2.129032258 37.600000000 6.200000000
+1.935483871 2.322580645 37.040000000 6.480000000
+1.935483871 2.516129032 36.400000000 6.780000000
+1.935483871 2.709677419 35.920000000 7.060000000
+1.935483871 2.903225806 35.280000000 7.360000000
+1.935483871 3.096774194 57.360000000 7.360000000
+1.935483871 3.290322581 57.120000000 7.060000000
+1.935483871 3.483870968 56.720000000 6.780000000
+1.935483871 3.677419355 56.480000000 6.480000000
+1.935483871 3.870967742 56.240000000 6.200000000
+1.935483871 4.064516129 55.920000000 5.960000000
+1.935483871 4.258064516 55.920000000 5.940000000
+1.935483871 4.451612903 55.920000000 5.940000000
+1.935483871 4.645161290 55.920000000 5.940000000
+1.935483871 4.838709677 55.920000000 5.940000000
+1.935483871 5.032258065 55.920000000 5.940000000
+1.935483871 5.225806452 55.920000000 5.940000000
+1.935483871 5.419354839 55.920000000 5.940000000
+1.935483871 5.612903226 55.920000000 5.940000000
+1.935483871 5.806451613 55.920000000 5.940000000
+1.935483871 6.000000000 55.920000000 5.940000000
+2.129032258 0.000000000 37.680000000 6.180000000
+2.129032258 0.193548387 37.680000000 6.180000000
+2.129032258 0.387096774 37.680000000 6.180000000
+2.129032258 0.580645161 37.680000000 6.180000000
+2.129032258 0.774193548 37.680000000 6.180000000
+2.129032258 0.967741935 37.680000000 6.180000000
+2.129032258 1.161290323 37.680000000 6.180000000
+2.129032258 1.354838710 37.680000000 6.180000000
+2.129032258 1.548387097 37.680000000 6.180000000
+2.129032258 1.741935484 37.680000000 6.180000000
+2.129032258 1.935483871 37.680000000 6.180000000
+2.129032258 2.129032258 37.600000000 6.200000000
+2.129032258 2.322580645 37.040000000 6.480000000
+2.129032258 2.516129032 36.400000000 6.780000000
+2.129032258 2.709677419 35.920000000 7.060000000
+2.129032258 2.903225806 35.280000000 7.360000000
+2.129032258 3.096774194 57.360000000 7.360000000
+2.129032258 3.290322581 57.120000000 7.060000000
+2.129032258 3.483870968 56.720000000 6.780000000
+2.129032258 3.677419355 56.480000000 6.480000000
+2.129032258 3.870967742 56.240000000 6.200000000
+2.129032258 4.064516129 56.160000000 6.180000000
+2.129032258 4.258064516 56.160000000 6.180000000
+2.129032258 4.451612903 56.160000000 6.180000000
+2.129032258 4.645161290 56.160000000 6.180000000
+2.129032258 4.838709677 56.160000000 6.180000000
+2.129032258 5.032258065 56.160000000 6.180000000
+2.129032258 5.225806452 56.160000000 6.180000000
+2.129032258 5.419354839 56.160000000 6.180000000
+2.129032258 5.612903226 56.160000000 6.180000000
+2.129032258 5.806451613 56.160000000 6.180000000
+2.129032258 6.000000000 56.160000000 6.180000000
+2.322580645 0.000000000 37.120000000 6.440000000
+2.322580645 0.193548387 37.120000000 6.440000000
+2.322580645 0.387096774 37.120000000 6.440000000
+2.322580645 0.580645161 37.120000000 6.440000000
+2.322580645 0.774193548 37.120000000 6.440000000
+2.322580645 0.967741935 37.120000000 6.440000000
+2.322580645 1.161290323 37.120000000 6.440000000
+2.322580645 1.354838710 37.120000000 6.440000000
+2.322580645 1.548387097 37.120000000 6.440000000
+2.322580645 1.741935484 37.120000000 6.440000000
+2.322580645 1.935483871 37.120000000 6.440000000
+2.322580645 2.129032258 37.120000000 6.440000000
+2.322580645 2.322580645 37.040000000 6.480000000
+2.322580645 2.516129032 36.400000000 6.780000000
+2.322580645 2.709677419 35.920000000 7.060000000
+2.322580645 2.903225806 35.280000000 7.360000000
+2.322580645 3.096774194 57.360000000 7.360000000
+2.322580645 3.290322581 57.120000000 7.060000000
+2.322580645 3.483870968 56.720000000 6.780000000
+2.322580645 3.677419355 56.480000000 6.480000000
+2.322580645 3.870967742 56.480000000 6.440000000
+2.322580645 4.064516129 56.480000000 6.440000000
+2.322580645 4.258064516 56.480000000 6.440000000
+2.322580645 4.451612903 56.480000000 6.440000000
+2.322580645 4.645161290 56.480000000 6.440000000
+2.322580645 4.838709677 56.480000000 6.440000000
+2.322580645 5.032258065 56.480000000 6.440000000
+2.322580645 5.225806452 56.480000000 6.440000000
+2.322580645 5.419354839 56.480000000 6.440000000
+2.322580645 5.612903226 56.480000000 6.440000000
+2.322580645 5.806451613 56.480000000 6.440000000
+2.322580645 6.000000000 56.480000000 6.440000000
+2.516129032 0.000000000 36.640000000 6.680000000
+2.516129032 0.193548387 36.640000000 6.680000000
+2.516129032 0.387096774 36.640000000 6.680000000
+2.516129032 0.580645161 36.640000000 6.680000000
+2.516129032 0.774193548 36.640000000 6.680000000
+2.516129032 0.967741935 36.640000000 6.680000000
+2.516129032 1.161290323 36.640000000 6.680000000
+2.516129032 1.354838710 36.640000000 6.680000000
+2.516129032 1.548387097 36.640000000 6.680000000
+2.516129032 1.741935484 36.640000000 6.680000000
+2.516129032 1.935483871 36.640000000 6.680000000
+2.516129032 2.129032258 36.640000000 6.680000000
+2.516129032 2.322580645 36.640000000 6.680000000
+2.516129032 2.516129032 36.400000000 6.780000000
+2.516129032 2.709677419 35.920000000 7.060000000
+2.516129032 2.903225806 35.280000000 7.360000000
+2.516129032 3.096774194 57.360000000 7.360000000
+2.516129032 3.290322581 57.120000000 7.060000000
+2.516129032 3.483870968 56.720000000 6.780000000
+2.516129032 3.677419355 56.640000000 6.680000000
+2.516129032 3.870967742 56.640000000 6.680000000
+2.516129032 4.064516129 56.640000000 6.680000000
+2.516129032 4.258064516 56.640000000 6.680000000
+2.516129032 4.451612903 56.640000000 6.680000000
+2.516129032 4.645161290 56.640000000 6.680000000
+2.516129032 4.838709677 56.640000000 6.680000000
+2.516129032 5.032258065 56.640000000 6.680000000
+2.516129032 5.225806452 56.640000000 6.680000000
+2.516129032 5.419354839 56.640000000 6.680000000
+2.516129032 5.612903226 56.640000000 6.680000000
+2.516129032 5.806451613 56.640000000 6.680000000
+2.516129032 6.000000000 56.640000000 6.680000000
+2.709677419 0.000000000 36.080000000 6.940000000
+2.709677419 0.193548387 36.080000000 6.940000000
+2.709677419 0.387096774 36.080000000 6.940000000
+2.709677419 0.580645161 36.080000000 6.940000000
+2.709677419 0.774193548 36.080000000 6.940000000
+2.709677419 0.967741935 36.080000000 6.940000000
+2.709677419 1.161290323 36.080000000 6.940000000
+2.709677419 1.354838710 36.080000000 6.940000000
+2.709677419 1.548387097 36.080000000 6.940000000
+2.709677419 1.741935484 36.080000000 6.940000000
+2.709677419 1.935483871 36.080000000 6.940000000
+2.709677419 2.129032258 36.080000000 6.940000000
+2.709677419 2.322580645 36.080000000 6.940000000
+2.709677419 2.516129032 36.080000000 6.940000000
+2.709677419 2.709677419 35.920000000 7.060000000
+2.709677419 2.903225806 35.280000000 7.360000000
+2.709677419 3.096774194 57.360000000 7.360000000
+2.709677419 3.290322581 57.120000000 7.060000000
+2.709677419 3.483870968 56.960000000 6.940000000
+2.709677419 3.677419355 56.960000000 6.940000000
+2.709677419 3.870967742 56.960000000 6.940000000
+2.709677419 4.064516129 56.960000000 6.940000000
+2.709677419 4.258064516 56.960000000 6.940000000
+2.709677419 4.451612903 56.960000000 6.940000000
+2.709677419 4.645161290 56.960000000 6.940000000
+2.709677419 4.838709677 56.960000000 6.940000000
+2.709677419 5.032258065 56.960000000 6.940000000
+2.709677419 5.225806452 56.960000000 6.940000000
+2.709677419 5.419354839 56.960000000 6.940000000
+2.709677419 5.612903226 56.960000000 6.940000000
+2.709677419 5.806451613 56.960000000 6.940000000
+2.709677419 6.000000000 56.960000000 6.940000000
+2.903225806 0.000000000 35.600000000 7.200000000
+2.903225806 0.193548387 35.600000000 7.200000000
+2.903225806 0.387096774 35.600000000 7.200000000
+2.903225806 0.580645161 35.600000000 7.200000000
+2.903225806 0.774193548 35.600000000 7.200000000
+2.903225806 0.967741935 35.600000000 7.200000000
+2.903225806 1.161290323 35.600000000 7.200000000
+2.903225806 1.354838710 35.600000000 7.200000000
+2.903225806 1.548387097 35.600000000 7.200000000
+2.903225806 1.741935484 35.600000000 7.200000000
+2.903225806 1.935483871 35.600000000 7.200000000
+2.903225806 2.129032258 35.600000000 7.200000000
+2.903225806 2.322580645 35.600000000 7.200000000
+2.903225806 2.516129032 35.600000000 7.200000000
+2.903225806 2.709677419 35.600000000 7.200000000
+2.903225806 2.903225806 35.280000000 7.360000000
+2.903225806 3.096774194 57.360000000 7.360000000
+2.903225806 3.290322581 57.200000000 7.200000000
+2.903225806 3.483870968 57.200000000 7.200000000
+2.903225806 3.677419355 57.200000000 7.200000000
+2.903225806 3.870967742 57.200000000 7.200000000
+2.903225806 4.064516129 57.200000000 7.200000000
+2.903225806 4.258064516 57.200000000 7.200000000
+2.903225806 4.451612903 57.200000000 7.200000000
+2.903225806 4.645161290 57.200000000 7.200000000
+2.903225806 4.838709677 57.200000000 7.200000000
+2.903225806 5.032258065 57.200000000 7.200000000
+2.903225806 5.225806452 57.200000000 7.200000000
+2.903225806 5.419354839 57.200000000 7.200000000
+2.903225806 5.612903226 57.200000000 7.200000000
+2.903225806 5.806451613 57.200000000 7.200000000
+2.903225806 6.000000000 57.200000000 7.200000000
+3.096774194 0.000000000 35.120000000 7.460000000
+3.096774194 0.193548387 35.120000000 7.460000000
+3.096774194 0.387096774 35.120000000 7.460000000
+3.096774194 0.580645161 35.120000000 7.460000000
+3.096774194 0.774193548 35.120000000 7.460000000
+3.096774194 0.967741935 35.120000000 7.460000000
+3.096774194 1.161290323 35.120000000 7.460000000
+3.096774194 1.354838710 35.120000000 7.460000000
+3.096774194 1.548387097 35.120000000 7.460000000
+3.096774194 1.741935484 35.120000000 7.460000000
+3.096774194 1.935483871 35.120000000 7.460000000
+3.096774194 2.129032258 35.120000000 7.460000000
+3.096774194 2.322580645 35.120000000 7.460000000
+3.096774194 2.516129032 35.120000000 7.460000000
+3.096774194 2.709677419 35.120000000 7.460000000
+3.096774194 2.903225806 35.120000000 7.460000000
+3.096774194 3.096774194 57.520000000 7.460000000
+3.096774194 3.290322581 57.520000000 7.460000000
+3.096774194 3.483870968 57.520000000 7.460000000
+3.096774194 3.677419355 57.520000000 7.460000000
+3.096774194 3.870967742 57.520000000 7.460000000
+3.096774194 4.064516129 57.520000000 7.460000000
+3.096774194 4.258064516 57.520000000 7.460000000
+3.096774194 4.451612903 57.520000000 7.460000000
+3.096774194 4.645161290 57.520000000 7.460000000
+3.096774194 4.838709677 57.520000000 7.460000000
+3.096774194 5.032258065 57.520000000 7.460000000
+3.096774194 5.225806452 57.520000000 7.460000000
+3.096774194 5.419354839 57.520000000 7.460000000
+3.096774194 5.612903226 57.520000000 7.460000000
+3.096774194 5.806451613 57.520000000 7.460000000
+3.096774194 6.000000000 57.520000000 7.460000000
+3.290322581 0.000000000 34.560000000 7.720000000
+3.290322581 0.193548387 34.560000000 7.720000000
+3.290322581 0.387096774 34.560000000 7.720000000
+3.290322581 0.580645161 34.560000000 7.720000000
+3.290322581 0.774193548 34.560000000 7.720000000
+3.290322581 0.967741935 34.560000000 7.720000000
+3.290322581 1.161290323 34.560000000 7.720000000
+3.290322581 1.354838710 34.560000000 7.720000000
+3.290322581 1.548387097 34.560000000 7.720000000
+3.290322581 1.741935484 34.560000000 7.720000000
+3.290322581 1.935483871 34.560000000 7.720000000
+3.290322581 2.129032258 34.560000000 7.720000000
+3.290322581 2.322580645 34.560000000 7.720000000
+3.290322581 2.516129032 34.560000000 7.720000000
+3.290322581 2.709677419 34.560000000 7.720000000
+3.290322581 2.903225806 47.280000000 7.720000000
+3.290322581 3.096774194 47.280000000 7.720000000
+3.290322581 3.290322581 57.680000000 7.720000000
+3.290322581 3.483870968 57.680000000 7.720000000
+3.290322581 3.677419355 57.680000000 7.720000000
+3.290322581 3.870967742 57.680000000 7.720000000
+3.290322581 4.064516129 57.680000000 7.720000000
+3.290322581 4.258064516 57.680000000 7.720000000
+3.290322581 4.451612903 57.680000000 7.720000000
+3.290322581 4.645161290 57.680000000 7.720000000
+3.290322581 4.838709677 57.680000000 7.720000000
+3.290322581 5.032258065 57.680000000 7.720000000
+3.290322581 5.225806452 57.680000000 7.720000000
+3.290322581 5.419354839 57.680000000 7.720000000
+3.290322581 5.612903226 57.680000000 7.720000000
+3.290322581 5.806451613 57.680000000 7.720000000
+3.290322581 6.000000000 57.680000000 7.720000000
+3.483870968 0.000000000 34.800000000 7.580000000
+3.483870968 0.193548387 34.800000000 7.580000000
+3.483870968 0.387096774 34.800000000 7.580000000
+3.483870968 0.580645161 34.800000000 7.580000000
+3.483870968 0.774193548 34.800000000 7.580000000
+3.483870968 0.967741935 34.800000000 7.580000000
+3.483870968 1.161290323 34.800000000 7.580000000
+3.483870968 1.354838710 34.800000000 7.580000000
+3.483870968 1.548387097 34.800000000 7.580000000
+3.483870968 1.741935484 34.800000000 7.580000000
+3.483870968 1.935483871 34.800000000 7.580000000
+3.483870968 2.129032258 34.800000000 7.580000000
+3.483870968 2.322580645 34.800000000 7.580000000
+3.483870968 2.516129032 34.800000000 7.580000000
+3.483870968 2.709677419 34.800000000 7.580000000
+3.483870968 2.903225806 34.800000000 7.580000000
+3.483870968 3.096774194 34.800000000 10.000000000
+3.483870968 3.290322581 72.240000000 17.420000000
+3.483870968 3.483870968 72.240000000 17.420000000
+3.483870968 3.677419355 72.240000000 17.420000000
+3.483870968 3.870967742 72.240000000 17.420000000
+3.483870968 4.064516129 72.240000000 17.420000000
+3.483870968 4.258064516 72.240000000 17.420000000
+3.483870968 4.451612903 72.240000000 17.420000000
+3.483870968 4.645161290 72.240000000 17.420000000
+3.483870968 4.838709677 72.240000000 17.420000000
+3.483870968 5.032258065 72.240000000 17.420000000
+3.483870968 5.225806452 72.240000000 17.420000000
+3.483870968 5.419354839 72.240000000 17.420000000
+3.483870968 5.612903226 72.240000000 17.420000000
+3.483870968 5.806451613 72.240000000 17.420000000
+3.483870968 6.000000000 72.240000000 17.420000000
+3.677419355 0.000000000 36.800000000 6.620000000
+3.677419355 0.193548387 36.800000000 6.620000000
+3.677419355 0.387096774 36.800000000 6.620000000
+3.677419355 0.580645161 36.800000000 6.620000000
+3.677419355 0.774193548 36.800000000 6.620000000
+3.677419355 0.967741935 36.800000000 6.620000000
+3.677419355 1.161290323 36.800000000 6.620000000
+3.677419355 1.354838710 36.800000000 6.620000000
+3.677419355 1.548387097 36.800000000 6.620000000
+3.677419355 1.741935484 36.800000000 6.620000000
+3.677419355 1.935483871 36.800000000 6.620000000
+3.677419355 2.129032258 36.800000000 6.620000000
+3.677419355 2.322580645 36.800000000 6.620000000
+3.677419355 2.516129032 36.640000000 6.680000000
+3.677419355 2.709677419 36.080000000 6.940000000
+3.677419355 2.903225806 35.600000000 7.200000000
+3.677419355 3.096774194 72.960000000 17.640000000
+3.677419355 3.290322581 73.840000000 17.940000000
+3.677419355 3.483870968 74.640000000 18.220000000
+3.677419355 3.677419355 75.200000000 18.380000000
+3.677419355 3.870967742 75.200000000 18.380000000
+3.677419355 4.064516129 75.200000000 18.380000000
+3.677419355 4.258064516 75.200000000 18.380000000
+3.677419355 4.451612903 75.200000000 18.380000000
+3.677419355 4.645161290 75.200000000 18.380000000
+3.677419355 4.838709677 75.200000000 18.380000000
+3.677419355 5.032258065 75.200000000 18.380000000
+3.677419355 5.225806452 75.200000000 18.380000000
+3.677419355 5.419354839 75.200000000 18.380000000
+3.677419355 5.612903226 75.200000000 18.380000000
+3.677419355 5.806451613 75.200000000 18.380000000
+3.677419355 6.000000000 75.200000000 18.380000000
+3.870967742 0.000000000 38.720000000 5.640000000
+3.870967742 0.193548387 38.720000000 5.640000000
+3.870967742 0.387096774 38.720000000 5.640000000
+3.870967742 0.580645161 38.720000000 5.640000000
+3.870967742 0.774193548 38.720000000 5.640000000
+3.870967742 0.967741935 38.720000000 5.640000000
+3.870967742 1.161290323 38.720000000 5.640000000
+3.870967742 1.354838710 38.640000000 5.680000000
+3.870967742 1.548387097 38.480000000 5.780000000
+3.870967742 1.741935484 38.240000000 5.880000000
+3.870967742 1.935483871 38.080000000 5.960000000
+3.870967742 2.129032258 37.680000000 6.180000000
+3.870967742 2.322580645 37.120000000 6.440000000
+3.870967742 2.516129032 36.640000000 6.680000000
+3.870967742 2.709677419 36.080000000 6.940000000
+3.870967742 2.903225806 35.600000000 7.200000000
+3.870967742 3.096774194 72.960000000 17.640000000
+3.870967742 3.290322581 73.840000000 17.940000000
+3.870967742 3.483870968 74.640000000 18.220000000
+3.870967742 3.677419355 75.520000000 18.520000000
+3.870967742 3.870967742 76.400000000 18.800000000
+3.870967742 4.064516129 77.120000000 19.040000000
+3.870967742 4.258064516 77.360000000 19.120000000
+3.870967742 4.451612903 77.680000000 19.220000000
+3.870967742 4.645161290 78.000000000 19.320000000
+3.870967742 4.838709677 78.080000000 19.360000000
+3.870967742 5.032258065 78.080000000 19.360000000
+3.870967742 5.225806452 78.080000000 19.360000000
+3.870967742 5.419354839 78.080000000 19.360000000
+3.870967742 5.612903226 78.080000000 19.360000000
+3.870967742 5.806451613 78.080000000 19.360000000
+3.870967742 6.000000000 78.080000000 19.360000000
+4.064516129 0.000000000 39.680000000 5.160000000
+4.064516129 0.193548387 39.680000000 5.160000000
+4.064516129 0.387096774 39.600000000 5.200000000
+4.064516129 0.580645161 39.440000000 5.300000000
+4.064516129 0.774193548 39.200000000 5.380000000
+4.064516129 0.967741935 39.040000000 5.480000000
+4.064516129 1.161290323 38.800000000 5.580000000
+4.064516129 1.354838710 38.640000000 5.680000000
+4.064516129 1.548387097 38.480000000 5.780000000
+4.064516129 1.741935484 38.240000000 5.880000000
+4.064516129 1.935483871 38.080000000 5.960000000
+4.064516129 2.129032258 37.680000000 6.180000000
+4.064516129 2.322580645 37.120000000 6.440000000
+4.064516129 2.516129032 36.640000000 6.680000000
+4.064516129 2.709677419 36.080000000 6.940000000
+4.064516129 2.903225806 35.600000000 7.200000000
+4.064516129 3.096774194 72.960000000 17.640000000
+4.064516129 3.290322581 73.840000000 17.940000000
+4.064516129 3.483870968 74.640000000 18.220000000
+4.064516129 3.677419355 75.520000000 18.520000000
+4.064516129 3.870967742 76.400000000 18.800000000
+4.064516129 4.064516129 77.120000000 19.040000000
+4.064516129 4.258064516 77.360000000 19.120000000
+4.064516129 4.451612903 77.680000000 19.220000000
+4.064516129 4.645161290 78.000000000 19.320000000
+4.064516129 4.838709677 78.240000000 19.420000000
+4.064516129 5.032258065 78.560000000 19.520000000
+4.064516129 5.225806452 78.800000000 19.620000000
+4.064516129 5.419354839 79.120000000 19.700000000
+4.064516129 5.612903226 79.440000000 19.800000000
+4.064516129 5.806451613 79.520000000 19.840000000
+4.064516129 6.000000000 79.520000000 19.840000000
+4.258064516 0.000000000 38.720000000 5.640000000
+4.258064516 0.193548387 38.720000000 5.640000000
+4.258064516 0.387096774 38.720000000 5.640000000
+4.258064516 0.580645161 38.720000000 5.640000000
+4.258064516 0.774193548 38.720000000 5.640000000
+4.258064516 0.967741935 38.720000000 5.640000000
+4.258064516 1.161290323 38.720000000 5.640000000
+4.258064516 1.354838710 38.640000000 5.680000000
+4.258064516 1.548387097 38.480000000 5.780000000
+4.258064516 1.741935484 38.240000000 5.880000000
+4.258064516 1.935483871 38.080000000 5.960000000
+4.258064516 2.129032258 37.680000000 6.180000000
+4.258064516 2.322580645 37.120000000 6.440000000
+4.258064516 2.516129032 36.640000000 6.680000000
+4.258064516 2.709677419 36.080000000 6.940000000
+4.258064516 2.903225806 35.600000000 7.200000000
+4.258064516 3.096774194 72.960000000 17.640000000
+4.258064516 3.290322581 73.840000000 17.940000000
+4.258064516 3.483870968 74.640000000 18.220000000
+4.258064516 3.677419355 75.520000000 18.520000000
+4.258064516 3.870967742 76.400000000 18.800000000
+4.258064516 4.064516129 77.120000000 19.040000000
+4.258064516 4.258064516 77.360000000 19.120000000
+4.258064516 4.451612903 77.680000000 19.220000000
+4.258064516 4.645161290 78.000000000 19.320000000
+4.258064516 4.838709677 78.080000000 19.360000000
+4.258064516 5.032258065 78.080000000 19.360000000
+4.258064516 5.225806452 78.080000000 19.360000000
+4.258064516 5.419354839 78.080000000 19.360000000
+4.258064516 5.612903226 78.080000000 19.360000000
+4.258064516 5.806451613 78.080000000 19.360000000
+4.258064516 6.000000000 78.080000000 19.360000000
+4.451612903 0.000000000 37.760000000 6.120000000
+4.451612903 0.193548387 37.760000000 6.120000000
+4.451612903 0.387096774 37.760000000 6.120000000
+4.451612903 0.580645161 37.760000000 6.120000000
+4.451612903 0.774193548 37.760000000 6.120000000
+4.451612903 0.967741935 37.760000000 6.120000000
+4.451612903 1.161290323 37.760000000 6.120000000
+4.451612903 1.354838710 37.760000000 6.120000000
+4.451612903 1.548387097 37.760000000 6.120000000
+4.451612903 1.741935484 37.760000000 6.120000000
+4.451612903 1.935483871 37.760000000 6.120000000
+4.451612903 2.129032258 37.680000000 6.180000000
+4.451612903 2.322580645 37.120000000 6.440000000
+4.451612903 2.516129032 36.640000000 6.680000000
+4.451612903 2.709677419 36.080000000 6.940000000
+4.451612903 2.903225806 35.600000000 7.200000000
+4.451612903 3.096774194 72.960000000 17.640000000
+4.451612903 3.290322581 73.840000000 17.940000000
+4.451612903 3.483870968 74.640000000 18.220000000
+4.451612903 3.677419355 75.520000000 18.520000000
+4.451612903 3.870967742 76.400000000 18.800000000
+4.451612903 4.064516129 76.640000000 18.880000000
+4.451612903 4.258064516 76.640000000 18.880000000
+4.451612903 4.451612903 76.640000000 18.880000000
+4.451612903 4.645161290 76.640000000 18.880000000
+4.451612903 4.838709677 76.640000000 18.880000000
+4.451612903 5.032258065 76.640000000 18.880000000
+4.451612903 5.225806452 76.640000000 18.880000000
+4.451612903 5.419354839 76.640000000 18.880000000
+4.451612903 5.612903226 76.640000000 18.880000000
+4.451612903 5.806451613 76.640000000 18.880000000
+4.451612903 6.000000000 76.640000000 18.880000000
+4.645161290 0.000000000 36.800000000 6.620000000
+4.645161290 0.193548387 36.800000000 6.620000000
+4.645161290 0.387096774 36.800000000 6.620000000
+4.645161290 0.580645161 36.800000000 6.620000000
+4.645161290 0.774193548 36.800000000 6.620000000
+4.645161290 0.967741935 36.800000000 6.620000000
+4.645161290 1.161290323 36.800000000 6.620000000
+4.645161290 1.354838710 36.800000000 6.620000000
+4.645161290 1.548387097 36.800000000 6.620000000
+4.645161290 1.741935484 36.800000000 6.620000000
+4.645161290 1.935483871 36.800000000 6.620000000
+4.645161290 2.129032258 36.800000000 6.620000000
+4.645161290 2.322580645 36.800000000 6.620000000
+4.645161290 2.516129032 36.640000000 6.680000000
+4.645161290 2.709677419 36.080000000 6.940000000
+4.645161290 2.903225806 35.600000000 7.200000000
+4.645161290 3.096774194 72.960000000 17.640000000
+4.645161290 3.290322581 73.840000000 17.940000000
+4.645161290 3.483870968 74.640000000 18.220000000
+4.645161290 3.677419355 75.200000000 18.380000000
+4.645161290 3.870967742 75.200000000 18.380000000
+4.645161290 4.064516129 75.200000000 18.380000000
+4.645161290 4.258064516 75.200000000 18.380000000
+4.645161290 4.451612903 75.200000000 18.380000000
+4.645161290 4.645161290 75.200000000 18.380000000
+4.645161290 4.838709677 75.200000000 18.380000000
+4.645161290 5.032258065 75.200000000 18.380000000
+4.645161290 5.225806452 75.200000000 18.380000000
+4.645161290 5.419354839 75.200000000 18.380000000
+4.645161290 5.612903226 75.200000000 18.380000000
+4.645161290 5.806451613 75.200000000 18.380000000
+4.645161290 6.000000000 75.200000000 18.380000000
+4.838709677 0.000000000 35.760000000 7.100000000
+4.838709677 0.193548387 35.760000000 7.100000000
+4.838709677 0.387096774 35.760000000 7.100000000
+4.838709677 0.580645161 35.760000000 7.100000000
+4.838709677 0.774193548 35.760000000 7.100000000
+4.838709677 0.967741935 35.760000000 7.100000000
+4.838709677 1.161290323 35.760000000 7.100000000
+4.838709677 1.354838710 35.760000000 7.100000000
+4.838709677 1.548387097 35.760000000 7.100000000
+4.838709677 1.741935484 35.760000000 7.100000000
+4.838709677 1.935483871 35.760000000 7.100000000
+4.838709677 2.129032258 35.760000000 7.100000000
+4.838709677 2.322580645 35.760000000 7.100000000
+4.838709677 2.516129032 35.760000000 7.100000000
+4.838709677 2.709677419 35.760000000 7.100000000
+4.838709677 2.903225806 35.600000000 7.200000000
+4.838709677 3.096774194 72.960000000 17.640000000
+4.838709677 3.290322581 73.680000000 17.900000000
+4.838709677 3.483870968 73.680000000 17.900000000
+4.838709677 3.677419355 73.680000000 17.900000000
+4.838709677 3.870967742 73.680000000 17.900000000
+4.838709677 4.064516129 73.680000000 17.900000000
+4.838709677 4.258064516 73.680000000 17.900000000
+4.838709677 4.451612903 73.680000000 17.900000000
+4.838709677 4.645161290 73.680000000 17.900000000
+4.838709677 4.838709677 73.680000000 17.900000000
+4.838709677 5.032258065 73.680000000 17.900000000
+4.838709677 5.225806452 73.680000000 17.900000000
+4.838709677 5.419354839 73.680000000 17.900000000
+4.838709677 5.612903226 73.680000000 17.900000000
+4.838709677 5.806451613 73.680000000 17.900000000
+4.838709677 6.000000000 73.680000000 17.900000000
+5.032258065 0.000000000 34.800000000 7.580000000
+5.032258065 0.193548387 34.800000000 7.580000000
+5.032258065 0.387096774 34.800000000 7.580000000
+5.032258065 0.580645161 34.800000000 7.580000000
+5.032258065 0.774193548 34.800000000 7.580000000
+5.032258065 0.967741935 34.800000000 7.580000000
+5.032258065 1.161290323 34.800000000 7.580000000
+5.032258065 1.354838710 34.800000000 7.580000000
+5.032258065 1.548387097 34.800000000 7.580000000
+5.032258065 1.741935484 34.800000000 7.580000000
+5.032258065 1.935483871 34.800000000 7.580000000
+5.032258065 2.129032258 34.800000000 7.580000000
+5.032258065 2.322580645 34.800000000 7.580000000
+5.032258065 2.516129032 34.800000000 7.580000000
+5.032258065 2.709677419 34.800000000 7.580000000
+5.032258065 2.903225806 34.800000000 7.580000000
+5.032258065 3.096774194 34.800000000 10.000000000
+5.032258065 3.290322581 72.240000000 17.420000000
+5.032258065 3.483870968 72.240000000 17.420000000
+5.032258065 3.677419355 72.240000000 17.420000000
+5.032258065 3.870967742 72.240000000 17.420000000
+5.032258065 4.064516129 72.240000000 17.420000000
+5.032258065 4.258064516 72.240000000 17.420000000
+5.032258065 4.451612903 72.240000000 17.420000000
+5.032258065 4.645161290 72.240000000 17.420000000
+5.032258065 4.838709677 72.240000000 17.420000000
+5.032258065 5.032258065 72.240000000 17.420000000
+5.032258065 5.225806452 72.240000000 17.420000000
+5.032258065 5.419354839 72.240000000 17.420000000
+5.032258065 5.612903226 72.240000000 17.420000000
+5.032258065 5.806451613 72.240000000 17.420000000
+5.032258065 6.000000000 72.240000000 17.420000000
+5.225806452 0.000000000 33.840000000 8.060000000
+5.225806452 0.193548387 33.840000000 8.060000000
+5.225806452 0.387096774 33.840000000 8.060000000
+5.225806452 0.580645161 33.840000000 8.060000000
+5.225806452 0.774193548 33.840000000 8.060000000
+5.225806452 0.967741935 33.840000000 8.060000000
+5.225806452 1.161290323 33.840000000 8.060000000
+5.225806452 1.354838710 33.840000000 8.060000000
+5.225806452 1.548387097 33.840000000 8.060000000
+5.225806452 1.741935484 33.840000000 8.060000000
+5.225806452 1.935483871 33.840000000 8.060000000
+5.225806452 2.129032258 33.840000000 8.060000000
+5.225806452 2.322580645 33.840000000 8.060000000
+5.225806452 2.516129032 33.840000000 8.060000000
+5.225806452 2.709677419 33.840000000 10.000000000
+5.225806452 2.903225806 33.840000000 10.000000000
+5.225806452 3.096774194 33.840000000 10.000000000
+5.225806452 3.290322581 33.840000000 10.000000000
+5.225806452 3.483870968 33.840000000 10.000000000
+5.225806452 3.677419355 70.800000000 16.940000000
+5.225806452 3.870967742 70.800000000 16.940000000
+5.225806452 4.064516129 70.800000000 16.940000000
+5.225806452 4.258064516 70.800000000 16.940000000
+5.225806452 4.451612903 70.800000000 16.940000000
+5.225806452 4.645161290 70.800000000 16.940000000
+5.225806452 4.838709677 70.800000000 16.940000000
+5.225806452 5.032258065 70.800000000 16.940000000
+5.225806452 5.225806452 70.800000000 16.940000000
+5.225806452 5.419354839 70.800000000 16.940000000
+5.225806452 5.612903226 70.800000000 16.940000000
+5.225806452 5.806451613 70.800000000 16.940000000
+5.225806452 6.000000000 70.800000000 16.940000000
+5.419354839 0.000000000 32.880000000 8.540000000
+5.419354839 0.193548387 32.880000000 8.540000000
+5.419354839 0.387096774 32.880000000 8.540000000
+5.419354839 0.580645161 32.880000000 8.540000000
+5.419354839 0.774193548 32.880000000 8.540000000
+5.419354839 0.967741935 32.880000000 8.540000000
+5.419354839 1.161290323 32.880000000 8.540000000
+5.419354839 1.354838710 32.880000000 8.540000000
+5.419354839 1.548387097 32.880000000 8.540000000
+5.419354839 1.741935484 32.880000000 8.540000000
+5.419354839 1.935483871 32.880000000 8.540000000
+5.419354839 2.129032258 32.880000000 8.540000000
+5.419354839 2.322580645 32.880000000 10.000000000
+5.419354839 2.516129032 32.880000000 10.000000000
+5.419354839 2.709677419 32.880000000 10.000000000
+5.419354839 2.903225806 32.880000000 10.000000000
+5.419354839 3.096774194 32.880000000 10.000000000
+5.419354839 3.290322581 32.880000000 10.000000000
+5.419354839 3.483870968 32.880000000 10.000000000
+5.419354839 3.677419355 32.880000000 10.000000000
+5.419354839 3.870967742 32.880000000 10.000000000
+5.419354839 4.064516129 69.360000000 16.460000000
+5.419354839 4.258064516 69.360000000 16.460000000
+5.419354839 4.451612903 69.360000000 16.460000000
+5.419354839 4.645161290 69.360000000 16.460000000
+5.419354839 4.838709677 69.360000000 16.460000000
+5.419354839 5.032258065 69.360000000 16.460000000
+5.419354839 5.225806452 69.360000000 16.460000000
+5.419354839 5.419354839 69.360000000 16.460000000
+5.419354839 5.612903226 69.360000000 16.460000000
+5.419354839 5.806451613 69.360000000 16.460000000
+5.419354839 6.000000000 69.360000000 16.460000000
+5.612903226 0.000000000 31.920000000 9.040000000
+5.612903226 0.193548387 31.920000000 9.040000000
+5.612903226 0.387096774 31.920000000 9.040000000
+5.612903226 0.580645161 31.920000000 9.040000000
+5.612903226 0.774193548 31.920000000 9.040000000
+5.612903226 0.967741935 31.920000000 9.040000000
+5.612903226 1.161290323 31.920000000 9.040000000
+5.612903226 1.354838710 31.920000000 9.040000000
+5.612903226 1.548387097 31.920000000 9.040000000
+5.612903226 1.741935484 31.920000000 9.040000000
+5.612903226 1.935483871 31.920000000 9.040000000
+5.612903226 2.129032258 31.920000000 10.000000000
+5.612903226 2.322580645 31.920000000 10.000000000
+5.612903226 2.516129032 31.920000000 10.000000000
+5.612903226 2.709677419 31.920000000 10.000000000
+5.612903226 2.903225806 31.920000000 10.000000000
+5.612903226 3.096774194 31.920000000 10.000000000
+5.612903226 3.290322581 31.920000000 10.000000000
+5.612903226 3.483870968 31.920000000 10.000000000
+5.612903226 3.677419355 31.920000000 10.000000000
+5.612903226 3.870967742 31.920000000 10.000000000
+5.612903226 4.064516129 31.920000000 10.000000000
+5.612903226 4.258064516 31.920000000 10.000000000
+5.612903226 4.451612903 67.920000000 15.960000000
+5.612903226 4.645161290 67.920000000 15.960000000
+5.612903226 4.838709677 67.920000000 15.960000000
+5.612903226 5.032258065 67.920000000 15.960000000
+5.612903226 5.225806452 67.920000000 15.960000000
+5.612903226 5.419354839 67.920000000 15.960000000
+5.612903226 5.612903226 67.920000000 15.960000000
+5.612903226 5.806451613 67.920000000 15.960000000
+5.612903226 6.000000000 67.920000000 15.960000000
+5.806451613 0.000000000 30.960000000 9.520000000
+5.806451613 0.193548387 30.960000000 9.520000000
+5.806451613 0.387096774 30.960000000 9.520000000
+5.806451613 0.580645161 30.960000000 9.520000000
+5.806451613 0.774193548 30.960000000 9.520000000
+5.806451613 0.967741935 30.960000000 9.520000000
+5.806451613 1.161290323 30.960000000 9.520000000
+5.806451613 1.354838710 30.960000000 9.520000000
+5.806451613 1.548387097 30.960000000 10.000000000
+5.806451613 1.741935484 30.960000000 10.000000000
+5.806451613 1.935483871 30.960000000 10.000000000
+5.806451613 2.129032258 30.960000000 10.000000000
+5.806451613 2.322580645 30.960000000 10.000000000
+5.806451613 2.516129032 30.960000000 10.000000000
+5.806451613 2.709677419 30.960000000 10.000000000
+5.806451613 2.903225806 30.960000000 10.000000000
+5.806451613 3.096774194 30.960000000 10.000000000
+5.806451613 3.290322581 30.960000000 10.000000000
+5.806451613 3.483870968 30.960000000 10.000000000
+5.806451613 3.677419355 30.960000000 10.000000000
+5.806451613 3.870967742 30.960000000 10.000000000
+5.806451613 4.064516129 30.960000000 10.000000000
+5.806451613 4.258064516 30.960000000 10.000000000
+5.806451613 4.451612903 30.960000000 10.000000000
+5.806451613 4.645161290 66.480000000 15.480000000
+5.806451613 4.838709677 66.480000000 15.480000000
+5.806451613 5.032258065 66.480000000 15.480000000
+5.806451613 5.225806452 66.480000000 15.480000000
+5.806451613 5.419354839 66.480000000 15.480000000
+5.806451613 5.612903226 66.480000000 15.480000000
+5.806451613 5.806451613 66.480000000 15.480000000
+5.806451613 6.000000000 66.480000000 15.480000000
+6.000000000 0.000000000 nan nan
+6.000000000 0.193548387 nan nan
+6.000000000 0.387096774 nan nan
+6.000000000 0.580645161 nan nan
+6.000000000 0.774193548 nan nan
+6.000000000 0.967741935 nan nan
+6.000000000 1.161290323 nan nan
+6.000000000 1.354838710 nan nan
+6.000000000 1.548387097 nan nan
+6.000000000 1.741935484 nan nan
+6.000000000 1.935483871 nan nan
+6.000000000 2.129032258 nan nan
+6.000000000 2.322580645 nan nan
+6.000000000 2.516129032 nan nan
+6.000000000 2.709677419 nan nan
+6.000000000 2.903225806 nan nan
+6.000000000 3.096774194 nan nan
+6.000000000 3.290322581 nan nan
+6.000000000 3.483870968 nan nan
+6.000000000 3.677419355 nan nan
+6.000000000 3.870967742 nan nan
+6.000000000 4.064516129 nan nan
+6.000000000 4.258064516 nan nan
+6.000000000 4.451612903 nan nan
+6.000000000 4.645161290 nan nan
+6.000000000 4.838709677 nan nan
+6.000000000 5.032258065 nan nan
+6.000000000 5.225806452 nan nan
+6.000000000 5.419354839 nan nan
+6.000000000 5.612903226 nan nan
+6.000000000 5.806451613 nan nan
+6.000000000 6.000000000 nan nan
diff --git a/examples/mamdani/Laundry.fll b/examples/mamdani/Laundry.fll
new file mode 100644
index 0000000..6abf2df
--- /dev/null
+++ b/examples/mamdani/Laundry.fll
@@ -0,0 +1,46 @@
+Engine: Laundry
+InputVariable: Load
+ enabled: true
+ range: 0.000 6.000
+ lock-range: false
+ term: small Discrete 0.000 1.000 1.000 1.000 2.000 0.800 5.000 0.000
+ term: normal Discrete 3.000 0.000 4.000 1.000 6.000 0.000
+InputVariable: Dirt
+ enabled: true
+ range: 0.000 6.000
+ lock-range: false
+ term: low Discrete 0.000 1.000 2.000 0.800 5.000 0.000
+ term: high Discrete 1.000 0.000 2.000 0.200 4.000 0.800 6.000 1.000
+OutputVariable: Detergent
+ enabled: true
+ range: 0.000 80.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: MeanOfMaximum 500
+ default: nan
+ lock-previous: false
+ term: less_than_usual Discrete 10.000 0.000 40.000 1.000 50.000 0.000
+ term: usual Discrete 40.000 0.000 50.000 1.000 60.000 1.000 80.000 0.000
+ term: more_than_usual Discrete 50.000 0.000 80.000 1.000
+OutputVariable: Cycle
+ enabled: true
+ range: 0.000 20.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: MeanOfMaximum 500
+ default: nan
+ lock-previous: false
+ term: short Discrete 0.000 1.000 10.000 1.000 20.000 0.000
+ term: long Discrete 10.000 0.000 20.000 1.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if Load is small and Dirt is not high then Detergent is less_than_usual
+ rule: if Load is small and Dirt is high then Detergent is usual
+ rule: if Load is normal and Dirt is low then Detergent is less_than_usual
+ rule: if Load is normal and Dirt is high then Detergent is more_than_usual
+ rule: if Detergent is usual or Detergent is less_than_usual then Cycle is short
+ rule: if Detergent is more_than_usual then Cycle is long \ No newline at end of file
diff --git a/examples/mamdani/Laundry.java b/examples/mamdani/Laundry.java
new file mode 100644
index 0000000..95cbe7c
--- /dev/null
+++ b/examples/mamdani/Laundry.java
@@ -0,0 +1,89 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class Laundry{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("Laundry");
+engine.setDescription("");
+
+InputVariable Load = new InputVariable();
+Load.setName("Load");
+Load.setDescription("");
+Load.setEnabled(true);
+Load.setRange(0.000, 6.000);
+Load.setLockValueInRange(false);
+Load.addTerm(Discrete.create("small", 0.000, 1.000, 1.000, 1.000, 2.000, 0.800, 5.000, 0.000));
+Load.addTerm(Discrete.create("normal", 3.000, 0.000, 4.000, 1.000, 6.000, 0.000));
+engine.addInputVariable(Load);
+
+InputVariable Dirt = new InputVariable();
+Dirt.setName("Dirt");
+Dirt.setDescription("");
+Dirt.setEnabled(true);
+Dirt.setRange(0.000, 6.000);
+Dirt.setLockValueInRange(false);
+Dirt.addTerm(Discrete.create("low", 0.000, 1.000, 2.000, 0.800, 5.000, 0.000));
+Dirt.addTerm(Discrete.create("high", 1.000, 0.000, 2.000, 0.200, 4.000, 0.800, 6.000, 1.000));
+engine.addInputVariable(Dirt);
+
+OutputVariable Detergent = new OutputVariable();
+Detergent.setName("Detergent");
+Detergent.setDescription("");
+Detergent.setEnabled(true);
+Detergent.setRange(0.000, 80.000);
+Detergent.setLockValueInRange(false);
+Detergent.setAggregation(new Maximum());
+Detergent.setDefuzzifier(new MeanOfMaximum(500));
+Detergent.setDefaultValue(Double.NaN);
+Detergent.setLockPreviousValue(false);
+Detergent.addTerm(Discrete.create("less_than_usual", 10.000, 0.000, 40.000, 1.000, 50.000, 0.000));
+Detergent.addTerm(Discrete.create("usual", 40.000, 0.000, 50.000, 1.000, 60.000, 1.000, 80.000, 0.000));
+Detergent.addTerm(Discrete.create("more_than_usual", 50.000, 0.000, 80.000, 1.000));
+engine.addOutputVariable(Detergent);
+
+OutputVariable Cycle = new OutputVariable();
+Cycle.setName("Cycle");
+Cycle.setDescription("");
+Cycle.setEnabled(true);
+Cycle.setRange(0.000, 20.000);
+Cycle.setLockValueInRange(false);
+Cycle.setAggregation(new Maximum());
+Cycle.setDefuzzifier(new MeanOfMaximum(500));
+Cycle.setDefaultValue(Double.NaN);
+Cycle.setLockPreviousValue(false);
+Cycle.addTerm(Discrete.create("short", 0.000, 1.000, 10.000, 1.000, 20.000, 0.000));
+Cycle.addTerm(Discrete.create("long", 10.000, 0.000, 20.000, 1.000));
+engine.addOutputVariable(Cycle);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new Minimum());
+ruleBlock.setDisjunction(new Maximum());
+ruleBlock.setImplication(new Minimum());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if Load is small and Dirt is not high then Detergent is less_than_usual", engine));
+ruleBlock.addRule(Rule.parse("if Load is small and Dirt is high then Detergent is usual", engine));
+ruleBlock.addRule(Rule.parse("if Load is normal and Dirt is low then Detergent is less_than_usual", engine));
+ruleBlock.addRule(Rule.parse("if Load is normal and Dirt is high then Detergent is more_than_usual", engine));
+ruleBlock.addRule(Rule.parse("if Detergent is usual or Detergent is less_than_usual then Cycle is short", engine));
+ruleBlock.addRule(Rule.parse("if Detergent is more_than_usual then Cycle is long", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/Laundry.pdf b/examples/mamdani/Laundry.pdf
new file mode 100644
index 0000000..42df3cf
--- /dev/null
+++ b/examples/mamdani/Laundry.pdf
Binary files differ
diff --git a/examples/mamdani/ObstacleAvoidance.R b/examples/mamdani/ObstacleAvoidance.R
new file mode 100644
index 0000000..5533d26
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.R
@@ -0,0 +1,57 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "ObstacleAvoidance"
+engine.fll = "Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: mSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+RuleBlock: mamdani
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: AlgebraicProduct
+ activation: General
+ rule: if obstacle is left then mSteer is right
+ rule: if obstacle is right then mSteer is left"
+
+engine.fldFile = "ObstacleAvoidance.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(obstacle, mSteer)) +
+ geom_line(aes(color=mSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("obstacle vs mSteer")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(obstacle, mSteer)) +
+ geom_line(aes(color=mSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("mSteer vs obstacle")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/ObstacleAvoidance.cpp b/examples/mamdani/ObstacleAvoidance.cpp
new file mode 100644
index 0000000..341ffe5
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.cpp
@@ -0,0 +1,49 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("ObstacleAvoidance");
+engine->setDescription("");
+
+InputVariable* obstacle = new InputVariable;
+obstacle->setName("obstacle");
+obstacle->setDescription("");
+obstacle->setEnabled(true);
+obstacle->setRange(0.000, 1.000);
+obstacle->setLockValueInRange(false);
+obstacle->addTerm(new Ramp("left", 1.000, 0.000));
+obstacle->addTerm(new Ramp("right", 0.000, 1.000));
+engine->addInputVariable(obstacle);
+
+OutputVariable* mSteer = new OutputVariable;
+mSteer->setName("mSteer");
+mSteer->setDescription("");
+mSteer->setEnabled(true);
+mSteer->setRange(0.000, 1.000);
+mSteer->setLockValueInRange(false);
+mSteer->setAggregation(new Maximum);
+mSteer->setDefuzzifier(new Centroid(100));
+mSteer->setDefaultValue(fl::nan);
+mSteer->setLockPreviousValue(false);
+mSteer->addTerm(new Ramp("left", 1.000, 0.000));
+mSteer->addTerm(new Ramp("right", 0.000, 1.000));
+engine->addOutputVariable(mSteer);
+
+RuleBlock* mamdani = new RuleBlock;
+mamdani->setName("mamdani");
+mamdani->setDescription("");
+mamdani->setEnabled(true);
+mamdani->setConjunction(fl::null);
+mamdani->setDisjunction(fl::null);
+mamdani->setImplication(new AlgebraicProduct);
+mamdani->setActivation(new General);
+mamdani->addRule(Rule::parse("if obstacle is left then mSteer is right", engine));
+mamdani->addRule(Rule::parse("if obstacle is right then mSteer is left", engine));
+engine->addRuleBlock(mamdani);
+
+
+}
diff --git a/examples/mamdani/ObstacleAvoidance.fcl b/examples/mamdani/ObstacleAvoidance.fcl
new file mode 100644
index 0000000..1f2bac0
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.fcl
@@ -0,0 +1,34 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK ObstacleAvoidance
+
+VAR_INPUT
+ obstacle: REAL;
+END_VAR
+
+VAR_OUTPUT
+ mSteer: REAL;
+END_VAR
+
+FUZZIFY obstacle
+ RANGE := (0.000 .. 1.000);
+ TERM left := Ramp 1.000 0.000;
+ TERM right := Ramp 0.000 1.000;
+END_FUZZIFY
+
+DEFUZZIFY mSteer
+ RANGE := (0.000 .. 1.000);
+ TERM left := Ramp 1.000 0.000;
+ TERM right := Ramp 0.000 1.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK mamdani
+ ACT : PROD;
+ RULE 1 : if obstacle is left then mSteer is right
+ RULE 2 : if obstacle is right then mSteer is left
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/ObstacleAvoidance.fis b/examples/mamdani/ObstacleAvoidance.fis
new file mode 100644
index 0000000..f938ec0
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.fis
@@ -0,0 +1,32 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='ObstacleAvoidance'
+Type='mamdani'
+Version=6.0
+NumInputs=1
+NumOutputs=1
+NumRules=2
+AndMethod='min'
+OrMethod='max'
+ImpMethod='prod'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='obstacle'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'rampmf',[1.000 0.000]
+MF2='right':'rampmf',[0.000 1.000]
+
+[Output1]
+Name='mSteer'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'rampmf',[1.000 0.000]
+MF2='right':'rampmf',[0.000 1.000]
+
+[Rules]
+1.000 , 2.000 (1.000) : 1
+2.000 , 1.000 (1.000) : 1
diff --git a/examples/mamdani/ObstacleAvoidance.fld b/examples/mamdani/ObstacleAvoidance.fld
new file mode 100644
index 0000000..ec259dd
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.fld
@@ -0,0 +1,1025 @@
+obstacle mSteer
+0.000000000 0.666650000
+0.000977517 0.666650000
+0.001955034 0.666650000
+0.002932551 0.666650000
+0.003910068 0.666650000
+0.004887586 0.666650000
+0.005865103 0.666638485
+0.006842620 0.666625450
+0.007820137 0.666612389
+0.008797654 0.666599303
+0.009775171 0.666586193
+0.010752688 0.666573056
+0.011730205 0.666559894
+0.012707722 0.666546707
+0.013685239 0.666533494
+0.014662757 0.666520255
+0.015640274 0.666498518
+0.016617791 0.666472271
+0.017595308 0.666445974
+0.018572825 0.666419626
+0.019550342 0.666393229
+0.020527859 0.666366781
+0.021505376 0.666340282
+0.022482893 0.666313732
+0.023460411 0.666287131
+0.024437928 0.666260479
+0.025415445 0.666228313
+0.026392962 0.666188686
+0.027370479 0.666148986
+0.028347996 0.666109209
+0.029325513 0.666069358
+0.030303030 0.666029432
+0.031280547 0.665989429
+0.032258065 0.665949351
+0.033235582 0.665909196
+0.034213099 0.665868966
+0.035190616 0.665826169
+0.036168133 0.665773005
+0.037145650 0.665719742
+0.038123167 0.665666380
+0.039100684 0.665612917
+0.040078201 0.665559355
+0.041055718 0.665505693
+0.042033236 0.665451930
+0.043010753 0.665398066
+0.043988270 0.665344101
+0.044965787 0.665290034
+0.045943304 0.665223628
+0.046920821 0.665156655
+0.047898338 0.665089559
+0.048875855 0.665022339
+0.049853372 0.664954994
+0.050830890 0.664887525
+0.051808407 0.664819932
+0.052785924 0.664752213
+0.053763441 0.664684369
+0.054740958 0.664616398
+0.055718475 0.664539056
+0.056695992 0.664458237
+0.057673509 0.664377270
+0.058651026 0.664296156
+0.059628543 0.664214895
+0.060606061 0.664133485
+0.061583578 0.664051926
+0.062561095 0.663970218
+0.063538612 0.663888361
+0.064516129 0.663806354
+0.065493646 0.663717900
+0.066471163 0.663623109
+0.067448680 0.663528148
+0.068426197 0.663433016
+0.069403715 0.663337714
+0.070381232 0.663242240
+0.071358749 0.663146594
+0.072336266 0.663050776
+0.073313783 0.662954785
+0.074291300 0.662858620
+0.075268817 0.662758885
+0.076246334 0.662650011
+0.077223851 0.662540943
+0.078201369 0.662431683
+0.079178886 0.662322229
+0.080156403 0.662212581
+0.081133920 0.662102739
+0.082111437 0.661992701
+0.083088954 0.661882468
+0.084066471 0.661772039
+0.085043988 0.661660863
+0.086021505 0.661537806
+0.086999022 0.661414534
+0.087976540 0.661291048
+0.088954057 0.661167346
+0.089931574 0.661043428
+0.090909091 0.660919294
+0.091886608 0.660794942
+0.092864125 0.660670373
+0.093841642 0.660545585
+0.094819159 0.660420579
+0.095796676 0.660285492
+0.096774194 0.660147932
+0.097751711 0.660010136
+0.098729228 0.659872104
+0.099706745 0.659733835
+0.100684262 0.659595328
+0.101661779 0.659456582
+0.102639296 0.659317597
+0.103616813 0.659178373
+0.104594330 0.659038909
+0.105571848 0.658892208
+0.106549365 0.658740291
+0.107526882 0.658588119
+0.108504399 0.658435689
+0.109481916 0.658283002
+0.110459433 0.658130057
+0.111436950 0.657976852
+0.112414467 0.657823389
+0.113391984 0.657669665
+0.114369501 0.657515680
+0.115347019 0.657357242
+0.116324536 0.657190916
+0.117302053 0.657024315
+0.118279570 0.656857437
+0.119257087 0.656690282
+0.120234604 0.656522850
+0.121212121 0.656355139
+0.122189638 0.656187149
+0.123167155 0.656018879
+0.124144673 0.655850329
+0.125122190 0.655680041
+0.126099707 0.655499270
+0.127077224 0.655318205
+0.128054741 0.655136845
+0.129032258 0.654955190
+0.130009775 0.654773238
+0.130987292 0.654590990
+0.131964809 0.654408443
+0.132942326 0.654225598
+0.133919844 0.654042454
+0.134897361 0.653859010
+0.135874878 0.653664982
+0.136852395 0.653469436
+0.137829912 0.653273578
+0.138807429 0.653077407
+0.139784946 0.652880922
+0.140762463 0.652684123
+0.141739980 0.652487008
+0.142717498 0.652289577
+0.143695015 0.652091829
+0.144672532 0.651893763
+0.145650049 0.651687855
+0.146627566 0.651477831
+0.147605083 0.651267477
+0.148582600 0.651056794
+0.149560117 0.650845780
+0.150537634 0.650634436
+0.151515152 0.650422759
+0.152492669 0.650210750
+0.153470186 0.649998407
+0.154447703 0.649785731
+0.155425220 0.649567877
+0.156402737 0.649343393
+0.157380254 0.649118566
+0.158357771 0.648893393
+0.159335288 0.648667875
+0.160312805 0.648442011
+0.161290323 0.648215799
+0.162267840 0.647989239
+0.163245357 0.647762331
+0.164222874 0.647535073
+0.165200391 0.647305221
+0.166177908 0.647066320
+0.167155425 0.646827060
+0.168132942 0.646587441
+0.169110459 0.646347463
+0.170087977 0.646107124
+0.171065494 0.645866424
+0.172043011 0.645625361
+0.173020528 0.645383936
+0.173998045 0.645142147
+0.174975562 0.644899993
+0.175953079 0.644647002
+0.176930596 0.644393373
+0.177908113 0.644139372
+0.178885630 0.643884998
+0.179863148 0.643630251
+0.180840665 0.643375130
+0.181818182 0.643119633
+0.182795699 0.642863761
+0.183773216 0.642607513
+0.184750733 0.642350886
+0.185728250 0.642086038
+0.186705767 0.641818123
+0.187683284 0.641549824
+0.188660802 0.641281142
+0.189638319 0.641012074
+0.190615836 0.640742621
+0.191593353 0.640472782
+0.192570870 0.640202555
+0.193548387 0.639931940
+0.194525904 0.639660937
+0.195503421 0.639384233
+0.196480938 0.639102138
+0.197458456 0.638819650
+0.198435973 0.638536767
+0.199413490 0.638253490
+0.200391007 0.637969817
+0.201368524 0.637685747
+0.202346041 0.637401280
+0.203323558 0.637116415
+0.204301075 0.636831150
+0.205278592 0.636542613
+0.206256109 0.636246466
+0.207233627 0.635949918
+0.208211144 0.635652966
+0.209188661 0.635355612
+0.210166178 0.635057853
+0.211143695 0.634759688
+0.212121212 0.634461118
+0.213098729 0.634162142
+0.214076246 0.633862757
+0.215053763 0.633562423
+0.216031281 0.633252376
+0.217008798 0.632941920
+0.217986315 0.632631055
+0.218963832 0.632319779
+0.219941349 0.632008091
+0.220918866 0.631695992
+0.221896383 0.631383479
+0.222873900 0.631070553
+0.223851417 0.630757212
+0.224828935 0.630443455
+0.225806452 0.630121364
+0.226783969 0.629797178
+0.227761486 0.629472576
+0.228739003 0.629147559
+0.229716520 0.628822125
+0.230694037 0.628496272
+0.231671554 0.628170002
+0.232649071 0.627843312
+0.233626588 0.627516202
+0.234604106 0.627188671
+0.235581623 0.626855159
+0.236559140 0.626517443
+0.237536657 0.626179308
+0.238514174 0.625840753
+0.239491691 0.625501777
+0.240469208 0.625162379
+0.241446725 0.624822559
+0.242424242 0.624482316
+0.243401760 0.624141649
+0.244379277 0.623800557
+0.245356794 0.623455725
+0.246334311 0.623104704
+0.247311828 0.622753262
+0.248289345 0.622401397
+0.249266862 0.622049109
+0.250244379 0.621696398
+0.251221896 0.621343261
+0.252199413 0.620989700
+0.253176931 0.620635712
+0.254154448 0.620281297
+0.255131965 0.619925265
+0.256109482 0.619561189
+0.257086999 0.619196691
+0.258064516 0.618831769
+0.259042033 0.618466424
+0.260019550 0.618100655
+0.260997067 0.617734460
+0.261974585 0.617367839
+0.262952102 0.617000791
+0.263929619 0.616633316
+0.264907136 0.616265413
+0.265884653 0.615889366
+0.266862170 0.615512088
+0.267839687 0.615134387
+0.268817204 0.614756264
+0.269794721 0.614377718
+0.270772239 0.613998747
+0.271749756 0.613619351
+0.272727273 0.613239530
+0.273704790 0.612859282
+0.274682307 0.612478608
+0.275659824 0.612091947
+0.276637341 0.611702189
+0.277614858 0.611312012
+0.278592375 0.610921415
+0.279569892 0.610530398
+0.280547410 0.610138959
+0.281524927 0.609747097
+0.282502444 0.609354813
+0.283479961 0.608962106
+0.284457478 0.608568974
+0.285434995 0.608171886
+0.286412512 0.607769974
+0.287390029 0.607367648
+0.288367546 0.606964906
+0.289345064 0.606561748
+0.290322581 0.606158173
+0.291300098 0.605754180
+0.292277615 0.605349770
+0.293255132 0.604944940
+0.294232649 0.604539690
+0.295210166 0.604132380
+0.296187683 0.603718665
+0.297165200 0.603304542
+0.298142717 0.602890009
+0.299120235 0.602475066
+0.300097752 0.602059712
+0.301075269 0.601643947
+0.302052786 0.601227769
+0.303030303 0.600811179
+0.304007820 0.600394176
+0.304985337 0.599976759
+0.305962854 0.599551726
+0.306940371 0.599126182
+0.307917889 0.598700236
+0.308895406 0.598273888
+0.309872923 0.597847137
+0.310850440 0.597419982
+0.311827957 0.596992424
+0.312805474 0.596564460
+0.313782991 0.596136092
+0.314760508 0.595707318
+0.315738025 0.595272860
+0.316715543 0.594836296
+0.317693060 0.594399340
+0.318670577 0.593961991
+0.319648094 0.593524248
+0.320625611 0.593086112
+0.321603128 0.592647581
+0.322580645 0.592208655
+0.323558162 0.591769334
+0.324535679 0.591329617
+0.325513196 0.590886006
+0.326490714 0.590438847
+0.327468231 0.589991307
+0.328445748 0.589543385
+0.329423265 0.589095081
+0.330400782 0.588646394
+0.331378299 0.588197324
+0.332355816 0.587747870
+0.333333333 0.587298033
+0.334310850 0.586847811
+0.335288368 0.586395337
+0.336265885 0.585938031
+0.337243402 0.585480357
+0.338220919 0.585022313
+0.339198436 0.584563900
+0.340175953 0.584105117
+0.341153470 0.583645965
+0.342130987 0.583186441
+0.343108504 0.582726546
+0.344086022 0.582266280
+0.345063539 0.581805253
+0.346041056 0.581338270
+0.347018573 0.580870934
+0.347996090 0.580403243
+0.348973607 0.579935197
+0.349951124 0.579466795
+0.350928641 0.578998038
+0.351906158 0.578528925
+0.352883675 0.578059455
+0.353861193 0.577589628
+0.354838710 0.577119444
+0.355816227 0.576644207
+0.356793744 0.576167703
+0.357771261 0.575690860
+0.358748778 0.575213679
+0.359726295 0.574736158
+0.360703812 0.574258297
+0.361681329 0.573780096
+0.362658847 0.573301554
+0.363636364 0.572822672
+0.364613881 0.572343449
+0.365591398 0.571860698
+0.366568915 0.571375542
+0.367546432 0.570890065
+0.368523949 0.570404267
+0.369501466 0.569918146
+0.370478983 0.569431703
+0.371456500 0.568944938
+0.372434018 0.568457849
+0.373411535 0.567970438
+0.374389052 0.567482703
+0.375366569 0.566992805
+0.376344086 0.566499534
+0.377321603 0.566005960
+0.378299120 0.565512083
+0.379276637 0.565017903
+0.380254154 0.564523420
+0.381231672 0.564028633
+0.382209189 0.563533542
+0.383186706 0.563038147
+0.384164223 0.562542448
+0.385141740 0.562045786
+0.386119257 0.561544954
+0.387096774 0.561043840
+0.388074291 0.560542444
+0.389051808 0.560040764
+0.390029326 0.559538801
+0.391006843 0.559036555
+0.391984360 0.558534026
+0.392961877 0.558031212
+0.393939394 0.557528114
+0.394916911 0.557024732
+0.395894428 0.556517268
+0.396871945 0.556009189
+0.397849462 0.555500848
+0.398826979 0.554992247
+0.399804497 0.554483383
+0.400782014 0.553974258
+0.401759531 0.553464870
+0.402737048 0.552955221
+0.403714565 0.552445308
+0.404692082 0.551935134
+0.405669599 0.551422112
+0.406647116 0.550907660
+0.407624633 0.550392969
+0.408602151 0.549878039
+0.409579668 0.549362870
+0.410557185 0.548847462
+0.411534702 0.548331815
+0.412512219 0.547815928
+0.413489736 0.547299802
+0.414467253 0.546783436
+0.415444770 0.546265287
+0.416422287 0.545745069
+0.417399804 0.545224637
+0.418377322 0.544703989
+0.419354839 0.544183126
+0.420332356 0.543662048
+0.421309873 0.543140754
+0.422287390 0.542619244
+0.423264907 0.542097518
+0.424242424 0.541575577
+0.425219941 0.541052744
+0.426197458 0.540527383
+0.427174976 0.540001832
+0.428152493 0.539476090
+0.429130010 0.538950158
+0.430107527 0.538424035
+0.431085044 0.537897722
+0.432062561 0.537371217
+0.433040078 0.536844521
+0.434017595 0.536317635
+0.434995112 0.535790557
+0.435972630 0.535260701
+0.436950147 0.534730668
+0.437927664 0.534200469
+0.438905181 0.533670106
+0.439882698 0.533139577
+0.440860215 0.532608883
+0.441837732 0.532078024
+0.442815249 0.531546999
+0.443792766 0.531015810
+0.444770283 0.530484454
+0.445747801 0.529951246
+0.446725318 0.529417377
+0.447702835 0.528883370
+0.448680352 0.528349224
+0.449657869 0.527814939
+0.450635386 0.527280516
+0.451612903 0.526745953
+0.452590420 0.526211252
+0.453567937 0.525676412
+0.454545455 0.525141432
+0.455522972 0.524605346
+0.456500489 0.524068300
+0.457478006 0.523531142
+0.458455523 0.522993872
+0.459433040 0.522456490
+0.460410557 0.521918997
+0.461388074 0.521381392
+0.462365591 0.520843675
+0.463343109 0.520305846
+0.464320626 0.519767905
+0.465298143 0.519229421
+0.466275660 0.518689863
+0.467253177 0.518150220
+0.468230694 0.517610493
+0.469208211 0.517070682
+0.470185728 0.516530787
+0.471163245 0.515990807
+0.472140762 0.515450743
+0.473118280 0.514910594
+0.474095797 0.514370361
+0.475073314 0.513829968
+0.476050831 0.513288569
+0.477028348 0.512747115
+0.478005865 0.512205604
+0.478983382 0.511664036
+0.479960899 0.511122412
+0.480938416 0.510580732
+0.481915934 0.510038995
+0.482893451 0.509497202
+0.483870968 0.508955352
+0.484848485 0.508413446
+0.485826002 0.507870980
+0.486803519 0.507328390
+0.487781036 0.506785773
+0.488758553 0.506243127
+0.489736070 0.505700453
+0.490713587 0.505157751
+0.491691105 0.504615020
+0.492668622 0.504072261
+0.493646139 0.503529474
+0.494623656 0.502986658
+0.495601173 0.502443695
+0.496578690 0.501900652
+0.497556207 0.501357608
+0.498533724 0.500814565
+0.499511241 0.500271522
+0.500488759 0.499728478
+0.501466276 0.499185435
+0.502443793 0.498642392
+0.503421310 0.498099348
+0.504398827 0.497556305
+0.505376344 0.497013342
+0.506353861 0.496470526
+0.507331378 0.495927739
+0.508308895 0.495384980
+0.509286413 0.494842249
+0.510263930 0.494299547
+0.511241447 0.493756873
+0.512218964 0.493214227
+0.513196481 0.492671610
+0.514173998 0.492129020
+0.515151515 0.491586554
+0.516129032 0.491044648
+0.517106549 0.490502798
+0.518084066 0.489961005
+0.519061584 0.489419268
+0.520039101 0.488877588
+0.521016618 0.488335964
+0.521994135 0.487794396
+0.522971652 0.487252885
+0.523949169 0.486711431
+0.524926686 0.486170032
+0.525904203 0.485629639
+0.526881720 0.485089406
+0.527859238 0.484549257
+0.528836755 0.484009193
+0.529814272 0.483469213
+0.530791789 0.482929318
+0.531769306 0.482389507
+0.532746823 0.481849780
+0.533724340 0.481310137
+0.534701857 0.480770579
+0.535679374 0.480232095
+0.536656891 0.479694154
+0.537634409 0.479156325
+0.538611926 0.478618608
+0.539589443 0.478081003
+0.540566960 0.477543510
+0.541544477 0.477006128
+0.542521994 0.476468858
+0.543499511 0.475931700
+0.544477028 0.475394654
+0.545454545 0.474858568
+0.546432063 0.474323588
+0.547409580 0.473788748
+0.548387097 0.473254047
+0.549364614 0.472719484
+0.550342131 0.472185061
+0.551319648 0.471650776
+0.552297165 0.471116630
+0.553274682 0.470582623
+0.554252199 0.470048754
+0.555229717 0.469515546
+0.556207234 0.468984190
+0.557184751 0.468453001
+0.558162268 0.467921976
+0.559139785 0.467391117
+0.560117302 0.466860423
+0.561094819 0.466329894
+0.562072336 0.465799531
+0.563049853 0.465269332
+0.564027370 0.464739299
+0.565004888 0.464209443
+0.565982405 0.463682365
+0.566959922 0.463155479
+0.567937439 0.462628783
+0.568914956 0.462102278
+0.569892473 0.461575965
+0.570869990 0.461049842
+0.571847507 0.460523910
+0.572825024 0.459998168
+0.573802542 0.459472617
+0.574780059 0.458947256
+0.575757576 0.458424423
+0.576735093 0.457902482
+0.577712610 0.457380756
+0.578690127 0.456859246
+0.579667644 0.456337952
+0.580645161 0.455816874
+0.581622678 0.455296011
+0.582600196 0.454775363
+0.583577713 0.454254931
+0.584555230 0.453734713
+0.585532747 0.453216564
+0.586510264 0.452700198
+0.587487781 0.452184072
+0.588465298 0.451668185
+0.589442815 0.451152538
+0.590420332 0.450637130
+0.591397849 0.450121961
+0.592375367 0.449607031
+0.593352884 0.449092340
+0.594330401 0.448577888
+0.595307918 0.448064866
+0.596285435 0.447554692
+0.597262952 0.447044779
+0.598240469 0.446535130
+0.599217986 0.446025742
+0.600195503 0.445516617
+0.601173021 0.445007753
+0.602150538 0.444499152
+0.603128055 0.443990811
+0.604105572 0.443482732
+0.605083089 0.442975268
+0.606060606 0.442471886
+0.607038123 0.441968788
+0.608015640 0.441465974
+0.608993157 0.440963445
+0.609970674 0.440461199
+0.610948192 0.439959236
+0.611925709 0.439457556
+0.612903226 0.438956160
+0.613880743 0.438455046
+0.614858260 0.437954214
+0.615835777 0.437457552
+0.616813294 0.436961853
+0.617790811 0.436466458
+0.618768328 0.435971367
+0.619745846 0.435476580
+0.620723363 0.434982097
+0.621700880 0.434487917
+0.622678397 0.433994040
+0.623655914 0.433500466
+0.624633431 0.433007195
+0.625610948 0.432517297
+0.626588465 0.432029562
+0.627565982 0.431542151
+0.628543500 0.431055062
+0.629521017 0.430568297
+0.630498534 0.430081854
+0.631476051 0.429595733
+0.632453568 0.429109935
+0.633431085 0.428624458
+0.634408602 0.428139302
+0.635386119 0.427656551
+0.636363636 0.427177328
+0.637341153 0.426698446
+0.638318671 0.426219904
+0.639296188 0.425741703
+0.640273705 0.425263842
+0.641251222 0.424786321
+0.642228739 0.424309140
+0.643206256 0.423832297
+0.644183773 0.423355793
+0.645161290 0.422880556
+0.646138807 0.422410372
+0.647116325 0.421940545
+0.648093842 0.421471075
+0.649071359 0.421001962
+0.650048876 0.420533205
+0.651026393 0.420064803
+0.652003910 0.419596757
+0.652981427 0.419129066
+0.653958944 0.418661730
+0.654936461 0.418194747
+0.655913978 0.417733720
+0.656891496 0.417273454
+0.657869013 0.416813559
+0.658846530 0.416354035
+0.659824047 0.415894883
+0.660801564 0.415436100
+0.661779081 0.414977687
+0.662756598 0.414519643
+0.663734115 0.414061969
+0.664711632 0.413604663
+0.665689150 0.413152189
+0.666666667 0.412701967
+0.667644184 0.412252130
+0.668621701 0.411802676
+0.669599218 0.411353606
+0.670576735 0.410904919
+0.671554252 0.410456615
+0.672531769 0.410008693
+0.673509286 0.409561153
+0.674486804 0.409113994
+0.675464321 0.408670383
+0.676441838 0.408230666
+0.677419355 0.407791345
+0.678396872 0.407352419
+0.679374389 0.406913888
+0.680351906 0.406475752
+0.681329423 0.406038009
+0.682306940 0.405600660
+0.683284457 0.405163704
+0.684261975 0.404727140
+0.685239492 0.404292682
+0.686217009 0.403863908
+0.687194526 0.403435540
+0.688172043 0.403007576
+0.689149560 0.402580018
+0.690127077 0.402152863
+0.691104594 0.401726112
+0.692082111 0.401299764
+0.693059629 0.400873818
+0.694037146 0.400448274
+0.695014663 0.400023241
+0.695992180 0.399605824
+0.696969697 0.399188821
+0.697947214 0.398772231
+0.698924731 0.398356053
+0.699902248 0.397940288
+0.700879765 0.397524934
+0.701857283 0.397109991
+0.702834800 0.396695458
+0.703812317 0.396281335
+0.704789834 0.395867620
+0.705767351 0.395460310
+0.706744868 0.395055060
+0.707722385 0.394650230
+0.708699902 0.394245820
+0.709677419 0.393841827
+0.710654936 0.393438252
+0.711632454 0.393035094
+0.712609971 0.392632352
+0.713587488 0.392230026
+0.714565005 0.391828114
+0.715542522 0.391431026
+0.716520039 0.391037894
+0.717497556 0.390645187
+0.718475073 0.390252903
+0.719452590 0.389861041
+0.720430108 0.389469602
+0.721407625 0.389078585
+0.722385142 0.388687988
+0.723362659 0.388297811
+0.724340176 0.387908053
+0.725317693 0.387521392
+0.726295210 0.387140718
+0.727272727 0.386760470
+0.728250244 0.386380649
+0.729227761 0.386001253
+0.730205279 0.385622282
+0.731182796 0.385243736
+0.732160313 0.384865613
+0.733137830 0.384487912
+0.734115347 0.384110634
+0.735092864 0.383734587
+0.736070381 0.383366684
+0.737047898 0.382999209
+0.738025415 0.382632161
+0.739002933 0.382265540
+0.739980450 0.381899345
+0.740957967 0.381533576
+0.741935484 0.381168231
+0.742913001 0.380803309
+0.743890518 0.380438811
+0.744868035 0.380074735
+0.745845552 0.379718703
+0.746823069 0.379364288
+0.747800587 0.379010300
+0.748778104 0.378656739
+0.749755621 0.378303602
+0.750733138 0.377950891
+0.751710655 0.377598603
+0.752688172 0.377246738
+0.753665689 0.376895296
+0.754643206 0.376544275
+0.755620723 0.376199443
+0.756598240 0.375858351
+0.757575758 0.375517684
+0.758553275 0.375177441
+0.759530792 0.374837621
+0.760508309 0.374498223
+0.761485826 0.374159247
+0.762463343 0.373820692
+0.763440860 0.373482557
+0.764418377 0.373144841
+0.765395894 0.372811329
+0.766373412 0.372483798
+0.767350929 0.372156688
+0.768328446 0.371829998
+0.769305963 0.371503728
+0.770283480 0.371177875
+0.771260997 0.370852441
+0.772238514 0.370527424
+0.773216031 0.370202822
+0.774193548 0.369878636
+0.775171065 0.369556545
+0.776148583 0.369242788
+0.777126100 0.368929447
+0.778103617 0.368616521
+0.779081134 0.368304008
+0.780058651 0.367991909
+0.781036168 0.367680221
+0.782013685 0.367368945
+0.782991202 0.367058080
+0.783968719 0.366747624
+0.784946237 0.366437577
+0.785923754 0.366137243
+0.786901271 0.365837858
+0.787878788 0.365538882
+0.788856305 0.365240312
+0.789833822 0.364942147
+0.790811339 0.364644388
+0.791788856 0.364347034
+0.792766373 0.364050082
+0.793743891 0.363753534
+0.794721408 0.363457387
+0.795698925 0.363168850
+0.796676442 0.362883585
+0.797653959 0.362598720
+0.798631476 0.362314253
+0.799608993 0.362030183
+0.800586510 0.361746510
+0.801564027 0.361463233
+0.802541544 0.361180350
+0.803519062 0.360897862
+0.804496579 0.360615767
+0.805474096 0.360339063
+0.806451613 0.360068060
+0.807429130 0.359797445
+0.808406647 0.359527218
+0.809384164 0.359257379
+0.810361681 0.358987926
+0.811339198 0.358718858
+0.812316716 0.358450176
+0.813294233 0.358181877
+0.814271750 0.357913962
+0.815249267 0.357649114
+0.816226784 0.357392487
+0.817204301 0.357136239
+0.818181818 0.356880367
+0.819159335 0.356624870
+0.820136852 0.356369749
+0.821114370 0.356115002
+0.822091887 0.355860628
+0.823069404 0.355606627
+0.824046921 0.355352998
+0.825024438 0.355100007
+0.826001955 0.354857853
+0.826979472 0.354616064
+0.827956989 0.354374639
+0.828934506 0.354133576
+0.829912023 0.353892876
+0.830889541 0.353652537
+0.831867058 0.353412559
+0.832844575 0.353172940
+0.833822092 0.352933680
+0.834799609 0.352694779
+0.835777126 0.352464927
+0.836754643 0.352237669
+0.837732160 0.352010761
+0.838709677 0.351784201
+0.839687195 0.351557989
+0.840664712 0.351332125
+0.841642229 0.351106607
+0.842619746 0.350881434
+0.843597263 0.350656607
+0.844574780 0.350432123
+0.845552297 0.350214269
+0.846529814 0.350001593
+0.847507331 0.349789250
+0.848484848 0.349577241
+0.849462366 0.349365564
+0.850439883 0.349154220
+0.851417400 0.348943206
+0.852394917 0.348732523
+0.853372434 0.348522169
+0.854349951 0.348312145
+0.855327468 0.348106237
+0.856304985 0.347908171
+0.857282502 0.347710423
+0.858260020 0.347512992
+0.859237537 0.347315877
+0.860215054 0.347119078
+0.861192571 0.346922593
+0.862170088 0.346726422
+0.863147605 0.346530564
+0.864125122 0.346335018
+0.865102639 0.346140990
+0.866080156 0.345957546
+0.867057674 0.345774402
+0.868035191 0.345591557
+0.869012708 0.345409010
+0.869990225 0.345226762
+0.870967742 0.345044810
+0.871945259 0.344863155
+0.872922776 0.344681795
+0.873900293 0.344500730
+0.874877810 0.344319959
+0.875855327 0.344149671
+0.876832845 0.343981121
+0.877810362 0.343812851
+0.878787879 0.343644861
+0.879765396 0.343477150
+0.880742913 0.343309718
+0.881720430 0.343142563
+0.882697947 0.342975685
+0.883675464 0.342809084
+0.884652981 0.342642758
+0.885630499 0.342484320
+0.886608016 0.342330335
+0.887585533 0.342176611
+0.888563050 0.342023148
+0.889540567 0.341869943
+0.890518084 0.341716998
+0.891495601 0.341564311
+0.892473118 0.341411881
+0.893450635 0.341259709
+0.894428152 0.341107792
+0.895405670 0.340961091
+0.896383187 0.340821627
+0.897360704 0.340682403
+0.898338221 0.340543418
+0.899315738 0.340404672
+0.900293255 0.340266165
+0.901270772 0.340127896
+0.902248289 0.339989864
+0.903225806 0.339852068
+0.904203324 0.339714508
+0.905180841 0.339579421
+0.906158358 0.339454415
+0.907135875 0.339329627
+0.908113392 0.339205058
+0.909090909 0.339080706
+0.910068426 0.338956572
+0.911045943 0.338832654
+0.912023460 0.338708952
+0.913000978 0.338585466
+0.913978495 0.338462194
+0.914956012 0.338339137
+0.915933529 0.338227961
+0.916911046 0.338117532
+0.917888563 0.338007299
+0.918866080 0.337897261
+0.919843597 0.337787419
+0.920821114 0.337677771
+0.921798631 0.337568317
+0.922776149 0.337459057
+0.923753666 0.337349989
+0.924731183 0.337241115
+0.925708700 0.337141380
+0.926686217 0.337045215
+0.927663734 0.336949224
+0.928641251 0.336853406
+0.929618768 0.336757760
+0.930596285 0.336662286
+0.931573803 0.336566984
+0.932551320 0.336471852
+0.933528837 0.336376891
+0.934506354 0.336282100
+0.935483871 0.336193646
+0.936461388 0.336111639
+0.937438905 0.336029782
+0.938416422 0.335948074
+0.939393939 0.335866515
+0.940371457 0.335785105
+0.941348974 0.335703844
+0.942326491 0.335622730
+0.943304008 0.335541763
+0.944281525 0.335460944
+0.945259042 0.335383602
+0.946236559 0.335315631
+0.947214076 0.335247787
+0.948191593 0.335180068
+0.949169110 0.335112475
+0.950146628 0.335045006
+0.951124145 0.334977661
+0.952101662 0.334910441
+0.953079179 0.334843345
+0.954056696 0.334776372
+0.955034213 0.334709966
+0.956011730 0.334655899
+0.956989247 0.334601934
+0.957966764 0.334548070
+0.958944282 0.334494307
+0.959921799 0.334440645
+0.960899316 0.334387083
+0.961876833 0.334333620
+0.962854350 0.334280258
+0.963831867 0.334226995
+0.964809384 0.334173831
+0.965786901 0.334131034
+0.966764418 0.334090804
+0.967741935 0.334050649
+0.968719453 0.334010571
+0.969696970 0.333970568
+0.970674487 0.333930642
+0.971652004 0.333890791
+0.972629521 0.333851014
+0.973607038 0.333811314
+0.974584555 0.333771687
+0.975562072 0.333739521
+0.976539589 0.333712869
+0.977517107 0.333686268
+0.978494624 0.333659718
+0.979472141 0.333633219
+0.980449658 0.333606771
+0.981427175 0.333580374
+0.982404692 0.333554026
+0.983382209 0.333527729
+0.984359726 0.333501482
+0.985337243 0.333479745
+0.986314761 0.333466506
+0.987292278 0.333453293
+0.988269795 0.333440106
+0.989247312 0.333426944
+0.990224829 0.333413807
+0.991202346 0.333400697
+0.992179863 0.333387611
+0.993157380 0.333374550
+0.994134897 0.333361515
+0.995112414 0.333350000
+0.996089932 0.333350000
+0.997067449 0.333350000
+0.998044966 0.333350000
+0.999022483 0.333350000
+1.000000000 0.333350000
diff --git a/examples/mamdani/ObstacleAvoidance.fll b/examples/mamdani/ObstacleAvoidance.fll
new file mode 100644
index 0000000..a47f1b4
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.fll
@@ -0,0 +1,25 @@
+Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: mSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 100
+ default: nan
+ lock-previous: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+RuleBlock: mamdani
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: AlgebraicProduct
+ activation: General
+ rule: if obstacle is left then mSteer is right
+ rule: if obstacle is right then mSteer is left \ No newline at end of file
diff --git a/examples/mamdani/ObstacleAvoidance.java b/examples/mamdani/ObstacleAvoidance.java
new file mode 100644
index 0000000..8efef3b
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.java
@@ -0,0 +1,60 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class ObstacleAvoidance{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("ObstacleAvoidance");
+engine.setDescription("");
+
+InputVariable obstacle = new InputVariable();
+obstacle.setName("obstacle");
+obstacle.setDescription("");
+obstacle.setEnabled(true);
+obstacle.setRange(0.000, 1.000);
+obstacle.setLockValueInRange(false);
+obstacle.addTerm(new Ramp("left", 1.000, 0.000));
+obstacle.addTerm(new Ramp("right", 0.000, 1.000));
+engine.addInputVariable(obstacle);
+
+OutputVariable mSteer = new OutputVariable();
+mSteer.setName("mSteer");
+mSteer.setDescription("");
+mSteer.setEnabled(true);
+mSteer.setRange(0.000, 1.000);
+mSteer.setLockValueInRange(false);
+mSteer.setAggregation(new Maximum());
+mSteer.setDefuzzifier(new Centroid(100));
+mSteer.setDefaultValue(Double.NaN);
+mSteer.setLockPreviousValue(false);
+mSteer.addTerm(new Ramp("left", 1.000, 0.000));
+mSteer.addTerm(new Ramp("right", 0.000, 1.000));
+engine.addOutputVariable(mSteer);
+
+RuleBlock mamdani = new RuleBlock();
+mamdani.setName("mamdani");
+mamdani.setDescription("");
+mamdani.setEnabled(true);
+mamdani.setConjunction(null);
+mamdani.setDisjunction(null);
+mamdani.setImplication(new AlgebraicProduct());
+mamdani.setActivation(new General());
+mamdani.addRule(Rule.parse("if obstacle is left then mSteer is right", engine));
+mamdani.addRule(Rule.parse("if obstacle is right then mSteer is left", engine));
+engine.addRuleBlock(mamdani);
+
+
+}
+}
diff --git a/examples/mamdani/ObstacleAvoidance.pdf b/examples/mamdani/ObstacleAvoidance.pdf
new file mode 100644
index 0000000..63e1fe9
--- /dev/null
+++ b/examples/mamdani/ObstacleAvoidance.pdf
Binary files differ
diff --git a/examples/mamdani/SimpleDimmer.R b/examples/mamdani/SimpleDimmer.R
new file mode 100644
index 0000000..77a60f3
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.R
@@ -0,0 +1,60 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "SimpleDimmer"
+engine.fll = "Engine: SimpleDimmer
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW"
+
+engine.fldFile = "SimpleDimmer.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("Ambient vs Power")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Power vs Ambient")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/SimpleDimmer.cpp b/examples/mamdani/SimpleDimmer.cpp
new file mode 100644
index 0000000..7cd5e73
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.cpp
@@ -0,0 +1,52 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("SimpleDimmer");
+engine->setDescription("");
+
+InputVariable* Ambient = new InputVariable;
+Ambient->setName("Ambient");
+Ambient->setDescription("");
+Ambient->setEnabled(true);
+Ambient->setRange(0.000, 1.000);
+Ambient->setLockValueInRange(false);
+Ambient->addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient->addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine->addInputVariable(Ambient);
+
+OutputVariable* Power = new OutputVariable;
+Power->setName("Power");
+Power->setDescription("");
+Power->setEnabled(true);
+Power->setRange(0.000, 1.000);
+Power->setLockValueInRange(false);
+Power->setAggregation(new Maximum);
+Power->setDefuzzifier(new Centroid(200));
+Power->setDefaultValue(fl::nan);
+Power->setLockPreviousValue(false);
+Power->addTerm(new Triangle("LOW", 0.000, 0.250, 0.500));
+Power->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Power->addTerm(new Triangle("HIGH", 0.500, 0.750, 1.000));
+engine->addOutputVariable(Power);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(new Minimum);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is BRIGHT then Power is LOW", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/SimpleDimmer.fcl b/examples/mamdani/SimpleDimmer.fcl
new file mode 100644
index 0000000..104990a
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.fcl
@@ -0,0 +1,37 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK SimpleDimmer
+
+VAR_INPUT
+ Ambient: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Power: REAL;
+END_VAR
+
+FUZZIFY Ambient
+ RANGE := (0.000 .. 1.000);
+ TERM DARK := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM BRIGHT := Triangle 0.500 0.750 1.000;
+END_FUZZIFY
+
+DEFUZZIFY Power
+ RANGE := (0.000 .. 1.000);
+ TERM LOW := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM HIGH := Triangle 0.500 0.750 1.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ ACT : MIN;
+ RULE 1 : if Ambient is DARK then Power is HIGH
+ RULE 2 : if Ambient is MEDIUM then Power is MEDIUM
+ RULE 3 : if Ambient is BRIGHT then Power is LOW
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/SimpleDimmer.fis b/examples/mamdani/SimpleDimmer.fis
new file mode 100644
index 0000000..3435060
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.fis
@@ -0,0 +1,35 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='SimpleDimmer'
+Type='mamdani'
+Version=6.0
+NumInputs=1
+NumOutputs=1
+NumRules=3
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Ambient'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='DARK':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='BRIGHT':'trimf',[0.500 0.750 1.000]
+
+[Output1]
+Name='Power'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='LOW':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='HIGH':'trimf',[0.500 0.750 1.000]
+
+[Rules]
+1.000 , 3.000 (1.000) : 1
+2.000 , 2.000 (1.000) : 1
+3.000 , 1.000 (1.000) : 1
diff --git a/examples/mamdani/SimpleDimmer.fld b/examples/mamdani/SimpleDimmer.fld
new file mode 100644
index 0000000..bd4dc51
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.fld
@@ -0,0 +1,1025 @@
+Ambient Power
+0.000000000 nan
+0.000977517 0.750000000
+0.001955034 0.750000000
+0.002932551 0.750000000
+0.003910068 0.750000000
+0.004887586 0.750000000
+0.005865103 0.750000000
+0.006842620 0.750000000
+0.007820137 0.750000000
+0.008797654 0.750000000
+0.009775171 0.750000000
+0.010752688 0.750000000
+0.011730205 0.750000000
+0.012707722 0.750000000
+0.013685239 0.750000000
+0.014662757 0.750000000
+0.015640274 0.750000000
+0.016617791 0.750000000
+0.017595308 0.750000000
+0.018572825 0.750000000
+0.019550342 0.750000000
+0.020527859 0.750000000
+0.021505376 0.750000000
+0.022482893 0.750000000
+0.023460411 0.750000000
+0.024437928 0.750000000
+0.025415445 0.750000000
+0.026392962 0.750000000
+0.027370479 0.750000000
+0.028347996 0.750000000
+0.029325513 0.750000000
+0.030303030 0.750000000
+0.031280547 0.750000000
+0.032258065 0.750000000
+0.033235582 0.750000000
+0.034213099 0.750000000
+0.035190616 0.750000000
+0.036168133 0.750000000
+0.037145650 0.750000000
+0.038123167 0.750000000
+0.039100684 0.750000000
+0.040078201 0.750000000
+0.041055718 0.750000000
+0.042033236 0.750000000
+0.043010753 0.750000000
+0.043988270 0.750000000
+0.044965787 0.750000000
+0.045943304 0.750000000
+0.046920821 0.750000000
+0.047898338 0.750000000
+0.048875855 0.750000000
+0.049853372 0.750000000
+0.050830890 0.750000000
+0.051808407 0.750000000
+0.052785924 0.750000000
+0.053763441 0.750000000
+0.054740958 0.750000000
+0.055718475 0.750000000
+0.056695992 0.750000000
+0.057673509 0.750000000
+0.058651026 0.750000000
+0.059628543 0.750000000
+0.060606061 0.750000000
+0.061583578 0.750000000
+0.062561095 0.750000000
+0.063538612 0.750000000
+0.064516129 0.750000000
+0.065493646 0.750000000
+0.066471163 0.750000000
+0.067448680 0.750000000
+0.068426197 0.750000000
+0.069403715 0.750000000
+0.070381232 0.750000000
+0.071358749 0.750000000
+0.072336266 0.750000000
+0.073313783 0.750000000
+0.074291300 0.750000000
+0.075268817 0.750000000
+0.076246334 0.750000000
+0.077223851 0.750000000
+0.078201369 0.750000000
+0.079178886 0.750000000
+0.080156403 0.750000000
+0.081133920 0.750000000
+0.082111437 0.750000000
+0.083088954 0.750000000
+0.084066471 0.750000000
+0.085043988 0.750000000
+0.086021505 0.750000000
+0.086999022 0.750000000
+0.087976540 0.750000000
+0.088954057 0.750000000
+0.089931574 0.750000000
+0.090909091 0.750000000
+0.091886608 0.750000000
+0.092864125 0.750000000
+0.093841642 0.750000000
+0.094819159 0.750000000
+0.095796676 0.750000000
+0.096774194 0.750000000
+0.097751711 0.750000000
+0.098729228 0.750000000
+0.099706745 0.750000000
+0.100684262 0.750000000
+0.101661779 0.750000000
+0.102639296 0.750000000
+0.103616813 0.750000000
+0.104594330 0.750000000
+0.105571848 0.750000000
+0.106549365 0.750000000
+0.107526882 0.750000000
+0.108504399 0.750000000
+0.109481916 0.750000000
+0.110459433 0.750000000
+0.111436950 0.750000000
+0.112414467 0.750000000
+0.113391984 0.750000000
+0.114369501 0.750000000
+0.115347019 0.750000000
+0.116324536 0.750000000
+0.117302053 0.750000000
+0.118279570 0.750000000
+0.119257087 0.750000000
+0.120234604 0.750000000
+0.121212121 0.750000000
+0.122189638 0.750000000
+0.123167155 0.750000000
+0.124144673 0.750000000
+0.125122190 0.750000000
+0.126099707 0.750000000
+0.127077224 0.750000000
+0.128054741 0.750000000
+0.129032258 0.750000000
+0.130009775 0.750000000
+0.130987292 0.750000000
+0.131964809 0.750000000
+0.132942326 0.750000000
+0.133919844 0.750000000
+0.134897361 0.750000000
+0.135874878 0.750000000
+0.136852395 0.750000000
+0.137829912 0.750000000
+0.138807429 0.750000000
+0.139784946 0.750000000
+0.140762463 0.750000000
+0.141739980 0.750000000
+0.142717498 0.750000000
+0.143695015 0.750000000
+0.144672532 0.750000000
+0.145650049 0.750000000
+0.146627566 0.750000000
+0.147605083 0.750000000
+0.148582600 0.750000000
+0.149560117 0.750000000
+0.150537634 0.750000000
+0.151515152 0.750000000
+0.152492669 0.750000000
+0.153470186 0.750000000
+0.154447703 0.750000000
+0.155425220 0.750000000
+0.156402737 0.750000000
+0.157380254 0.750000000
+0.158357771 0.750000000
+0.159335288 0.750000000
+0.160312805 0.750000000
+0.161290323 0.750000000
+0.162267840 0.750000000
+0.163245357 0.750000000
+0.164222874 0.750000000
+0.165200391 0.750000000
+0.166177908 0.750000000
+0.167155425 0.750000000
+0.168132942 0.750000000
+0.169110459 0.750000000
+0.170087977 0.750000000
+0.171065494 0.750000000
+0.172043011 0.750000000
+0.173020528 0.750000000
+0.173998045 0.750000000
+0.174975562 0.750000000
+0.175953079 0.750000000
+0.176930596 0.750000000
+0.177908113 0.750000000
+0.178885630 0.750000000
+0.179863148 0.750000000
+0.180840665 0.750000000
+0.181818182 0.750000000
+0.182795699 0.750000000
+0.183773216 0.750000000
+0.184750733 0.750000000
+0.185728250 0.750000000
+0.186705767 0.750000000
+0.187683284 0.750000000
+0.188660802 0.750000000
+0.189638319 0.750000000
+0.190615836 0.750000000
+0.191593353 0.750000000
+0.192570870 0.750000000
+0.193548387 0.750000000
+0.194525904 0.750000000
+0.195503421 0.750000000
+0.196480938 0.750000000
+0.197458456 0.750000000
+0.198435973 0.750000000
+0.199413490 0.750000000
+0.200391007 0.750000000
+0.201368524 0.750000000
+0.202346041 0.750000000
+0.203323558 0.750000000
+0.204301075 0.750000000
+0.205278592 0.750000000
+0.206256109 0.750000000
+0.207233627 0.750000000
+0.208211144 0.750000000
+0.209188661 0.750000000
+0.210166178 0.750000000
+0.211143695 0.750000000
+0.212121212 0.750000000
+0.213098729 0.750000000
+0.214076246 0.750000000
+0.215053763 0.750000000
+0.216031281 0.750000000
+0.217008798 0.750000000
+0.217986315 0.750000000
+0.218963832 0.750000000
+0.219941349 0.750000000
+0.220918866 0.750000000
+0.221896383 0.750000000
+0.222873900 0.750000000
+0.223851417 0.750000000
+0.224828935 0.750000000
+0.225806452 0.750000000
+0.226783969 0.750000000
+0.227761486 0.750000000
+0.228739003 0.750000000
+0.229716520 0.750000000
+0.230694037 0.750000000
+0.231671554 0.750000000
+0.232649071 0.750000000
+0.233626588 0.750000000
+0.234604106 0.750000000
+0.235581623 0.750000000
+0.236559140 0.750000000
+0.237536657 0.750000000
+0.238514174 0.750000000
+0.239491691 0.750000000
+0.240469208 0.750000000
+0.241446725 0.750000000
+0.242424242 0.750000000
+0.243401760 0.750000000
+0.244379277 0.750000000
+0.245356794 0.750000000
+0.246334311 0.750000000
+0.247311828 0.750000000
+0.248289345 0.750000000
+0.249266862 0.750000000
+0.250244379 0.749633789
+0.251221896 0.748176070
+0.252199413 0.746729651
+0.253176931 0.745307268
+0.254154448 0.743901152
+0.255131965 0.742505384
+0.256109482 0.741119851
+0.257086999 0.739744439
+0.258064516 0.738388970
+0.259042033 0.737050250
+0.260019550 0.735720805
+0.260997067 0.734400539
+0.261974585 0.733089356
+0.262952102 0.731794526
+0.263929619 0.730516794
+0.264907136 0.729247388
+0.265884653 0.727986227
+0.266862170 0.726733231
+0.267839687 0.725493442
+0.268817204 0.724270974
+0.269794721 0.723055990
+0.270772239 0.721848423
+0.271749756 0.720648204
+0.272727273 0.719458438
+0.273704790 0.718286101
+0.274682307 0.717120499
+0.275659824 0.715961575
+0.276637341 0.714809270
+0.277614858 0.713665012
+0.278592375 0.712538184
+0.279569892 0.711417421
+0.280547410 0.710302674
+0.281524927 0.709193894
+0.282502444 0.708091063
+0.283479961 0.707005566
+0.284457478 0.705925531
+0.285434995 0.704850918
+0.286412512 0.703781686
+0.287390029 0.702717795
+0.288367546 0.701668621
+0.289345064 0.700625580
+0.290322581 0.699587425
+0.291300098 0.698554121
+0.292277615 0.697525635
+0.293255132 0.696509490
+0.294232649 0.695500037
+0.295210166 0.694494984
+0.296187683 0.693494303
+0.297165200 0.692497965
+0.298142717 0.691511860
+0.299120235 0.690532874
+0.300097752 0.689557847
+0.301075269 0.688586755
+0.302052786 0.687619575
+0.303030303 0.686660765
+0.304007820 0.685709376
+0.304985337 0.684761545
+0.305962854 0.683817249
+0.306940371 0.682876470
+0.307917889 0.681942420
+0.308895406 0.681015980
+0.309872923 0.680092726
+0.310850440 0.679172643
+0.311827957 0.678255714
+0.312805474 0.677344077
+0.313782991 0.676440126
+0.314760508 0.675539023
+0.315738025 0.674640752
+0.316715543 0.673745302
+0.317693060 0.672853893
+0.318670577 0.671970143
+0.319648094 0.671088924
+0.320625611 0.670210227
+0.321603128 0.669334041
+0.322580645 0.668460818
+0.323558162 0.667595126
+0.324535679 0.666731672
+0.325513196 0.665870450
+0.326490714 0.665011449
+0.327468231 0.664154662
+0.328445748 0.663304848
+0.329423265 0.662457164
+0.330400782 0.661611439
+0.331378299 0.660767667
+0.332355816 0.659925840
+0.333333333 0.659089669
+0.334310850 0.658255868
+0.335288368 0.657423770
+0.336265885 0.656593371
+0.337243402 0.655764665
+0.338220919 0.654940458
+0.339198436 0.654118746
+0.340175953 0.653298497
+0.341153470 0.652479705
+0.342130987 0.651662368
+0.343108504 0.650848521
+0.344086022 0.650037186
+0.345063539 0.649227083
+0.346041056 0.648418210
+0.347018573 0.647610563
+0.347996090 0.646805538
+0.348973607 0.646002934
+0.349951124 0.645201343
+0.350928641 0.644400763
+0.351906158 0.643601190
+0.352883675 0.642803505
+0.353861193 0.642008044
+0.354838710 0.641213384
+0.355816227 0.640419523
+0.356793744 0.639626459
+0.357771261 0.638834675
+0.358748778 0.638044814
+0.359726295 0.637255548
+0.360703812 0.636466876
+0.361681329 0.635678797
+0.362658847 0.634891512
+0.363636364 0.634105743
+0.364613881 0.633320368
+0.365591398 0.632535386
+0.366568915 0.631750798
+0.367546432 0.630966638
+0.368523949 0.630183479
+0.369501466 0.629400516
+0.370478983 0.628617749
+0.371456500 0.627835178
+0.372434018 0.627052803
+0.373411535 0.626270772
+0.374389052 0.625488759
+0.375366569 0.624706745
+0.376344086 0.623924731
+0.377321603 0.623142717
+0.378299120 0.622360434
+0.379276637 0.621577912
+0.380254154 0.620795194
+0.381231672 0.620012280
+0.382209189 0.619229171
+0.383186706 0.618445288
+0.384164223 0.617660798
+0.385141740 0.616875914
+0.386119257 0.616090638
+0.387096774 0.615304967
+0.388074291 0.614518130
+0.389051808 0.613730200
+0.390029326 0.612941676
+0.391006843 0.612152558
+0.391984360 0.611362846
+0.392961877 0.610571682
+0.393939394 0.609778818
+0.394916911 0.608985156
+0.395894428 0.608190696
+0.396871945 0.607395436
+0.397849462 0.606598545
+0.398826979 0.605799225
+0.399804497 0.604998896
+0.400782014 0.604197558
+0.401759531 0.603395208
+0.402737048 0.602591157
+0.403714565 0.601783817
+0.404692082 0.600975251
+0.405669599 0.600165455
+0.406647116 0.599354429
+0.407624633 0.598541740
+0.408602151 0.597724765
+0.409579668 0.596906338
+0.410557185 0.596086453
+0.411534702 0.595265107
+0.412512219 0.594442248
+0.413489736 0.593613964
+0.414467253 0.592783988
+0.415444770 0.591952316
+0.416422287 0.591118941
+0.417399804 0.590283858
+0.418377322 0.589442972
+0.419354839 0.588599687
+0.420332356 0.587754450
+0.421309873 0.586907257
+0.422287390 0.586058099
+0.423264907 0.585202955
+0.424242424 0.584344508
+0.425219941 0.583483842
+0.426197458 0.582620947
+0.427174976 0.581755815
+0.428152493 0.580884615
+0.429130010 0.580009054
+0.430107527 0.579130986
+0.431085044 0.578250399
+0.432062561 0.577367283
+0.433040078 0.576478121
+0.434017595 0.575583374
+0.434995112 0.574685810
+0.435972630 0.573785416
+0.436950147 0.572882178
+0.437927664 0.571973027
+0.438905181 0.571056884
+0.439882698 0.570137591
+0.440860215 0.569215132
+0.441837732 0.568289490
+0.442815249 0.567358177
+0.443792766 0.566418275
+0.444770283 0.565474860
+0.445747801 0.564527914
+0.446725318 0.563577417
+0.447702835 0.562621612
+0.448680352 0.561655405
+0.449657869 0.560685294
+0.450635386 0.559711253
+0.451612903 0.558733259
+0.452590420 0.557750445
+0.453567937 0.556755188
+0.454545455 0.555755595
+0.455522972 0.554751638
+0.456500489 0.553743287
+0.457478006 0.552730515
+0.458455523 0.551703450
+0.459433040 0.550671354
+0.460410557 0.549634415
+0.461388074 0.548592599
+0.462365591 0.547545872
+0.463343109 0.546484786
+0.464320626 0.545416893
+0.465298143 0.544343629
+0.466275660 0.543264953
+0.467253177 0.542180826
+0.468230694 0.541082374
+0.469208211 0.539975079
+0.470185728 0.538861828
+0.471163245 0.537742573
+0.472140762 0.536617267
+0.473118280 0.535477779
+0.474095797 0.534327120
+0.475073314 0.533169855
+0.476050831 0.532005928
+0.477028348 0.530835281
+0.478005865 0.529650711
+0.478983382 0.528452318
+0.479960899 0.527246594
+0.480938416 0.526033471
+0.481915934 0.524812880
+0.482893451 0.523578752
+0.483870968 0.522327784
+0.484848485 0.521068672
+0.485826002 0.519801335
+0.486803519 0.518525692
+0.487781036 0.517237031
+0.488758553 0.515928105
+0.489736070 0.514610118
+0.490713587 0.513282977
+0.491691105 0.511946585
+0.492668622 0.510597845
+0.493646139 0.509224947
+0.494623656 0.507841954
+0.495601173 0.506448755
+0.496578690 0.505045237
+0.497556207 0.503630203
+0.498533724 0.502186589
+0.499511241 0.500731707
+0.500488759 0.499268293
+0.501466276 0.497813411
+0.502443793 0.496369797
+0.503421310 0.494954763
+0.504398827 0.493551245
+0.505376344 0.492158046
+0.506353861 0.490775053
+0.507331378 0.489402155
+0.508308895 0.488053415
+0.509286413 0.486717023
+0.510263930 0.485389882
+0.511241447 0.484071895
+0.512218964 0.482762969
+0.513196481 0.481474308
+0.514173998 0.480198665
+0.515151515 0.478931328
+0.516129032 0.477672216
+0.517106549 0.476421248
+0.518084066 0.475187120
+0.519061584 0.473966529
+0.520039101 0.472753406
+0.521016618 0.471547682
+0.521994135 0.470349289
+0.522971652 0.469164719
+0.523949169 0.467994072
+0.524926686 0.466830145
+0.525904203 0.465672880
+0.526881720 0.464522221
+0.527859238 0.463382733
+0.528836755 0.462257427
+0.529814272 0.461138172
+0.530791789 0.460024921
+0.531769306 0.458917626
+0.532746823 0.457819174
+0.533724340 0.456735047
+0.534701857 0.455656371
+0.535679374 0.454583107
+0.536656891 0.453515214
+0.537634409 0.452454128
+0.538611926 0.451407401
+0.539589443 0.450365585
+0.540566960 0.449328646
+0.541544477 0.448296550
+0.542521994 0.447269485
+0.543499511 0.446256713
+0.544477028 0.445248362
+0.545454545 0.444244405
+0.546432063 0.443244812
+0.547409580 0.442249555
+0.548387097 0.441266741
+0.549364614 0.440288747
+0.550342131 0.439314706
+0.551319648 0.438344595
+0.552297165 0.437378388
+0.553274682 0.436422583
+0.554252199 0.435472086
+0.555229717 0.434525140
+0.556207234 0.433581725
+0.557184751 0.432641823
+0.558162268 0.431710510
+0.559139785 0.430784868
+0.560117302 0.429862409
+0.561094819 0.428943116
+0.562072336 0.428026973
+0.563049853 0.427117822
+0.564027370 0.426214584
+0.565004888 0.425314190
+0.565982405 0.424416626
+0.566959922 0.423521879
+0.567937439 0.422632717
+0.568914956 0.421749601
+0.569892473 0.420869014
+0.570869990 0.419990946
+0.571847507 0.419115385
+0.572825024 0.418244185
+0.573802542 0.417379053
+0.574780059 0.416516158
+0.575757576 0.415655492
+0.576735093 0.414797045
+0.577712610 0.413941901
+0.578690127 0.413092743
+0.579667644 0.412245550
+0.580645161 0.411400313
+0.581622678 0.410557028
+0.582600196 0.409716142
+0.583577713 0.408881059
+0.584555230 0.408047684
+0.585532747 0.407216012
+0.586510264 0.406386036
+0.587487781 0.405557752
+0.588465298 0.404734893
+0.589442815 0.403913547
+0.590420332 0.403093662
+0.591397849 0.402275235
+0.592375367 0.401458260
+0.593352884 0.400645571
+0.594330401 0.399834545
+0.595307918 0.399024749
+0.596285435 0.398216183
+0.597262952 0.397408843
+0.598240469 0.396604792
+0.599217986 0.395802442
+0.600195503 0.395001104
+0.601173021 0.394200775
+0.602150538 0.393401455
+0.603128055 0.392604564
+0.604105572 0.391809304
+0.605083089 0.391014844
+0.606060606 0.390221182
+0.607038123 0.389428318
+0.608015640 0.388637154
+0.608993157 0.387847442
+0.609970674 0.387058324
+0.610948192 0.386269800
+0.611925709 0.385481870
+0.612903226 0.384695033
+0.613880743 0.383909362
+0.614858260 0.383124086
+0.615835777 0.382339202
+0.616813294 0.381554712
+0.617790811 0.380770829
+0.618768328 0.379987720
+0.619745846 0.379204806
+0.620723363 0.378422088
+0.621700880 0.377639566
+0.622678397 0.376857283
+0.623655914 0.376075269
+0.624633431 0.375293255
+0.625610948 0.374511241
+0.626588465 0.373729228
+0.627565982 0.372947197
+0.628543500 0.372164822
+0.629521017 0.371382251
+0.630498534 0.370599484
+0.631476051 0.369816521
+0.632453568 0.369033362
+0.633431085 0.368249202
+0.634408602 0.367464614
+0.635386119 0.366679632
+0.636363636 0.365894257
+0.637341153 0.365108488
+0.638318671 0.364321203
+0.639296188 0.363533124
+0.640273705 0.362744452
+0.641251222 0.361955186
+0.642228739 0.361165325
+0.643206256 0.360373541
+0.644183773 0.359580477
+0.645161290 0.358786616
+0.646138807 0.357991956
+0.647116325 0.357196495
+0.648093842 0.356398810
+0.649071359 0.355599237
+0.650048876 0.354798657
+0.651026393 0.353997066
+0.652003910 0.353194462
+0.652981427 0.352389437
+0.653958944 0.351581790
+0.654936461 0.350772917
+0.655913978 0.349962814
+0.656891496 0.349151479
+0.657869013 0.348337632
+0.658846530 0.347520295
+0.659824047 0.346701503
+0.660801564 0.345881254
+0.661779081 0.345059542
+0.662756598 0.344235335
+0.663734115 0.343406629
+0.664711632 0.342576230
+0.665689150 0.341744132
+0.666666667 0.340910331
+0.667644184 0.340074160
+0.668621701 0.339232333
+0.669599218 0.338388561
+0.670576735 0.337542836
+0.671554252 0.336695152
+0.672531769 0.335845338
+0.673509286 0.334988551
+0.674486804 0.334129550
+0.675464321 0.333268328
+0.676441838 0.332404874
+0.677419355 0.331539182
+0.678396872 0.330665959
+0.679374389 0.329789773
+0.680351906 0.328911076
+0.681329423 0.328029857
+0.682306940 0.327146107
+0.683284457 0.326254698
+0.684261975 0.325359248
+0.685239492 0.324460977
+0.686217009 0.323559874
+0.687194526 0.322655923
+0.688172043 0.321744286
+0.689149560 0.320827357
+0.690127077 0.319907274
+0.691104594 0.318984020
+0.692082111 0.318057580
+0.693059629 0.317123530
+0.694037146 0.316182751
+0.695014663 0.315238455
+0.695992180 0.314290624
+0.696969697 0.313339235
+0.697947214 0.312380425
+0.698924731 0.311413245
+0.699902248 0.310442153
+0.700879765 0.309467126
+0.701857283 0.308488140
+0.702834800 0.307502035
+0.703812317 0.306505697
+0.704789834 0.305505016
+0.705767351 0.304499963
+0.706744868 0.303490510
+0.707722385 0.302474365
+0.708699902 0.301445879
+0.709677419 0.300412575
+0.710654936 0.299374420
+0.711632454 0.298331379
+0.712609971 0.297282205
+0.713587488 0.296218314
+0.714565005 0.295149082
+0.715542522 0.294074469
+0.716520039 0.292994434
+0.717497556 0.291908937
+0.718475073 0.290806106
+0.719452590 0.289697326
+0.720430108 0.288582579
+0.721407625 0.287461816
+0.722385142 0.286334988
+0.723362659 0.285190730
+0.724340176 0.284038425
+0.725317693 0.282879501
+0.726295210 0.281713899
+0.727272727 0.280541562
+0.728250244 0.279351796
+0.729227761 0.278151577
+0.730205279 0.276944010
+0.731182796 0.275729026
+0.732160313 0.274506558
+0.733137830 0.273266769
+0.734115347 0.272013773
+0.735092864 0.270752612
+0.736070381 0.269483206
+0.737047898 0.268205474
+0.738025415 0.266910644
+0.739002933 0.265599461
+0.739980450 0.264279195
+0.740957967 0.262949750
+0.741935484 0.261611030
+0.742913001 0.260255561
+0.743890518 0.258880149
+0.744868035 0.257494616
+0.745845552 0.256098848
+0.746823069 0.254692732
+0.747800587 0.253270349
+0.748778104 0.251823930
+0.749755621 0.250366211
+0.750733138 0.250000000
+0.751710655 0.250000000
+0.752688172 0.250000000
+0.753665689 0.250000000
+0.754643206 0.250000000
+0.755620723 0.250000000
+0.756598240 0.250000000
+0.757575758 0.250000000
+0.758553275 0.250000000
+0.759530792 0.250000000
+0.760508309 0.250000000
+0.761485826 0.250000000
+0.762463343 0.250000000
+0.763440860 0.250000000
+0.764418377 0.250000000
+0.765395894 0.250000000
+0.766373412 0.250000000
+0.767350929 0.250000000
+0.768328446 0.250000000
+0.769305963 0.250000000
+0.770283480 0.250000000
+0.771260997 0.250000000
+0.772238514 0.250000000
+0.773216031 0.250000000
+0.774193548 0.250000000
+0.775171065 0.250000000
+0.776148583 0.250000000
+0.777126100 0.250000000
+0.778103617 0.250000000
+0.779081134 0.250000000
+0.780058651 0.250000000
+0.781036168 0.250000000
+0.782013685 0.250000000
+0.782991202 0.250000000
+0.783968719 0.250000000
+0.784946237 0.250000000
+0.785923754 0.250000000
+0.786901271 0.250000000
+0.787878788 0.250000000
+0.788856305 0.250000000
+0.789833822 0.250000000
+0.790811339 0.250000000
+0.791788856 0.250000000
+0.792766373 0.250000000
+0.793743891 0.250000000
+0.794721408 0.250000000
+0.795698925 0.250000000
+0.796676442 0.250000000
+0.797653959 0.250000000
+0.798631476 0.250000000
+0.799608993 0.250000000
+0.800586510 0.250000000
+0.801564027 0.250000000
+0.802541544 0.250000000
+0.803519062 0.250000000
+0.804496579 0.250000000
+0.805474096 0.250000000
+0.806451613 0.250000000
+0.807429130 0.250000000
+0.808406647 0.250000000
+0.809384164 0.250000000
+0.810361681 0.250000000
+0.811339198 0.250000000
+0.812316716 0.250000000
+0.813294233 0.250000000
+0.814271750 0.250000000
+0.815249267 0.250000000
+0.816226784 0.250000000
+0.817204301 0.250000000
+0.818181818 0.250000000
+0.819159335 0.250000000
+0.820136852 0.250000000
+0.821114370 0.250000000
+0.822091887 0.250000000
+0.823069404 0.250000000
+0.824046921 0.250000000
+0.825024438 0.250000000
+0.826001955 0.250000000
+0.826979472 0.250000000
+0.827956989 0.250000000
+0.828934506 0.250000000
+0.829912023 0.250000000
+0.830889541 0.250000000
+0.831867058 0.250000000
+0.832844575 0.250000000
+0.833822092 0.250000000
+0.834799609 0.250000000
+0.835777126 0.250000000
+0.836754643 0.250000000
+0.837732160 0.250000000
+0.838709677 0.250000000
+0.839687195 0.250000000
+0.840664712 0.250000000
+0.841642229 0.250000000
+0.842619746 0.250000000
+0.843597263 0.250000000
+0.844574780 0.250000000
+0.845552297 0.250000000
+0.846529814 0.250000000
+0.847507331 0.250000000
+0.848484848 0.250000000
+0.849462366 0.250000000
+0.850439883 0.250000000
+0.851417400 0.250000000
+0.852394917 0.250000000
+0.853372434 0.250000000
+0.854349951 0.250000000
+0.855327468 0.250000000
+0.856304985 0.250000000
+0.857282502 0.250000000
+0.858260020 0.250000000
+0.859237537 0.250000000
+0.860215054 0.250000000
+0.861192571 0.250000000
+0.862170088 0.250000000
+0.863147605 0.250000000
+0.864125122 0.250000000
+0.865102639 0.250000000
+0.866080156 0.250000000
+0.867057674 0.250000000
+0.868035191 0.250000000
+0.869012708 0.250000000
+0.869990225 0.250000000
+0.870967742 0.250000000
+0.871945259 0.250000000
+0.872922776 0.250000000
+0.873900293 0.250000000
+0.874877810 0.250000000
+0.875855327 0.250000000
+0.876832845 0.250000000
+0.877810362 0.250000000
+0.878787879 0.250000000
+0.879765396 0.250000000
+0.880742913 0.250000000
+0.881720430 0.250000000
+0.882697947 0.250000000
+0.883675464 0.250000000
+0.884652981 0.250000000
+0.885630499 0.250000000
+0.886608016 0.250000000
+0.887585533 0.250000000
+0.888563050 0.250000000
+0.889540567 0.250000000
+0.890518084 0.250000000
+0.891495601 0.250000000
+0.892473118 0.250000000
+0.893450635 0.250000000
+0.894428152 0.250000000
+0.895405670 0.250000000
+0.896383187 0.250000000
+0.897360704 0.250000000
+0.898338221 0.250000000
+0.899315738 0.250000000
+0.900293255 0.250000000
+0.901270772 0.250000000
+0.902248289 0.250000000
+0.903225806 0.250000000
+0.904203324 0.250000000
+0.905180841 0.250000000
+0.906158358 0.250000000
+0.907135875 0.250000000
+0.908113392 0.250000000
+0.909090909 0.250000000
+0.910068426 0.250000000
+0.911045943 0.250000000
+0.912023460 0.250000000
+0.913000978 0.250000000
+0.913978495 0.250000000
+0.914956012 0.250000000
+0.915933529 0.250000000
+0.916911046 0.250000000
+0.917888563 0.250000000
+0.918866080 0.250000000
+0.919843597 0.250000000
+0.920821114 0.250000000
+0.921798631 0.250000000
+0.922776149 0.250000000
+0.923753666 0.250000000
+0.924731183 0.250000000
+0.925708700 0.250000000
+0.926686217 0.250000000
+0.927663734 0.250000000
+0.928641251 0.250000000
+0.929618768 0.250000000
+0.930596285 0.250000000
+0.931573803 0.250000000
+0.932551320 0.250000000
+0.933528837 0.250000000
+0.934506354 0.250000000
+0.935483871 0.250000000
+0.936461388 0.250000000
+0.937438905 0.250000000
+0.938416422 0.250000000
+0.939393939 0.250000000
+0.940371457 0.250000000
+0.941348974 0.250000000
+0.942326491 0.250000000
+0.943304008 0.250000000
+0.944281525 0.250000000
+0.945259042 0.250000000
+0.946236559 0.250000000
+0.947214076 0.250000000
+0.948191593 0.250000000
+0.949169110 0.250000000
+0.950146628 0.250000000
+0.951124145 0.250000000
+0.952101662 0.250000000
+0.953079179 0.250000000
+0.954056696 0.250000000
+0.955034213 0.250000000
+0.956011730 0.250000000
+0.956989247 0.250000000
+0.957966764 0.250000000
+0.958944282 0.250000000
+0.959921799 0.250000000
+0.960899316 0.250000000
+0.961876833 0.250000000
+0.962854350 0.250000000
+0.963831867 0.250000000
+0.964809384 0.250000000
+0.965786901 0.250000000
+0.966764418 0.250000000
+0.967741935 0.250000000
+0.968719453 0.250000000
+0.969696970 0.250000000
+0.970674487 0.250000000
+0.971652004 0.250000000
+0.972629521 0.250000000
+0.973607038 0.250000000
+0.974584555 0.250000000
+0.975562072 0.250000000
+0.976539589 0.250000000
+0.977517107 0.250000000
+0.978494624 0.250000000
+0.979472141 0.250000000
+0.980449658 0.250000000
+0.981427175 0.250000000
+0.982404692 0.250000000
+0.983382209 0.250000000
+0.984359726 0.250000000
+0.985337243 0.250000000
+0.986314761 0.250000000
+0.987292278 0.250000000
+0.988269795 0.250000000
+0.989247312 0.250000000
+0.990224829 0.250000000
+0.991202346 0.250000000
+0.992179863 0.250000000
+0.993157380 0.250000000
+0.994134897 0.250000000
+0.995112414 0.250000000
+0.996089932 0.250000000
+0.997067449 0.250000000
+0.998044966 0.250000000
+0.999022483 0.250000000
+1.000000000 nan
diff --git a/examples/mamdani/SimpleDimmer.fll b/examples/mamdani/SimpleDimmer.fll
new file mode 100644
index 0000000..896bebf
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.fll
@@ -0,0 +1,28 @@
+Engine: SimpleDimmer
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW \ No newline at end of file
diff --git a/examples/mamdani/SimpleDimmer.java b/examples/mamdani/SimpleDimmer.java
new file mode 100644
index 0000000..d7b127d
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.java
@@ -0,0 +1,63 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class SimpleDimmer{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("SimpleDimmer");
+engine.setDescription("");
+
+InputVariable Ambient = new InputVariable();
+Ambient.setName("Ambient");
+Ambient.setDescription("");
+Ambient.setEnabled(true);
+Ambient.setRange(0.000, 1.000);
+Ambient.setLockValueInRange(false);
+Ambient.addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient.addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine.addInputVariable(Ambient);
+
+OutputVariable Power = new OutputVariable();
+Power.setName("Power");
+Power.setDescription("");
+Power.setEnabled(true);
+Power.setRange(0.000, 1.000);
+Power.setLockValueInRange(false);
+Power.setAggregation(new Maximum());
+Power.setDefuzzifier(new Centroid(200));
+Power.setDefaultValue(Double.NaN);
+Power.setLockPreviousValue(false);
+Power.addTerm(new Triangle("LOW", 0.000, 0.250, 0.500));
+Power.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Power.addTerm(new Triangle("HIGH", 0.500, 0.750, 1.000));
+engine.addOutputVariable(Power);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(new Minimum());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is BRIGHT then Power is LOW", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/SimpleDimmer.pdf b/examples/mamdani/SimpleDimmer.pdf
new file mode 100644
index 0000000..82ef82f
--- /dev/null
+++ b/examples/mamdani/SimpleDimmer.pdf
Binary files differ
diff --git a/examples/mamdani/SimpleDimmerChained.R b/examples/mamdani/SimpleDimmerChained.R
new file mode 100644
index 0000000..323aa7d
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.R
@@ -0,0 +1,85 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "SimpleDimmerChained"
+engine.fll = "Engine: SimpleDimmerChained
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+OutputVariable: InversePower
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 500
+ default: nan
+ lock-previous: false
+ term: LOW Cosine 0.200 0.500
+ term: MEDIUM Cosine 0.500 0.500
+ term: HIGH Cosine 0.800 0.500
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
+ rule: if Power is LOW then InversePower is HIGH
+ rule: if Power is MEDIUM then InversePower is MEDIUM
+ rule: if Power is HIGH then InversePower is LOW"
+
+engine.fldFile = "SimpleDimmerChained.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("Ambient vs Power")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Power vs Ambient")
+
+engine.plot.i1_o2 = ggplot(engine.df, aes(Ambient, InversePower)) +
+ geom_line(aes(color=InversePower), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("Ambient vs InversePower")
+
+engine.plot.o2_i1 = ggplot(engine.df, aes(Ambient, InversePower)) +
+ geom_line(aes(color=InversePower), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("InversePower vs Ambient")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, engine.plot.i1_o2, engine.plot.o2_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/SimpleDimmerChained.cpp b/examples/mamdani/SimpleDimmerChained.cpp
new file mode 100644
index 0000000..bc59c8e
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.cpp
@@ -0,0 +1,70 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("SimpleDimmerChained");
+engine->setDescription("");
+
+InputVariable* Ambient = new InputVariable;
+Ambient->setName("Ambient");
+Ambient->setDescription("");
+Ambient->setEnabled(true);
+Ambient->setRange(0.000, 1.000);
+Ambient->setLockValueInRange(false);
+Ambient->addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient->addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine->addInputVariable(Ambient);
+
+OutputVariable* Power = new OutputVariable;
+Power->setName("Power");
+Power->setDescription("");
+Power->setEnabled(true);
+Power->setRange(0.000, 1.000);
+Power->setLockValueInRange(false);
+Power->setAggregation(new Maximum);
+Power->setDefuzzifier(new Centroid(200));
+Power->setDefaultValue(fl::nan);
+Power->setLockPreviousValue(false);
+Power->addTerm(new Triangle("LOW", 0.000, 0.250, 0.500));
+Power->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Power->addTerm(new Triangle("HIGH", 0.500, 0.750, 1.000));
+engine->addOutputVariable(Power);
+
+OutputVariable* InversePower = new OutputVariable;
+InversePower->setName("InversePower");
+InversePower->setDescription("");
+InversePower->setEnabled(true);
+InversePower->setRange(0.000, 1.000);
+InversePower->setLockValueInRange(false);
+InversePower->setAggregation(new Maximum);
+InversePower->setDefuzzifier(new Centroid(500));
+InversePower->setDefaultValue(fl::nan);
+InversePower->setLockPreviousValue(false);
+InversePower->addTerm(new Cosine("LOW", 0.200, 0.500));
+InversePower->addTerm(new Cosine("MEDIUM", 0.500, 0.500));
+InversePower->addTerm(new Cosine("HIGH", 0.800, 0.500));
+engine->addOutputVariable(InversePower);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(new Minimum);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is BRIGHT then Power is LOW", engine));
+ruleBlock->addRule(Rule::parse("if Power is LOW then InversePower is HIGH", engine));
+ruleBlock->addRule(Rule::parse("if Power is MEDIUM then InversePower is MEDIUM", engine));
+ruleBlock->addRule(Rule::parse("if Power is HIGH then InversePower is LOW", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/SimpleDimmerChained.fcl b/examples/mamdani/SimpleDimmerChained.fcl
new file mode 100644
index 0000000..29bb4ea
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.fcl
@@ -0,0 +1,51 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK SimpleDimmerChained
+
+VAR_INPUT
+ Ambient: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Power: REAL;
+ InversePower: REAL;
+END_VAR
+
+FUZZIFY Ambient
+ RANGE := (0.000 .. 1.000);
+ TERM DARK := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM BRIGHT := Triangle 0.500 0.750 1.000;
+END_FUZZIFY
+
+DEFUZZIFY Power
+ RANGE := (0.000 .. 1.000);
+ TERM LOW := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM HIGH := Triangle 0.500 0.750 1.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY InversePower
+ RANGE := (0.000 .. 1.000);
+ TERM LOW := Cosine 0.200 0.500;
+ TERM MEDIUM := Cosine 0.500 0.500;
+ TERM HIGH := Cosine 0.800 0.500;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ ACT : MIN;
+ RULE 1 : if Ambient is DARK then Power is HIGH
+ RULE 2 : if Ambient is MEDIUM then Power is MEDIUM
+ RULE 3 : if Ambient is BRIGHT then Power is LOW
+ RULE 4 : if Power is LOW then InversePower is HIGH
+ RULE 5 : if Power is MEDIUM then InversePower is MEDIUM
+ RULE 6 : if Power is HIGH then InversePower is LOW
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/SimpleDimmerChained.fis b/examples/mamdani/SimpleDimmerChained.fis
new file mode 100644
index 0000000..c2fc642
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.fis
@@ -0,0 +1,46 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='SimpleDimmerChained'
+Type='mamdani'
+Version=6.0
+NumInputs=1
+NumOutputs=2
+NumRules=6
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Ambient'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='DARK':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='BRIGHT':'trimf',[0.500 0.750 1.000]
+
+[Output1]
+Name='Power'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='LOW':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='HIGH':'trimf',[0.500 0.750 1.000]
+
+[Output2]
+Name='InversePower'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='LOW':'cosinemf',[0.200 0.500]
+MF2='MEDIUM':'cosinemf',[0.500 0.500]
+MF3='HIGH':'cosinemf',[0.800 0.500]
+
+[Rules]
+1.000 , 3.000 0.000 (1.000) : 1
+2.000 , 2.000 0.000 (1.000) : 1
+3.000 , 1.000 0.000 (1.000) : 1
+0.000 , 0.000 3.000 (1.000) : 1
+0.000 , 0.000 2.000 (1.000) : 1
+0.000 , 0.000 1.000 (1.000) : 1
diff --git a/examples/mamdani/SimpleDimmerChained.fld b/examples/mamdani/SimpleDimmerChained.fld
new file mode 100644
index 0000000..843c017
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.fld
@@ -0,0 +1,1025 @@
+Ambient Power InversePower
+0.000000000 nan nan
+0.000977517 0.750000000 0.221671502
+0.001955034 0.750000000 0.220306607
+0.002932551 0.750000000 0.219272108
+0.003910068 0.750000000 0.218372593
+0.004887586 0.750000000 0.217595038
+0.005865103 0.750000000 0.216891736
+0.006842620 0.750000000 0.216242049
+0.007820137 0.750000000 0.215635499
+0.008797654 0.750000000 0.215066121
+0.009775171 0.750000000 0.214530188
+0.010752688 0.750000000 0.214025192
+0.011730205 0.750000000 0.213535928
+0.012707722 0.750000000 0.213059653
+0.013685239 0.750000000 0.212609497
+0.014662757 0.750000000 0.212181500
+0.015640274 0.750000000 0.211749797
+0.016617791 0.750000000 0.211342499
+0.017595308 0.750000000 0.210947791
+0.018572825 0.750000000 0.210554977
+0.019550342 0.750000000 0.210185583
+0.020527859 0.750000000 0.209810047
+0.021505376 0.750000000 0.209453273
+0.022482893 0.750000000 0.209099710
+0.023460411 0.750000000 0.208754784
+0.024437928 0.750000000 0.208418460
+0.025415445 0.750000000 0.208108896
+0.026392962 0.750000000 0.207822337
+0.027370479 0.750000000 0.207557090
+0.028347996 0.750000000 0.207310043
+0.029325513 0.750000000 0.207080132
+0.030303030 0.750000000 0.206864987
+0.031280547 0.750000000 0.206663695
+0.032258065 0.750000000 0.206474685
+0.033235582 0.750000000 0.206296887
+0.034213099 0.750000000 0.206129563
+0.035190616 0.750000000 0.205971282
+0.036168133 0.750000000 0.205822154
+0.037145650 0.750000000 0.205680293
+0.038123167 0.750000000 0.205546551
+0.039100684 0.750000000 0.205418994
+0.040078201 0.750000000 0.205298019
+0.041055718 0.750000000 0.205182743
+0.042033236 0.750000000 0.205072718
+0.043010753 0.750000000 0.204968065
+0.043988270 0.750000000 0.204867643
+0.044965787 0.750000000 0.204772102
+0.045943304 0.750000000 0.204680372
+0.046920821 0.750000000 0.204592478
+0.047898338 0.750000000 0.204508389
+0.048875855 0.750000000 0.204427324
+0.049853372 0.750000000 0.204349869
+0.050830890 0.750000000 0.204275190
+0.051808407 0.750000000 0.204203265
+0.052785924 0.750000000 0.204134275
+0.053763441 0.750000000 0.204067513
+0.054740958 0.750000000 0.204003359
+0.055718475 0.750000000 0.203941436
+0.056695992 0.750000000 0.203881398
+0.057673509 0.750000000 0.203823826
+0.058651026 0.750000000 0.203767941
+0.059628543 0.750000000 0.203713842
+0.060606061 0.750000000 0.203661714
+0.061583578 0.750000000 0.203611030
+0.062561095 0.750000000 0.203562034
+0.063538612 0.750000000 0.203514617
+0.064516129 0.750000000 0.203468446
+0.065493646 0.750000000 0.203423862
+0.066471163 0.750000000 0.203380551
+0.067448680 0.750000000 0.203338322
+0.068426197 0.750000000 0.203297578
+0.069403715 0.750000000 0.203257869
+0.070381232 0.750000000 0.203219115
+0.071358749 0.750000000 0.203181723
+0.072336266 0.750000000 0.203145191
+0.073313783 0.750000000 0.203109538
+0.074291300 0.750000000 0.203075066
+0.075268817 0.750000000 0.203041351
+0.076246334 0.750000000 0.203008438
+0.077223851 0.750000000 0.202976564
+0.078201369 0.750000000 0.202945359
+0.079178886 0.750000000 0.202914878
+0.080156403 0.750000000 0.202885326
+0.081133920 0.750000000 0.202856368
+0.082111437 0.750000000 0.202828056
+0.083088954 0.750000000 0.202800588
+0.084066471 0.750000000 0.202773648
+0.085043988 0.750000000 0.202747278
+0.086021505 0.750000000 0.202721688
+0.086999022 0.750000000 0.202696569
+0.087976540 0.750000000 0.202671946
+0.088954057 0.750000000 0.202648053
+0.089931574 0.750000000 0.202624584
+0.090909091 0.750000000 0.202601536
+0.091886608 0.750000000 0.202579184
+0.092864125 0.750000000 0.202557213
+0.093841642 0.750000000 0.202535613
+0.094819159 0.750000000 0.202514642
+0.095796676 0.750000000 0.202494036
+0.096774194 0.750000000 0.202473765
+0.097751711 0.750000000 0.202454042
+0.098729228 0.750000000 0.202434684
+0.099706745 0.750000000 0.202415629
+0.100684262 0.750000000 0.202397043
+0.101661779 0.750000000 0.202378829
+0.102639296 0.750000000 0.202360889
+0.103616813 0.750000000 0.202343345
+0.104594330 0.750000000 0.202326181
+0.105571848 0.750000000 0.202309267
+0.106549365 0.750000000 0.202292677
+0.107526882 0.750000000 0.202276482
+0.108504399 0.750000000 0.202260514
+0.109481916 0.750000000 0.202244803
+0.110459433 0.750000000 0.202229501
+0.111436950 0.750000000 0.202214406
+0.112414467 0.750000000 0.202199515
+0.113391984 0.750000000 0.202185031
+0.114369501 0.750000000 0.202170746
+0.115347019 0.750000000 0.202156646
+0.116324536 0.750000000 0.202142887
+0.117302053 0.750000000 0.202129352
+0.118279570 0.750000000 0.202115988
+0.119257087 0.750000000 0.202102901
+0.120234604 0.750000000 0.202090065
+0.121212121 0.750000000 0.202077384
+0.122189638 0.750000000 0.202064922
+0.123167155 0.750000000 0.202052737
+0.124144673 0.750000000 0.202040694
+0.125122190 0.750000000 0.202028815
+0.126099707 0.750000000 0.202017236
+0.127077224 0.750000000 0.202005788
+0.128054741 0.750000000 0.201994470
+0.129032258 0.750000000 0.201983442
+0.130009775 0.750000000 0.201972551
+0.130987292 0.750000000 0.201961779
+0.131964809 0.750000000 0.201951246
+0.132942326 0.750000000 0.201940877
+0.133919844 0.750000000 0.201930618
+0.134897361 0.750000000 0.201920549
+0.135874878 0.750000000 0.201910669
+0.136852395 0.750000000 0.201900891
+0.137829912 0.750000000 0.201891259
+0.138807429 0.750000000 0.201881839
+0.139784946 0.750000000 0.201872513
+0.140762463 0.750000000 0.201863294
+0.141739980 0.750000000 0.201854307
+0.142717498 0.750000000 0.201845406
+0.143695015 0.750000000 0.201836590
+0.144672532 0.750000000 0.201827998
+0.145650049 0.750000000 0.201819498
+0.146627566 0.750000000 0.201811078
+0.147605083 0.750000000 0.201802845
+0.148582600 0.750000000 0.201794724
+0.149560117 0.750000000 0.201786676
+0.150537634 0.750000000 0.201778785
+0.151515152 0.750000000 0.201771022
+0.152492669 0.750000000 0.201763326
+0.153470186 0.750000000 0.201755760
+0.154447703 0.750000000 0.201748336
+0.155425220 0.750000000 0.201740974
+0.156402737 0.750000000 0.201733719
+0.157380254 0.750000000 0.201726616
+0.158357771 0.750000000 0.201719570
+0.159335288 0.750000000 0.201712612
+0.160312805 0.750000000 0.201705813
+0.161290323 0.750000000 0.201699068
+0.162267840 0.750000000 0.201692394
+0.163245357 0.750000000 0.201685884
+0.164222874 0.750000000 0.201679424
+0.165200391 0.750000000 0.201673024
+0.166177908 0.750000000 0.201666789
+0.167155425 0.750000000 0.201660600
+0.168132942 0.750000000 0.201654463
+0.169110459 0.750000000 0.201648489
+0.170087977 0.750000000 0.201642558
+0.171065494 0.750000000 0.201636676
+0.172043011 0.750000000 0.201630951
+0.173020528 0.750000000 0.201625266
+0.173998045 0.750000000 0.201619630
+0.174975562 0.750000000 0.201614142
+0.175953079 0.750000000 0.201608691
+0.176930596 0.750000000 0.201603293
+0.177908113 0.750000000 0.201598032
+0.178885630 0.750000000 0.201592805
+0.179863148 0.750000000 0.201587638
+0.180840665 0.750000000 0.201582594
+0.181818182 0.750000000 0.201577581
+0.182795699 0.750000000 0.201572640
+0.183773216 0.750000000 0.201567801
+0.184750733 0.750000000 0.201562993
+0.185728250 0.750000000 0.201558272
+0.186705767 0.750000000 0.201553632
+0.187683284 0.750000000 0.201549019
+0.188660802 0.750000000 0.201544513
+0.189638319 0.750000000 0.201540063
+0.190615836 0.750000000 0.201535638
+0.191593353 0.750000000 0.201531342
+0.192570870 0.750000000 0.201527074
+0.193548387 0.750000000 0.201522856
+0.194525904 0.750000000 0.201518740
+0.195503421 0.750000000 0.201514646
+0.196480938 0.750000000 0.201510635
+0.197458456 0.750000000 0.201506688
+0.198435973 0.750000000 0.201502762
+0.199413490 0.750000000 0.201498955
+0.200391007 0.750000000 0.201495170
+0.201368524 0.750000000 0.201491445
+0.202346041 0.750000000 0.201487799
+0.203323558 0.750000000 0.201484172
+0.204301075 0.750000000 0.201480648
+0.205278592 0.750000000 0.201477155
+0.206256109 0.750000000 0.201473716
+0.207233627 0.750000000 0.201470354
+0.208211144 0.750000000 0.201467007
+0.209188661 0.750000000 0.201463769
+0.210166178 0.750000000 0.201460550
+0.211143695 0.750000000 0.201457402
+0.212121212 0.750000000 0.201454307
+0.213098729 0.750000000 0.201451251
+0.214076246 0.750000000 0.201448278
+0.215053763 0.750000000 0.201445318
+0.216031281 0.750000000 0.201442464
+0.217008798 0.750000000 0.201439621
+0.217986315 0.750000000 0.201436866
+0.218963832 0.750000000 0.201434139
+0.219941349 0.750000000 0.201431486
+0.220918866 0.750000000 0.201428872
+0.221896383 0.750000000 0.201426324
+0.222873900 0.750000000 0.201423821
+0.223851417 0.750000000 0.201421381
+0.224828935 0.750000000 0.201418988
+0.225806452 0.750000000 0.201416661
+0.226783969 0.750000000 0.201414375
+0.227761486 0.750000000 0.201412163
+0.228739003 0.750000000 0.201409982
+0.229716520 0.750000000 0.201407891
+0.230694037 0.750000000 0.201405828
+0.231671554 0.750000000 0.201403846
+0.232649071 0.750000000 0.201401913
+0.233626588 0.750000000 0.201400032
+0.234604106 0.750000000 0.201398232
+0.235581623 0.750000000 0.201396477
+0.236559140 0.750000000 0.201394788
+0.237536657 0.750000000 0.201393176
+0.238514174 0.750000000 0.201391621
+0.239491691 0.750000000 0.201390128
+0.240469208 0.750000000 0.201388719
+0.241446725 0.750000000 0.201387385
+0.242424242 0.750000000 0.201386125
+0.243401760 0.750000000 0.201384946
+0.244379277 0.750000000 0.201383854
+0.245356794 0.750000000 0.201382854
+0.246334311 0.750000000 0.201381954
+0.247311828 0.750000000 0.201381173
+0.248289345 0.750000000 0.201380522
+0.249266862 0.750000000 0.201380043
+0.250244379 0.749633789 0.201846207
+0.251221896 0.748176070 0.203676892
+0.252199413 0.746729651 0.205470420
+0.253176931 0.745307268 0.207232921
+0.254154448 0.743901152 0.208969603
+0.255131965 0.742505384 0.210681995
+0.256109482 0.741119851 0.212371422
+0.257086999 0.739744439 0.214039141
+0.258064516 0.738388970 0.215686343
+0.259042033 0.737050250 0.217314161
+0.260019550 0.735720805 0.218923667
+0.260997067 0.734400539 0.220515879
+0.261974585 0.733089356 0.222091759
+0.262952102 0.731794526 0.223649762
+0.263929619 0.730516794 0.225192151
+0.264907136 0.729247388 0.226720383
+0.265884653 0.727986227 0.228232727
+0.266862170 0.726733231 0.229730635
+0.267839687 0.725493442 0.231216292
+0.268817204 0.724270974 0.232685872
+0.269794721 0.723055990 0.234144013
+0.270772239 0.721848423 0.235588818
+0.271749756 0.720648204 0.237021028
+0.272727273 0.719458438 0.238442032
+0.273704790 0.718286101 0.239849792
+0.274682307 0.717120499 0.241247924
+0.275659824 0.715961575 0.242632618
+0.276637341 0.714809270 0.244008759
+0.277614858 0.713665012 0.245371680
+0.278592375 0.712538184 0.246726670
+0.279569892 0.711417421 0.248069026
+0.280547410 0.710302674 0.249403669
+0.281524927 0.709193894 0.250726587
+0.282502444 0.708091063 0.252041647
+0.283479961 0.707005566 0.253346179
+0.284457478 0.705925531 0.254642389
+0.285434995 0.704850918 0.255929518
+0.286412512 0.703781686 0.257207578
+0.287390029 0.702717795 0.258478219
+0.288367546 0.701668621 0.259738800
+0.289345064 0.700625580 0.260993370
+0.290322581 0.699587425 0.262237549
+0.291300098 0.698554121 0.263475527
+0.292277615 0.697525635 0.264705239
+0.293255132 0.696509490 0.265927232
+0.294232649 0.695500037 0.267143201
+0.295210166 0.694494984 0.268349791
+0.296187683 0.693494303 0.269551115
+0.297165200 0.692497965 0.270744440
+0.298142717 0.691511860 0.271931138
+0.299120235 0.690532874 0.273112342
+0.300097752 0.689557847 0.274284946
+0.301075269 0.688586755 0.275452739
+0.302052786 0.687619575 0.276613621
+0.303030303 0.686660765 0.277768031
+0.304007820 0.685709376 0.278917856
+0.304985337 0.684761545 0.280059697
+0.305962854 0.683817249 0.281196818
+0.306940371 0.682876470 0.282328684
+0.307917889 0.681942420 0.283453563
+0.308895406 0.681015980 0.284574256
+0.309872923 0.680092726 0.285688972
+0.310850440 0.679172643 0.286798049
+0.311827957 0.678255714 0.287903138
+0.312805474 0.677344077 0.289001763
+0.313782991 0.676440126 0.290095833
+0.314760508 0.675539023 0.291186105
+0.315738025 0.674640752 0.292269631
+0.316715543 0.673745302 0.293349456
+0.317693060 0.672853893 0.294425247
+0.318670577 0.671970143 0.295495017
+0.319648094 0.671088924 0.296561328
+0.320625611 0.670210227 0.297623455
+0.321603128 0.669334041 0.298680243
+0.322580645 0.668460818 0.299733738
+0.323558162 0.667595126 0.300783030
+0.324535679 0.666731672 0.301827515
+0.325513196 0.665870450 0.302868868
+0.326490714 0.665011449 0.303906100
+0.327468231 0.664154662 0.304938935
+0.328445748 0.663304848 0.305968793
+0.329423265 0.662457164 0.306994695
+0.330400782 0.661611439 0.308016510
+0.331378299 0.660767667 0.309035496
+0.332355816 0.659925840 0.310050754
+0.333333333 0.659089669 0.311062154
+0.334310850 0.658255868 0.312070870
+0.335288368 0.657423770 0.313076130
+0.336265885 0.656593371 0.314077703
+0.337243402 0.655764665 0.315076729
+0.338220919 0.654940458 0.316071981
+0.339198436 0.654118746 0.317062640
+0.340175953 0.653298497 0.318050990
+0.341153470 0.652479705 0.319036167
+0.342130987 0.651662368 0.320016921
+0.343108504 0.650848521 0.320995595
+0.344086022 0.650037186 0.321971698
+0.345063539 0.649227083 0.322943523
+0.346041056 0.648418210 0.323913488
+0.347018573 0.647610563 0.324881463
+0.347996090 0.646805538 0.325845303
+0.348973607 0.646002934 0.326807497
+0.349951124 0.645201343 0.327768050
+0.350928641 0.644400763 0.328725018
+0.351906158 0.643601190 0.329680354
+0.352883675 0.642803505 0.330634256
+0.353861193 0.642008044 0.331585332
+0.354838710 0.641213384 0.332534700
+0.355816227 0.640419523 0.333482835
+0.356793744 0.639626459 0.334428830
+0.357771261 0.638834675 0.335373101
+0.358748778 0.638044814 0.336316337
+0.359726295 0.637255548 0.337258027
+0.360703812 0.636466876 0.338198057
+0.361681329 0.635678797 0.339137245
+0.362658847 0.634891512 0.340075384
+0.363636364 0.634105743 0.341012014
+0.364613881 0.633320368 0.341947992
+0.365591398 0.632535386 0.342883313
+0.366568915 0.631750798 0.343817374
+0.367546432 0.630966638 0.344750971
+0.368523949 0.630183479 0.345684104
+0.369501466 0.629400516 0.346616504
+0.370478983 0.628617749 0.347548540
+0.371456500 0.627835178 0.348480299
+0.372434018 0.627052803 0.349411745
+0.373411535 0.626270772 0.350343037
+0.374389052 0.625488759 0.351274237
+0.375366569 0.624706745 0.352205426
+0.376344086 0.623924731 0.353136787
+0.377321603 0.623142717 0.354068240
+0.378299120 0.622360434 0.354999866
+0.379276637 0.621577912 0.355932108
+0.380254154 0.620795194 0.356864629
+0.381231672 0.620012280 0.357797428
+0.382209189 0.619229171 0.358731329
+0.383186706 0.618445288 0.359665733
+0.384164223 0.617660798 0.360600602
+0.385141740 0.616875914 0.361536789
+0.386119257 0.616090638 0.362473899
+0.387096774 0.615304967 0.363411663
+0.388074291 0.614518130 0.364350853
+0.389051808 0.613730200 0.365291500
+0.390029326 0.612941676 0.366232990
+0.391006843 0.612152558 0.367175921
+0.391984360 0.611362846 0.368120944
+0.392961877 0.610571682 0.369067005
+0.393939394 0.609778818 0.370014435
+0.394916911 0.608985156 0.370964689
+0.395894428 0.608190696 0.371916178
+0.396871945 0.607395436 0.372868906
+0.397849462 0.606598545 0.373825246
+0.398826979 0.605799225 0.374783038
+0.399804497 0.604998896 0.375742272
+0.400782014 0.604197558 0.376705194
+0.401759531 0.603395208 0.377670184
+0.402737048 0.602591157 0.378636823
+0.403714565 0.601783817 0.379607193
+0.404692082 0.600975251 0.380580296
+0.405669599 0.600165455 0.381555265
+0.406647116 0.599354429 0.382533989
+0.407624633 0.598541740 0.383516150
+0.408602151 0.597724765 0.384500397
+0.409579668 0.596906338 0.385488433
+0.410557185 0.596086453 0.386480623
+0.411534702 0.595265107 0.387475131
+0.412512219 0.594442248 0.388473492
+0.413489736 0.593613964 0.389476718
+0.414467253 0.592783988 0.390482499
+0.415444770 0.591952316 0.391491555
+0.416422287 0.591118941 0.392504668
+0.417399804 0.590283858 0.393520477
+0.418377322 0.589442972 0.394539685
+0.419354839 0.588599687 0.395563270
+0.420332356 0.587754450 0.396589695
+0.421309873 0.586907257 0.397619709
+0.422287390 0.586058099 0.398654373
+0.423264907 0.585202955 0.399692025
+0.424242424 0.584344508 0.400733540
+0.425219941 0.583483842 0.401779909
+0.426197458 0.582620947 0.402829422
+0.427174976 0.581755815 0.403883177
+0.428152493 0.580884615 0.404941902
+0.429130010 0.580009054 0.406003935
+0.430107527 0.579130986 0.407070716
+0.431085044 0.578250399 0.408142475
+0.432062561 0.577367283 0.409217712
+0.433040078 0.576478121 0.410298357
+0.434017595 0.575583374 0.411383856
+0.434995112 0.574685810 0.412473008
+0.435972630 0.573785416 0.413568413
+0.436950147 0.572882178 0.414668387
+0.437927664 0.571973027 0.415772198
+0.438905181 0.571056884 0.416883317
+0.439882698 0.570137591 0.417998533
+0.440860215 0.569215132 0.419118581
+0.441837732 0.568289490 0.420245634
+0.442815249 0.567358177 0.421376894
+0.443792766 0.566418275 0.422514343
+0.444770283 0.565474860 0.423658069
+0.445747801 0.564527914 0.424806212
+0.446725318 0.563577417 0.425962211
+0.447702835 0.562621612 0.427123480
+0.448680352 0.561655405 0.428290282
+0.449657869 0.560685294 0.429465166
+0.450635386 0.559711253 0.430644890
+0.451612903 0.558733259 0.431832308
+0.452590420 0.557750445 0.433026364
+0.453567937 0.556755188 0.434226000
+0.454545455 0.555755595 0.435434924
+0.455522972 0.554751638 0.436649146
+0.456500489 0.553743287 0.437871753
+0.457478006 0.552730515 0.439101626
+0.458455523 0.551703450 0.440338101
+0.459433040 0.550671354 0.441584214
+0.460410557 0.549634415 0.442836126
+0.461388074 0.548592599 0.444098260
+0.462365591 0.547545872 0.445367270
+0.463343109 0.546484786 0.446645195
+0.464320626 0.545416893 0.447931951
+0.465298143 0.544343629 0.449226535
+0.466275660 0.543264953 0.450531713
+0.467253177 0.542180826 0.451843888
+0.468230694 0.541082374 0.453168194
+0.469208211 0.539975079 0.454499403
+0.470185728 0.538861828 0.455843131
+0.471163245 0.537742573 0.457194500
+0.472140762 0.536617267 0.458558366
+0.473118280 0.535477779 0.459930679
+0.474095797 0.534327120 0.461315854
+0.475073314 0.533169855 0.462709935
+0.476050831 0.532005928 0.464117671
+0.477028348 0.530835281 0.465534381
+0.478005865 0.529650711 0.466952620
+0.478983382 0.528452318 0.468377996
+0.479960899 0.527246594 0.469806093
+0.480938416 0.526033471 0.471239943
+0.481915934 0.524812880 0.472678374
+0.482893451 0.523578752 0.474120606
+0.483870968 0.522327784 0.475569070
+0.484848485 0.521068672 0.477020289
+0.485826002 0.519801335 0.478476759
+0.486803519 0.518525692 0.479938796
+0.487781036 0.517237031 0.481403707
+0.488758553 0.515928105 0.482873363
+0.489736070 0.514610118 0.484347894
+0.490713587 0.513282977 0.485826893
+0.491691105 0.511946585 0.487309221
+0.492668622 0.510597845 0.488795133
+0.493646139 0.509224947 0.490284775
+0.494623656 0.507841954 0.491777716
+0.495601173 0.506448755 0.493273513
+0.496578690 0.505045237 0.494770784
+0.497556207 0.503630203 0.496268873
+0.498533724 0.502186589 0.497766318
+0.499511241 0.500731707 0.499259366
+0.500488759 0.499268293 0.500740634
+0.501466276 0.497813411 0.502233682
+0.502443793 0.496369797 0.503731127
+0.503421310 0.494954763 0.505229216
+0.504398827 0.493551245 0.506726487
+0.505376344 0.492158046 0.508222284
+0.506353861 0.490775053 0.509715225
+0.507331378 0.489402155 0.511204867
+0.508308895 0.488053415 0.512690779
+0.509286413 0.486717023 0.514173107
+0.510263930 0.485389882 0.515652106
+0.511241447 0.484071895 0.517126637
+0.512218964 0.482762969 0.518596293
+0.513196481 0.481474308 0.520061204
+0.514173998 0.480198665 0.521523241
+0.515151515 0.478931328 0.522979711
+0.516129032 0.477672216 0.524430930
+0.517106549 0.476421248 0.525879394
+0.518084066 0.475187120 0.527321626
+0.519061584 0.473966529 0.528760057
+0.520039101 0.472753406 0.530193907
+0.521016618 0.471547682 0.531622004
+0.521994135 0.470349289 0.533047380
+0.522971652 0.469164719 0.534465619
+0.523949169 0.467994072 0.535882329
+0.524926686 0.466830145 0.537290065
+0.525904203 0.465672880 0.538684146
+0.526881720 0.464522221 0.540069321
+0.527859238 0.463382733 0.541441634
+0.528836755 0.462257427 0.542805500
+0.529814272 0.461138172 0.544156869
+0.530791789 0.460024921 0.545500597
+0.531769306 0.458917626 0.546831806
+0.532746823 0.457819174 0.548156112
+0.533724340 0.456735047 0.549468287
+0.534701857 0.455656371 0.550773465
+0.535679374 0.454583107 0.552068049
+0.536656891 0.453515214 0.553354805
+0.537634409 0.452454128 0.554632730
+0.538611926 0.451407401 0.555901740
+0.539589443 0.450365585 0.557163874
+0.540566960 0.449328646 0.558415786
+0.541544477 0.448296550 0.559661899
+0.542521994 0.447269485 0.560898374
+0.543499511 0.446256713 0.562128247
+0.544477028 0.445248362 0.563350854
+0.545454545 0.444244405 0.564565076
+0.546432063 0.443244812 0.565774000
+0.547409580 0.442249555 0.566973636
+0.548387097 0.441266741 0.568167692
+0.549364614 0.440288747 0.569355110
+0.550342131 0.439314706 0.570534834
+0.551319648 0.438344595 0.571709718
+0.552297165 0.437378388 0.572876520
+0.553274682 0.436422583 0.574037789
+0.554252199 0.435472086 0.575193788
+0.555229717 0.434525140 0.576341931
+0.556207234 0.433581725 0.577485657
+0.557184751 0.432641823 0.578623106
+0.558162268 0.431710510 0.579754366
+0.559139785 0.430784868 0.580881419
+0.560117302 0.429862409 0.582001467
+0.561094819 0.428943116 0.583116683
+0.562072336 0.428026973 0.584227802
+0.563049853 0.427117822 0.585331613
+0.564027370 0.426214584 0.586431587
+0.565004888 0.425314190 0.587526992
+0.565982405 0.424416626 0.588616144
+0.566959922 0.423521879 0.589701643
+0.567937439 0.422632717 0.590782288
+0.568914956 0.421749601 0.591857525
+0.569892473 0.420869014 0.592929284
+0.570869990 0.419990946 0.593996065
+0.571847507 0.419115385 0.595058098
+0.572825024 0.418244185 0.596116823
+0.573802542 0.417379053 0.597170578
+0.574780059 0.416516158 0.598220091
+0.575757576 0.415655492 0.599266460
+0.576735093 0.414797045 0.600307975
+0.577712610 0.413941901 0.601345627
+0.578690127 0.413092743 0.602380291
+0.579667644 0.412245550 0.603410305
+0.580645161 0.411400313 0.604436730
+0.581622678 0.410557028 0.605460315
+0.582600196 0.409716142 0.606479523
+0.583577713 0.408881059 0.607495332
+0.584555230 0.408047684 0.608508445
+0.585532747 0.407216012 0.609517501
+0.586510264 0.406386036 0.610523282
+0.587487781 0.405557752 0.611526508
+0.588465298 0.404734893 0.612524869
+0.589442815 0.403913547 0.613519377
+0.590420332 0.403093662 0.614511567
+0.591397849 0.402275235 0.615499603
+0.592375367 0.401458260 0.616483850
+0.593352884 0.400645571 0.617466011
+0.594330401 0.399834545 0.618444735
+0.595307918 0.399024749 0.619419704
+0.596285435 0.398216183 0.620392807
+0.597262952 0.397408843 0.621363177
+0.598240469 0.396604792 0.622329816
+0.599217986 0.395802442 0.623294806
+0.600195503 0.395001104 0.624257728
+0.601173021 0.394200775 0.625216962
+0.602150538 0.393401455 0.626174754
+0.603128055 0.392604564 0.627131094
+0.604105572 0.391809304 0.628083822
+0.605083089 0.391014844 0.629035311
+0.606060606 0.390221182 0.629985565
+0.607038123 0.389428318 0.630932995
+0.608015640 0.388637154 0.631879056
+0.608993157 0.387847442 0.632824079
+0.609970674 0.387058324 0.633767010
+0.610948192 0.386269800 0.634708500
+0.611925709 0.385481870 0.635649147
+0.612903226 0.384695033 0.636588337
+0.613880743 0.383909362 0.637526101
+0.614858260 0.383124086 0.638463211
+0.615835777 0.382339202 0.639399398
+0.616813294 0.381554712 0.640334267
+0.617790811 0.380770829 0.641268671
+0.618768328 0.379987720 0.642202572
+0.619745846 0.379204806 0.643135371
+0.620723363 0.378422088 0.644067892
+0.621700880 0.377639566 0.645000134
+0.622678397 0.376857283 0.645931760
+0.623655914 0.376075269 0.646863213
+0.624633431 0.375293255 0.647794574
+0.625610948 0.374511241 0.648725763
+0.626588465 0.373729228 0.649656963
+0.627565982 0.372947197 0.650588255
+0.628543500 0.372164822 0.651519701
+0.629521017 0.371382251 0.652451460
+0.630498534 0.370599484 0.653383496
+0.631476051 0.369816521 0.654315896
+0.632453568 0.369033362 0.655249029
+0.633431085 0.368249202 0.656182626
+0.634408602 0.367464614 0.657116687
+0.635386119 0.366679632 0.658052008
+0.636363636 0.365894257 0.658987986
+0.637341153 0.365108488 0.659924616
+0.638318671 0.364321203 0.660862755
+0.639296188 0.363533124 0.661801943
+0.640273705 0.362744452 0.662741973
+0.641251222 0.361955186 0.663683663
+0.642228739 0.361165325 0.664626899
+0.643206256 0.360373541 0.665571170
+0.644183773 0.359580477 0.666517165
+0.645161290 0.358786616 0.667465300
+0.646138807 0.357991956 0.668414668
+0.647116325 0.357196495 0.669365744
+0.648093842 0.356398810 0.670319646
+0.649071359 0.355599237 0.671274982
+0.650048876 0.354798657 0.672231950
+0.651026393 0.353997066 0.673192503
+0.652003910 0.353194462 0.674154697
+0.652981427 0.352389437 0.675118537
+0.653958944 0.351581790 0.676086512
+0.654936461 0.350772917 0.677056477
+0.655913978 0.349962814 0.678028302
+0.656891496 0.349151479 0.679004405
+0.657869013 0.348337632 0.679983079
+0.658846530 0.347520295 0.680963833
+0.659824047 0.346701503 0.681949010
+0.660801564 0.345881254 0.682937360
+0.661779081 0.345059542 0.683928019
+0.662756598 0.344235335 0.684923271
+0.663734115 0.343406629 0.685922297
+0.664711632 0.342576230 0.686923870
+0.665689150 0.341744132 0.687929130
+0.666666667 0.340910331 0.688937846
+0.667644184 0.340074160 0.689949246
+0.668621701 0.339232333 0.690964504
+0.669599218 0.338388561 0.691983490
+0.670576735 0.337542836 0.693005305
+0.671554252 0.336695152 0.694031207
+0.672531769 0.335845338 0.695061065
+0.673509286 0.334988551 0.696093900
+0.674486804 0.334129550 0.697131132
+0.675464321 0.333268328 0.698172485
+0.676441838 0.332404874 0.699216970
+0.677419355 0.331539182 0.700266262
+0.678396872 0.330665959 0.701319757
+0.679374389 0.329789773 0.702376545
+0.680351906 0.328911076 0.703438672
+0.681329423 0.328029857 0.704504983
+0.682306940 0.327146107 0.705574753
+0.683284457 0.326254698 0.706650544
+0.684261975 0.325359248 0.707730369
+0.685239492 0.324460977 0.708813895
+0.686217009 0.323559874 0.709904167
+0.687194526 0.322655923 0.710998237
+0.688172043 0.321744286 0.712096862
+0.689149560 0.320827357 0.713201951
+0.690127077 0.319907274 0.714311028
+0.691104594 0.318984020 0.715425744
+0.692082111 0.318057580 0.716546437
+0.693059629 0.317123530 0.717671316
+0.694037146 0.316182751 0.718803182
+0.695014663 0.315238455 0.719940303
+0.695992180 0.314290624 0.721082144
+0.696969697 0.313339235 0.722231969
+0.697947214 0.312380425 0.723386379
+0.698924731 0.311413245 0.724547261
+0.699902248 0.310442153 0.725715054
+0.700879765 0.309467126 0.726887658
+0.701857283 0.308488140 0.728068862
+0.702834800 0.307502035 0.729255560
+0.703812317 0.306505697 0.730448885
+0.704789834 0.305505016 0.731650209
+0.705767351 0.304499963 0.732856799
+0.706744868 0.303490510 0.734072768
+0.707722385 0.302474365 0.735294761
+0.708699902 0.301445879 0.736524473
+0.709677419 0.300412575 0.737762451
+0.710654936 0.299374420 0.739006630
+0.711632454 0.298331379 0.740261200
+0.712609971 0.297282205 0.741521781
+0.713587488 0.296218314 0.742792422
+0.714565005 0.295149082 0.744070482
+0.715542522 0.294074469 0.745357611
+0.716520039 0.292994434 0.746653821
+0.717497556 0.291908937 0.747958353
+0.718475073 0.290806106 0.749273413
+0.719452590 0.289697326 0.750596331
+0.720430108 0.288582579 0.751930974
+0.721407625 0.287461816 0.753273330
+0.722385142 0.286334988 0.754628320
+0.723362659 0.285190730 0.755991241
+0.724340176 0.284038425 0.757367382
+0.725317693 0.282879501 0.758752076
+0.726295210 0.281713899 0.760150208
+0.727272727 0.280541562 0.761557968
+0.728250244 0.279351796 0.762978972
+0.729227761 0.278151577 0.764411182
+0.730205279 0.276944010 0.765855987
+0.731182796 0.275729026 0.767314128
+0.732160313 0.274506558 0.768783708
+0.733137830 0.273266769 0.770269365
+0.734115347 0.272013773 0.771767273
+0.735092864 0.270752612 0.773279617
+0.736070381 0.269483206 0.774807849
+0.737047898 0.268205474 0.776350238
+0.738025415 0.266910644 0.777908241
+0.739002933 0.265599461 0.779484121
+0.739980450 0.264279195 0.781076333
+0.740957967 0.262949750 0.782685839
+0.741935484 0.261611030 0.784313657
+0.742913001 0.260255561 0.785960859
+0.743890518 0.258880149 0.787628578
+0.744868035 0.257494616 0.789318005
+0.745845552 0.256098848 0.791030397
+0.746823069 0.254692732 0.792767079
+0.747800587 0.253270349 0.794529580
+0.748778104 0.251823930 0.796323108
+0.749755621 0.250366211 0.798153793
+0.750733138 0.250000000 0.798619957
+0.751710655 0.250000000 0.798619478
+0.752688172 0.250000000 0.798618827
+0.753665689 0.250000000 0.798618046
+0.754643206 0.250000000 0.798617146
+0.755620723 0.250000000 0.798616146
+0.756598240 0.250000000 0.798615054
+0.757575758 0.250000000 0.798613875
+0.758553275 0.250000000 0.798612615
+0.759530792 0.250000000 0.798611281
+0.760508309 0.250000000 0.798609872
+0.761485826 0.250000000 0.798608379
+0.762463343 0.250000000 0.798606824
+0.763440860 0.250000000 0.798605212
+0.764418377 0.250000000 0.798603523
+0.765395894 0.250000000 0.798601768
+0.766373412 0.250000000 0.798599968
+0.767350929 0.250000000 0.798598087
+0.768328446 0.250000000 0.798596154
+0.769305963 0.250000000 0.798594172
+0.770283480 0.250000000 0.798592109
+0.771260997 0.250000000 0.798590018
+0.772238514 0.250000000 0.798587837
+0.773216031 0.250000000 0.798585625
+0.774193548 0.250000000 0.798583339
+0.775171065 0.250000000 0.798581012
+0.776148583 0.250000000 0.798578619
+0.777126100 0.250000000 0.798576179
+0.778103617 0.250000000 0.798573676
+0.779081134 0.250000000 0.798571128
+0.780058651 0.250000000 0.798568514
+0.781036168 0.250000000 0.798565861
+0.782013685 0.250000000 0.798563134
+0.782991202 0.250000000 0.798560379
+0.783968719 0.250000000 0.798557536
+0.784946237 0.250000000 0.798554682
+0.785923754 0.250000000 0.798551722
+0.786901271 0.250000000 0.798548749
+0.787878788 0.250000000 0.798545693
+0.788856305 0.250000000 0.798542598
+0.789833822 0.250000000 0.798539450
+0.790811339 0.250000000 0.798536231
+0.791788856 0.250000000 0.798532993
+0.792766373 0.250000000 0.798529646
+0.793743891 0.250000000 0.798526284
+0.794721408 0.250000000 0.798522845
+0.795698925 0.250000000 0.798519352
+0.796676442 0.250000000 0.798515828
+0.797653959 0.250000000 0.798512201
+0.798631476 0.250000000 0.798508555
+0.799608993 0.250000000 0.798504830
+0.800586510 0.250000000 0.798501045
+0.801564027 0.250000000 0.798497238
+0.802541544 0.250000000 0.798493312
+0.803519062 0.250000000 0.798489365
+0.804496579 0.250000000 0.798485354
+0.805474096 0.250000000 0.798481260
+0.806451613 0.250000000 0.798477144
+0.807429130 0.250000000 0.798472926
+0.808406647 0.250000000 0.798468658
+0.809384164 0.250000000 0.798464362
+0.810361681 0.250000000 0.798459937
+0.811339198 0.250000000 0.798455487
+0.812316716 0.250000000 0.798450981
+0.813294233 0.250000000 0.798446368
+0.814271750 0.250000000 0.798441728
+0.815249267 0.250000000 0.798437007
+0.816226784 0.250000000 0.798432199
+0.817204301 0.250000000 0.798427360
+0.818181818 0.250000000 0.798422419
+0.819159335 0.250000000 0.798417406
+0.820136852 0.250000000 0.798412362
+0.821114370 0.250000000 0.798407195
+0.822091887 0.250000000 0.798401968
+0.823069404 0.250000000 0.798396707
+0.824046921 0.250000000 0.798391309
+0.825024438 0.250000000 0.798385858
+0.826001955 0.250000000 0.798380370
+0.826979472 0.250000000 0.798374734
+0.827956989 0.250000000 0.798369049
+0.828934506 0.250000000 0.798363324
+0.829912023 0.250000000 0.798357442
+0.830889541 0.250000000 0.798351511
+0.831867058 0.250000000 0.798345537
+0.832844575 0.250000000 0.798339400
+0.833822092 0.250000000 0.798333211
+0.834799609 0.250000000 0.798326976
+0.835777126 0.250000000 0.798320576
+0.836754643 0.250000000 0.798314116
+0.837732160 0.250000000 0.798307606
+0.838709677 0.250000000 0.798300932
+0.839687195 0.250000000 0.798294187
+0.840664712 0.250000000 0.798287388
+0.841642229 0.250000000 0.798280430
+0.842619746 0.250000000 0.798273384
+0.843597263 0.250000000 0.798266281
+0.844574780 0.250000000 0.798259026
+0.845552297 0.250000000 0.798251664
+0.846529814 0.250000000 0.798244240
+0.847507331 0.250000000 0.798236674
+0.848484848 0.250000000 0.798228978
+0.849462366 0.250000000 0.798221215
+0.850439883 0.250000000 0.798213324
+0.851417400 0.250000000 0.798205276
+0.852394917 0.250000000 0.798197155
+0.853372434 0.250000000 0.798188922
+0.854349951 0.250000000 0.798180502
+0.855327468 0.250000000 0.798172002
+0.856304985 0.250000000 0.798163410
+0.857282502 0.250000000 0.798154594
+0.858260020 0.250000000 0.798145693
+0.859237537 0.250000000 0.798136706
+0.860215054 0.250000000 0.798127487
+0.861192571 0.250000000 0.798118161
+0.862170088 0.250000000 0.798108741
+0.863147605 0.250000000 0.798099109
+0.864125122 0.250000000 0.798089331
+0.865102639 0.250000000 0.798079451
+0.866080156 0.250000000 0.798069382
+0.867057674 0.250000000 0.798059123
+0.868035191 0.250000000 0.798048754
+0.869012708 0.250000000 0.798038221
+0.869990225 0.250000000 0.798027449
+0.870967742 0.250000000 0.798016558
+0.871945259 0.250000000 0.798005530
+0.872922776 0.250000000 0.797994212
+0.873900293 0.250000000 0.797982764
+0.874877810 0.250000000 0.797971185
+0.875855327 0.250000000 0.797959306
+0.876832845 0.250000000 0.797947263
+0.877810362 0.250000000 0.797935078
+0.878787879 0.250000000 0.797922616
+0.879765396 0.250000000 0.797909935
+0.880742913 0.250000000 0.797897099
+0.881720430 0.250000000 0.797884012
+0.882697947 0.250000000 0.797870648
+0.883675464 0.250000000 0.797857113
+0.884652981 0.250000000 0.797843354
+0.885630499 0.250000000 0.797829254
+0.886608016 0.250000000 0.797814969
+0.887585533 0.250000000 0.797800485
+0.888563050 0.250000000 0.797785594
+0.889540567 0.250000000 0.797770499
+0.890518084 0.250000000 0.797755197
+0.891495601 0.250000000 0.797739486
+0.892473118 0.250000000 0.797723518
+0.893450635 0.250000000 0.797707323
+0.894428152 0.250000000 0.797690733
+0.895405670 0.250000000 0.797673819
+0.896383187 0.250000000 0.797656655
+0.897360704 0.250000000 0.797639111
+0.898338221 0.250000000 0.797621171
+0.899315738 0.250000000 0.797602957
+0.900293255 0.250000000 0.797584371
+0.901270772 0.250000000 0.797565316
+0.902248289 0.250000000 0.797545958
+0.903225806 0.250000000 0.797526235
+0.904203324 0.250000000 0.797505964
+0.905180841 0.250000000 0.797485358
+0.906158358 0.250000000 0.797464387
+0.907135875 0.250000000 0.797442787
+0.908113392 0.250000000 0.797420816
+0.909090909 0.250000000 0.797398464
+0.910068426 0.250000000 0.797375416
+0.911045943 0.250000000 0.797351947
+0.912023460 0.250000000 0.797328054
+0.913000978 0.250000000 0.797303431
+0.913978495 0.250000000 0.797278312
+0.914956012 0.250000000 0.797252722
+0.915933529 0.250000000 0.797226352
+0.916911046 0.250000000 0.797199412
+0.917888563 0.250000000 0.797171944
+0.918866080 0.250000000 0.797143632
+0.919843597 0.250000000 0.797114674
+0.920821114 0.250000000 0.797085122
+0.921798631 0.250000000 0.797054641
+0.922776149 0.250000000 0.797023436
+0.923753666 0.250000000 0.796991562
+0.924731183 0.250000000 0.796958649
+0.925708700 0.250000000 0.796924934
+0.926686217 0.250000000 0.796890462
+0.927663734 0.250000000 0.796854809
+0.928641251 0.250000000 0.796818277
+0.929618768 0.250000000 0.796780885
+0.930596285 0.250000000 0.796742131
+0.931573803 0.250000000 0.796702422
+0.932551320 0.250000000 0.796661678
+0.933528837 0.250000000 0.796619449
+0.934506354 0.250000000 0.796576138
+0.935483871 0.250000000 0.796531554
+0.936461388 0.250000000 0.796485383
+0.937438905 0.250000000 0.796437966
+0.938416422 0.250000000 0.796388970
+0.939393939 0.250000000 0.796338286
+0.940371457 0.250000000 0.796286158
+0.941348974 0.250000000 0.796232059
+0.942326491 0.250000000 0.796176174
+0.943304008 0.250000000 0.796118602
+0.944281525 0.250000000 0.796058564
+0.945259042 0.250000000 0.795996641
+0.946236559 0.250000000 0.795932487
+0.947214076 0.250000000 0.795865725
+0.948191593 0.250000000 0.795796735
+0.949169110 0.250000000 0.795724810
+0.950146628 0.250000000 0.795650131
+0.951124145 0.250000000 0.795572676
+0.952101662 0.250000000 0.795491611
+0.953079179 0.250000000 0.795407522
+0.954056696 0.250000000 0.795319628
+0.955034213 0.250000000 0.795227898
+0.956011730 0.250000000 0.795132357
+0.956989247 0.250000000 0.795031935
+0.957966764 0.250000000 0.794927282
+0.958944282 0.250000000 0.794817257
+0.959921799 0.250000000 0.794701981
+0.960899316 0.250000000 0.794581006
+0.961876833 0.250000000 0.794453449
+0.962854350 0.250000000 0.794319707
+0.963831867 0.250000000 0.794177846
+0.964809384 0.250000000 0.794028718
+0.965786901 0.250000000 0.793870437
+0.966764418 0.250000000 0.793703113
+0.967741935 0.250000000 0.793525315
+0.968719453 0.250000000 0.793336305
+0.969696970 0.250000000 0.793135013
+0.970674487 0.250000000 0.792919868
+0.971652004 0.250000000 0.792689957
+0.972629521 0.250000000 0.792442910
+0.973607038 0.250000000 0.792177663
+0.974584555 0.250000000 0.791891104
+0.975562072 0.250000000 0.791581540
+0.976539589 0.250000000 0.791245216
+0.977517107 0.250000000 0.790900290
+0.978494624 0.250000000 0.790546727
+0.979472141 0.250000000 0.790189953
+0.980449658 0.250000000 0.789814417
+0.981427175 0.250000000 0.789445023
+0.982404692 0.250000000 0.789052209
+0.983382209 0.250000000 0.788657501
+0.984359726 0.250000000 0.788250203
+0.985337243 0.250000000 0.787818500
+0.986314761 0.250000000 0.787390503
+0.987292278 0.250000000 0.786940347
+0.988269795 0.250000000 0.786464072
+0.989247312 0.250000000 0.785974808
+0.990224829 0.250000000 0.785469812
+0.991202346 0.250000000 0.784933879
+0.992179863 0.250000000 0.784364501
+0.993157380 0.250000000 0.783757951
+0.994134897 0.250000000 0.783108264
+0.995112414 0.250000000 0.782404962
+0.996089932 0.250000000 0.781627407
+0.997067449 0.250000000 0.780727892
+0.998044966 0.250000000 0.779693393
+0.999022483 0.250000000 0.778328498
+1.000000000 nan nan
diff --git a/examples/mamdani/SimpleDimmerChained.fll b/examples/mamdani/SimpleDimmerChained.fll
new file mode 100644
index 0000000..02b35cc
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.fll
@@ -0,0 +1,42 @@
+Engine: SimpleDimmerChained
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+OutputVariable: InversePower
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 500
+ default: nan
+ lock-previous: false
+ term: LOW Cosine 0.200 0.500
+ term: MEDIUM Cosine 0.500 0.500
+ term: HIGH Cosine 0.800 0.500
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
+ rule: if Power is LOW then InversePower is HIGH
+ rule: if Power is MEDIUM then InversePower is MEDIUM
+ rule: if Power is HIGH then InversePower is LOW \ No newline at end of file
diff --git a/examples/mamdani/SimpleDimmerChained.java b/examples/mamdani/SimpleDimmerChained.java
new file mode 100644
index 0000000..a7c28c6
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.java
@@ -0,0 +1,81 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class SimpleDimmerChained{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("SimpleDimmerChained");
+engine.setDescription("");
+
+InputVariable Ambient = new InputVariable();
+Ambient.setName("Ambient");
+Ambient.setDescription("");
+Ambient.setEnabled(true);
+Ambient.setRange(0.000, 1.000);
+Ambient.setLockValueInRange(false);
+Ambient.addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient.addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine.addInputVariable(Ambient);
+
+OutputVariable Power = new OutputVariable();
+Power.setName("Power");
+Power.setDescription("");
+Power.setEnabled(true);
+Power.setRange(0.000, 1.000);
+Power.setLockValueInRange(false);
+Power.setAggregation(new Maximum());
+Power.setDefuzzifier(new Centroid(200));
+Power.setDefaultValue(Double.NaN);
+Power.setLockPreviousValue(false);
+Power.addTerm(new Triangle("LOW", 0.000, 0.250, 0.500));
+Power.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Power.addTerm(new Triangle("HIGH", 0.500, 0.750, 1.000));
+engine.addOutputVariable(Power);
+
+OutputVariable InversePower = new OutputVariable();
+InversePower.setName("InversePower");
+InversePower.setDescription("");
+InversePower.setEnabled(true);
+InversePower.setRange(0.000, 1.000);
+InversePower.setLockValueInRange(false);
+InversePower.setAggregation(new Maximum());
+InversePower.setDefuzzifier(new Centroid(500));
+InversePower.setDefaultValue(Double.NaN);
+InversePower.setLockPreviousValue(false);
+InversePower.addTerm(new Cosine("LOW", 0.200, 0.500));
+InversePower.addTerm(new Cosine("MEDIUM", 0.500, 0.500));
+InversePower.addTerm(new Cosine("HIGH", 0.800, 0.500));
+engine.addOutputVariable(InversePower);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(new Minimum());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is BRIGHT then Power is LOW", engine));
+ruleBlock.addRule(Rule.parse("if Power is LOW then InversePower is HIGH", engine));
+ruleBlock.addRule(Rule.parse("if Power is MEDIUM then InversePower is MEDIUM", engine));
+ruleBlock.addRule(Rule.parse("if Power is HIGH then InversePower is LOW", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/SimpleDimmerChained.pdf b/examples/mamdani/SimpleDimmerChained.pdf
new file mode 100644
index 0000000..bc22cfa
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerChained.pdf
Binary files differ
diff --git a/examples/mamdani/SimpleDimmerInverse.R b/examples/mamdani/SimpleDimmerInverse.R
new file mode 100644
index 0000000..358916d
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.R
@@ -0,0 +1,85 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "SimpleDimmerInverse"
+engine.fll = "Engine: SimpleDimmerInverse
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+OutputVariable: InversePower
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 500
+ default: nan
+ lock-previous: false
+ term: LOW Cosine 0.200 0.500
+ term: MEDIUM Cosine 0.500 0.500
+ term: HIGH Cosine 0.800 0.500
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
+ rule: if Power is LOW then InversePower is HIGH
+ rule: if Power is MEDIUM then InversePower is MEDIUM
+ rule: if Power is HIGH then InversePower is LOW"
+
+engine.fldFile = "SimpleDimmerInverse.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("Ambient vs Power")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Power vs Ambient")
+
+engine.plot.i1_o2 = ggplot(engine.df, aes(Ambient, InversePower)) +
+ geom_line(aes(color=InversePower), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("Ambient vs InversePower")
+
+engine.plot.o2_i1 = ggplot(engine.df, aes(Ambient, InversePower)) +
+ geom_line(aes(color=InversePower), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("InversePower vs Ambient")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, engine.plot.i1_o2, engine.plot.o2_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/SimpleDimmerInverse.cpp b/examples/mamdani/SimpleDimmerInverse.cpp
new file mode 100644
index 0000000..1c22275
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.cpp
@@ -0,0 +1,70 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("SimpleDimmerInverse");
+engine->setDescription("");
+
+InputVariable* Ambient = new InputVariable;
+Ambient->setName("Ambient");
+Ambient->setDescription("");
+Ambient->setEnabled(true);
+Ambient->setRange(0.000, 1.000);
+Ambient->setLockValueInRange(false);
+Ambient->addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient->addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine->addInputVariable(Ambient);
+
+OutputVariable* Power = new OutputVariable;
+Power->setName("Power");
+Power->setDescription("");
+Power->setEnabled(true);
+Power->setRange(0.000, 1.000);
+Power->setLockValueInRange(false);
+Power->setAggregation(new Maximum);
+Power->setDefuzzifier(new Centroid(200));
+Power->setDefaultValue(fl::nan);
+Power->setLockPreviousValue(false);
+Power->addTerm(new Triangle("LOW", 0.000, 0.250, 0.500));
+Power->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Power->addTerm(new Triangle("HIGH", 0.500, 0.750, 1.000));
+engine->addOutputVariable(Power);
+
+OutputVariable* InversePower = new OutputVariable;
+InversePower->setName("InversePower");
+InversePower->setDescription("");
+InversePower->setEnabled(true);
+InversePower->setRange(0.000, 1.000);
+InversePower->setLockValueInRange(false);
+InversePower->setAggregation(new Maximum);
+InversePower->setDefuzzifier(new Centroid(500));
+InversePower->setDefaultValue(fl::nan);
+InversePower->setLockPreviousValue(false);
+InversePower->addTerm(new Cosine("LOW", 0.200, 0.500));
+InversePower->addTerm(new Cosine("MEDIUM", 0.500, 0.500));
+InversePower->addTerm(new Cosine("HIGH", 0.800, 0.500));
+engine->addOutputVariable(InversePower);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(new Minimum);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is BRIGHT then Power is LOW", engine));
+ruleBlock->addRule(Rule::parse("if Power is LOW then InversePower is HIGH", engine));
+ruleBlock->addRule(Rule::parse("if Power is MEDIUM then InversePower is MEDIUM", engine));
+ruleBlock->addRule(Rule::parse("if Power is HIGH then InversePower is LOW", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/SimpleDimmerInverse.fcl b/examples/mamdani/SimpleDimmerInverse.fcl
new file mode 100644
index 0000000..d8043d3
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.fcl
@@ -0,0 +1,51 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK SimpleDimmerInverse
+
+VAR_INPUT
+ Ambient: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Power: REAL;
+ InversePower: REAL;
+END_VAR
+
+FUZZIFY Ambient
+ RANGE := (0.000 .. 1.000);
+ TERM DARK := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM BRIGHT := Triangle 0.500 0.750 1.000;
+END_FUZZIFY
+
+DEFUZZIFY Power
+ RANGE := (0.000 .. 1.000);
+ TERM LOW := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM HIGH := Triangle 0.500 0.750 1.000;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY InversePower
+ RANGE := (0.000 .. 1.000);
+ TERM LOW := Cosine 0.200 0.500;
+ TERM MEDIUM := Cosine 0.500 0.500;
+ TERM HIGH := Cosine 0.800 0.500;
+ METHOD : COG;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ ACT : MIN;
+ RULE 1 : if Ambient is DARK then Power is HIGH
+ RULE 2 : if Ambient is MEDIUM then Power is MEDIUM
+ RULE 3 : if Ambient is BRIGHT then Power is LOW
+ RULE 4 : if Power is LOW then InversePower is HIGH
+ RULE 5 : if Power is MEDIUM then InversePower is MEDIUM
+ RULE 6 : if Power is HIGH then InversePower is LOW
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/SimpleDimmerInverse.fis b/examples/mamdani/SimpleDimmerInverse.fis
new file mode 100644
index 0000000..b044014
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.fis
@@ -0,0 +1,46 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='SimpleDimmerInverse'
+Type='mamdani'
+Version=6.0
+NumInputs=1
+NumOutputs=2
+NumRules=6
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Ambient'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='DARK':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='BRIGHT':'trimf',[0.500 0.750 1.000]
+
+[Output1]
+Name='Power'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='LOW':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='HIGH':'trimf',[0.500 0.750 1.000]
+
+[Output2]
+Name='InversePower'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='LOW':'cosinemf',[0.200 0.500]
+MF2='MEDIUM':'cosinemf',[0.500 0.500]
+MF3='HIGH':'cosinemf',[0.800 0.500]
+
+[Rules]
+1.000 , 3.000 0.000 (1.000) : 1
+2.000 , 2.000 0.000 (1.000) : 1
+3.000 , 1.000 0.000 (1.000) : 1
+0.000 , 0.000 3.000 (1.000) : 1
+0.000 , 0.000 2.000 (1.000) : 1
+0.000 , 0.000 1.000 (1.000) : 1
diff --git a/examples/mamdani/SimpleDimmerInverse.fld b/examples/mamdani/SimpleDimmerInverse.fld
new file mode 100644
index 0000000..843c017
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.fld
@@ -0,0 +1,1025 @@
+Ambient Power InversePower
+0.000000000 nan nan
+0.000977517 0.750000000 0.221671502
+0.001955034 0.750000000 0.220306607
+0.002932551 0.750000000 0.219272108
+0.003910068 0.750000000 0.218372593
+0.004887586 0.750000000 0.217595038
+0.005865103 0.750000000 0.216891736
+0.006842620 0.750000000 0.216242049
+0.007820137 0.750000000 0.215635499
+0.008797654 0.750000000 0.215066121
+0.009775171 0.750000000 0.214530188
+0.010752688 0.750000000 0.214025192
+0.011730205 0.750000000 0.213535928
+0.012707722 0.750000000 0.213059653
+0.013685239 0.750000000 0.212609497
+0.014662757 0.750000000 0.212181500
+0.015640274 0.750000000 0.211749797
+0.016617791 0.750000000 0.211342499
+0.017595308 0.750000000 0.210947791
+0.018572825 0.750000000 0.210554977
+0.019550342 0.750000000 0.210185583
+0.020527859 0.750000000 0.209810047
+0.021505376 0.750000000 0.209453273
+0.022482893 0.750000000 0.209099710
+0.023460411 0.750000000 0.208754784
+0.024437928 0.750000000 0.208418460
+0.025415445 0.750000000 0.208108896
+0.026392962 0.750000000 0.207822337
+0.027370479 0.750000000 0.207557090
+0.028347996 0.750000000 0.207310043
+0.029325513 0.750000000 0.207080132
+0.030303030 0.750000000 0.206864987
+0.031280547 0.750000000 0.206663695
+0.032258065 0.750000000 0.206474685
+0.033235582 0.750000000 0.206296887
+0.034213099 0.750000000 0.206129563
+0.035190616 0.750000000 0.205971282
+0.036168133 0.750000000 0.205822154
+0.037145650 0.750000000 0.205680293
+0.038123167 0.750000000 0.205546551
+0.039100684 0.750000000 0.205418994
+0.040078201 0.750000000 0.205298019
+0.041055718 0.750000000 0.205182743
+0.042033236 0.750000000 0.205072718
+0.043010753 0.750000000 0.204968065
+0.043988270 0.750000000 0.204867643
+0.044965787 0.750000000 0.204772102
+0.045943304 0.750000000 0.204680372
+0.046920821 0.750000000 0.204592478
+0.047898338 0.750000000 0.204508389
+0.048875855 0.750000000 0.204427324
+0.049853372 0.750000000 0.204349869
+0.050830890 0.750000000 0.204275190
+0.051808407 0.750000000 0.204203265
+0.052785924 0.750000000 0.204134275
+0.053763441 0.750000000 0.204067513
+0.054740958 0.750000000 0.204003359
+0.055718475 0.750000000 0.203941436
+0.056695992 0.750000000 0.203881398
+0.057673509 0.750000000 0.203823826
+0.058651026 0.750000000 0.203767941
+0.059628543 0.750000000 0.203713842
+0.060606061 0.750000000 0.203661714
+0.061583578 0.750000000 0.203611030
+0.062561095 0.750000000 0.203562034
+0.063538612 0.750000000 0.203514617
+0.064516129 0.750000000 0.203468446
+0.065493646 0.750000000 0.203423862
+0.066471163 0.750000000 0.203380551
+0.067448680 0.750000000 0.203338322
+0.068426197 0.750000000 0.203297578
+0.069403715 0.750000000 0.203257869
+0.070381232 0.750000000 0.203219115
+0.071358749 0.750000000 0.203181723
+0.072336266 0.750000000 0.203145191
+0.073313783 0.750000000 0.203109538
+0.074291300 0.750000000 0.203075066
+0.075268817 0.750000000 0.203041351
+0.076246334 0.750000000 0.203008438
+0.077223851 0.750000000 0.202976564
+0.078201369 0.750000000 0.202945359
+0.079178886 0.750000000 0.202914878
+0.080156403 0.750000000 0.202885326
+0.081133920 0.750000000 0.202856368
+0.082111437 0.750000000 0.202828056
+0.083088954 0.750000000 0.202800588
+0.084066471 0.750000000 0.202773648
+0.085043988 0.750000000 0.202747278
+0.086021505 0.750000000 0.202721688
+0.086999022 0.750000000 0.202696569
+0.087976540 0.750000000 0.202671946
+0.088954057 0.750000000 0.202648053
+0.089931574 0.750000000 0.202624584
+0.090909091 0.750000000 0.202601536
+0.091886608 0.750000000 0.202579184
+0.092864125 0.750000000 0.202557213
+0.093841642 0.750000000 0.202535613
+0.094819159 0.750000000 0.202514642
+0.095796676 0.750000000 0.202494036
+0.096774194 0.750000000 0.202473765
+0.097751711 0.750000000 0.202454042
+0.098729228 0.750000000 0.202434684
+0.099706745 0.750000000 0.202415629
+0.100684262 0.750000000 0.202397043
+0.101661779 0.750000000 0.202378829
+0.102639296 0.750000000 0.202360889
+0.103616813 0.750000000 0.202343345
+0.104594330 0.750000000 0.202326181
+0.105571848 0.750000000 0.202309267
+0.106549365 0.750000000 0.202292677
+0.107526882 0.750000000 0.202276482
+0.108504399 0.750000000 0.202260514
+0.109481916 0.750000000 0.202244803
+0.110459433 0.750000000 0.202229501
+0.111436950 0.750000000 0.202214406
+0.112414467 0.750000000 0.202199515
+0.113391984 0.750000000 0.202185031
+0.114369501 0.750000000 0.202170746
+0.115347019 0.750000000 0.202156646
+0.116324536 0.750000000 0.202142887
+0.117302053 0.750000000 0.202129352
+0.118279570 0.750000000 0.202115988
+0.119257087 0.750000000 0.202102901
+0.120234604 0.750000000 0.202090065
+0.121212121 0.750000000 0.202077384
+0.122189638 0.750000000 0.202064922
+0.123167155 0.750000000 0.202052737
+0.124144673 0.750000000 0.202040694
+0.125122190 0.750000000 0.202028815
+0.126099707 0.750000000 0.202017236
+0.127077224 0.750000000 0.202005788
+0.128054741 0.750000000 0.201994470
+0.129032258 0.750000000 0.201983442
+0.130009775 0.750000000 0.201972551
+0.130987292 0.750000000 0.201961779
+0.131964809 0.750000000 0.201951246
+0.132942326 0.750000000 0.201940877
+0.133919844 0.750000000 0.201930618
+0.134897361 0.750000000 0.201920549
+0.135874878 0.750000000 0.201910669
+0.136852395 0.750000000 0.201900891
+0.137829912 0.750000000 0.201891259
+0.138807429 0.750000000 0.201881839
+0.139784946 0.750000000 0.201872513
+0.140762463 0.750000000 0.201863294
+0.141739980 0.750000000 0.201854307
+0.142717498 0.750000000 0.201845406
+0.143695015 0.750000000 0.201836590
+0.144672532 0.750000000 0.201827998
+0.145650049 0.750000000 0.201819498
+0.146627566 0.750000000 0.201811078
+0.147605083 0.750000000 0.201802845
+0.148582600 0.750000000 0.201794724
+0.149560117 0.750000000 0.201786676
+0.150537634 0.750000000 0.201778785
+0.151515152 0.750000000 0.201771022
+0.152492669 0.750000000 0.201763326
+0.153470186 0.750000000 0.201755760
+0.154447703 0.750000000 0.201748336
+0.155425220 0.750000000 0.201740974
+0.156402737 0.750000000 0.201733719
+0.157380254 0.750000000 0.201726616
+0.158357771 0.750000000 0.201719570
+0.159335288 0.750000000 0.201712612
+0.160312805 0.750000000 0.201705813
+0.161290323 0.750000000 0.201699068
+0.162267840 0.750000000 0.201692394
+0.163245357 0.750000000 0.201685884
+0.164222874 0.750000000 0.201679424
+0.165200391 0.750000000 0.201673024
+0.166177908 0.750000000 0.201666789
+0.167155425 0.750000000 0.201660600
+0.168132942 0.750000000 0.201654463
+0.169110459 0.750000000 0.201648489
+0.170087977 0.750000000 0.201642558
+0.171065494 0.750000000 0.201636676
+0.172043011 0.750000000 0.201630951
+0.173020528 0.750000000 0.201625266
+0.173998045 0.750000000 0.201619630
+0.174975562 0.750000000 0.201614142
+0.175953079 0.750000000 0.201608691
+0.176930596 0.750000000 0.201603293
+0.177908113 0.750000000 0.201598032
+0.178885630 0.750000000 0.201592805
+0.179863148 0.750000000 0.201587638
+0.180840665 0.750000000 0.201582594
+0.181818182 0.750000000 0.201577581
+0.182795699 0.750000000 0.201572640
+0.183773216 0.750000000 0.201567801
+0.184750733 0.750000000 0.201562993
+0.185728250 0.750000000 0.201558272
+0.186705767 0.750000000 0.201553632
+0.187683284 0.750000000 0.201549019
+0.188660802 0.750000000 0.201544513
+0.189638319 0.750000000 0.201540063
+0.190615836 0.750000000 0.201535638
+0.191593353 0.750000000 0.201531342
+0.192570870 0.750000000 0.201527074
+0.193548387 0.750000000 0.201522856
+0.194525904 0.750000000 0.201518740
+0.195503421 0.750000000 0.201514646
+0.196480938 0.750000000 0.201510635
+0.197458456 0.750000000 0.201506688
+0.198435973 0.750000000 0.201502762
+0.199413490 0.750000000 0.201498955
+0.200391007 0.750000000 0.201495170
+0.201368524 0.750000000 0.201491445
+0.202346041 0.750000000 0.201487799
+0.203323558 0.750000000 0.201484172
+0.204301075 0.750000000 0.201480648
+0.205278592 0.750000000 0.201477155
+0.206256109 0.750000000 0.201473716
+0.207233627 0.750000000 0.201470354
+0.208211144 0.750000000 0.201467007
+0.209188661 0.750000000 0.201463769
+0.210166178 0.750000000 0.201460550
+0.211143695 0.750000000 0.201457402
+0.212121212 0.750000000 0.201454307
+0.213098729 0.750000000 0.201451251
+0.214076246 0.750000000 0.201448278
+0.215053763 0.750000000 0.201445318
+0.216031281 0.750000000 0.201442464
+0.217008798 0.750000000 0.201439621
+0.217986315 0.750000000 0.201436866
+0.218963832 0.750000000 0.201434139
+0.219941349 0.750000000 0.201431486
+0.220918866 0.750000000 0.201428872
+0.221896383 0.750000000 0.201426324
+0.222873900 0.750000000 0.201423821
+0.223851417 0.750000000 0.201421381
+0.224828935 0.750000000 0.201418988
+0.225806452 0.750000000 0.201416661
+0.226783969 0.750000000 0.201414375
+0.227761486 0.750000000 0.201412163
+0.228739003 0.750000000 0.201409982
+0.229716520 0.750000000 0.201407891
+0.230694037 0.750000000 0.201405828
+0.231671554 0.750000000 0.201403846
+0.232649071 0.750000000 0.201401913
+0.233626588 0.750000000 0.201400032
+0.234604106 0.750000000 0.201398232
+0.235581623 0.750000000 0.201396477
+0.236559140 0.750000000 0.201394788
+0.237536657 0.750000000 0.201393176
+0.238514174 0.750000000 0.201391621
+0.239491691 0.750000000 0.201390128
+0.240469208 0.750000000 0.201388719
+0.241446725 0.750000000 0.201387385
+0.242424242 0.750000000 0.201386125
+0.243401760 0.750000000 0.201384946
+0.244379277 0.750000000 0.201383854
+0.245356794 0.750000000 0.201382854
+0.246334311 0.750000000 0.201381954
+0.247311828 0.750000000 0.201381173
+0.248289345 0.750000000 0.201380522
+0.249266862 0.750000000 0.201380043
+0.250244379 0.749633789 0.201846207
+0.251221896 0.748176070 0.203676892
+0.252199413 0.746729651 0.205470420
+0.253176931 0.745307268 0.207232921
+0.254154448 0.743901152 0.208969603
+0.255131965 0.742505384 0.210681995
+0.256109482 0.741119851 0.212371422
+0.257086999 0.739744439 0.214039141
+0.258064516 0.738388970 0.215686343
+0.259042033 0.737050250 0.217314161
+0.260019550 0.735720805 0.218923667
+0.260997067 0.734400539 0.220515879
+0.261974585 0.733089356 0.222091759
+0.262952102 0.731794526 0.223649762
+0.263929619 0.730516794 0.225192151
+0.264907136 0.729247388 0.226720383
+0.265884653 0.727986227 0.228232727
+0.266862170 0.726733231 0.229730635
+0.267839687 0.725493442 0.231216292
+0.268817204 0.724270974 0.232685872
+0.269794721 0.723055990 0.234144013
+0.270772239 0.721848423 0.235588818
+0.271749756 0.720648204 0.237021028
+0.272727273 0.719458438 0.238442032
+0.273704790 0.718286101 0.239849792
+0.274682307 0.717120499 0.241247924
+0.275659824 0.715961575 0.242632618
+0.276637341 0.714809270 0.244008759
+0.277614858 0.713665012 0.245371680
+0.278592375 0.712538184 0.246726670
+0.279569892 0.711417421 0.248069026
+0.280547410 0.710302674 0.249403669
+0.281524927 0.709193894 0.250726587
+0.282502444 0.708091063 0.252041647
+0.283479961 0.707005566 0.253346179
+0.284457478 0.705925531 0.254642389
+0.285434995 0.704850918 0.255929518
+0.286412512 0.703781686 0.257207578
+0.287390029 0.702717795 0.258478219
+0.288367546 0.701668621 0.259738800
+0.289345064 0.700625580 0.260993370
+0.290322581 0.699587425 0.262237549
+0.291300098 0.698554121 0.263475527
+0.292277615 0.697525635 0.264705239
+0.293255132 0.696509490 0.265927232
+0.294232649 0.695500037 0.267143201
+0.295210166 0.694494984 0.268349791
+0.296187683 0.693494303 0.269551115
+0.297165200 0.692497965 0.270744440
+0.298142717 0.691511860 0.271931138
+0.299120235 0.690532874 0.273112342
+0.300097752 0.689557847 0.274284946
+0.301075269 0.688586755 0.275452739
+0.302052786 0.687619575 0.276613621
+0.303030303 0.686660765 0.277768031
+0.304007820 0.685709376 0.278917856
+0.304985337 0.684761545 0.280059697
+0.305962854 0.683817249 0.281196818
+0.306940371 0.682876470 0.282328684
+0.307917889 0.681942420 0.283453563
+0.308895406 0.681015980 0.284574256
+0.309872923 0.680092726 0.285688972
+0.310850440 0.679172643 0.286798049
+0.311827957 0.678255714 0.287903138
+0.312805474 0.677344077 0.289001763
+0.313782991 0.676440126 0.290095833
+0.314760508 0.675539023 0.291186105
+0.315738025 0.674640752 0.292269631
+0.316715543 0.673745302 0.293349456
+0.317693060 0.672853893 0.294425247
+0.318670577 0.671970143 0.295495017
+0.319648094 0.671088924 0.296561328
+0.320625611 0.670210227 0.297623455
+0.321603128 0.669334041 0.298680243
+0.322580645 0.668460818 0.299733738
+0.323558162 0.667595126 0.300783030
+0.324535679 0.666731672 0.301827515
+0.325513196 0.665870450 0.302868868
+0.326490714 0.665011449 0.303906100
+0.327468231 0.664154662 0.304938935
+0.328445748 0.663304848 0.305968793
+0.329423265 0.662457164 0.306994695
+0.330400782 0.661611439 0.308016510
+0.331378299 0.660767667 0.309035496
+0.332355816 0.659925840 0.310050754
+0.333333333 0.659089669 0.311062154
+0.334310850 0.658255868 0.312070870
+0.335288368 0.657423770 0.313076130
+0.336265885 0.656593371 0.314077703
+0.337243402 0.655764665 0.315076729
+0.338220919 0.654940458 0.316071981
+0.339198436 0.654118746 0.317062640
+0.340175953 0.653298497 0.318050990
+0.341153470 0.652479705 0.319036167
+0.342130987 0.651662368 0.320016921
+0.343108504 0.650848521 0.320995595
+0.344086022 0.650037186 0.321971698
+0.345063539 0.649227083 0.322943523
+0.346041056 0.648418210 0.323913488
+0.347018573 0.647610563 0.324881463
+0.347996090 0.646805538 0.325845303
+0.348973607 0.646002934 0.326807497
+0.349951124 0.645201343 0.327768050
+0.350928641 0.644400763 0.328725018
+0.351906158 0.643601190 0.329680354
+0.352883675 0.642803505 0.330634256
+0.353861193 0.642008044 0.331585332
+0.354838710 0.641213384 0.332534700
+0.355816227 0.640419523 0.333482835
+0.356793744 0.639626459 0.334428830
+0.357771261 0.638834675 0.335373101
+0.358748778 0.638044814 0.336316337
+0.359726295 0.637255548 0.337258027
+0.360703812 0.636466876 0.338198057
+0.361681329 0.635678797 0.339137245
+0.362658847 0.634891512 0.340075384
+0.363636364 0.634105743 0.341012014
+0.364613881 0.633320368 0.341947992
+0.365591398 0.632535386 0.342883313
+0.366568915 0.631750798 0.343817374
+0.367546432 0.630966638 0.344750971
+0.368523949 0.630183479 0.345684104
+0.369501466 0.629400516 0.346616504
+0.370478983 0.628617749 0.347548540
+0.371456500 0.627835178 0.348480299
+0.372434018 0.627052803 0.349411745
+0.373411535 0.626270772 0.350343037
+0.374389052 0.625488759 0.351274237
+0.375366569 0.624706745 0.352205426
+0.376344086 0.623924731 0.353136787
+0.377321603 0.623142717 0.354068240
+0.378299120 0.622360434 0.354999866
+0.379276637 0.621577912 0.355932108
+0.380254154 0.620795194 0.356864629
+0.381231672 0.620012280 0.357797428
+0.382209189 0.619229171 0.358731329
+0.383186706 0.618445288 0.359665733
+0.384164223 0.617660798 0.360600602
+0.385141740 0.616875914 0.361536789
+0.386119257 0.616090638 0.362473899
+0.387096774 0.615304967 0.363411663
+0.388074291 0.614518130 0.364350853
+0.389051808 0.613730200 0.365291500
+0.390029326 0.612941676 0.366232990
+0.391006843 0.612152558 0.367175921
+0.391984360 0.611362846 0.368120944
+0.392961877 0.610571682 0.369067005
+0.393939394 0.609778818 0.370014435
+0.394916911 0.608985156 0.370964689
+0.395894428 0.608190696 0.371916178
+0.396871945 0.607395436 0.372868906
+0.397849462 0.606598545 0.373825246
+0.398826979 0.605799225 0.374783038
+0.399804497 0.604998896 0.375742272
+0.400782014 0.604197558 0.376705194
+0.401759531 0.603395208 0.377670184
+0.402737048 0.602591157 0.378636823
+0.403714565 0.601783817 0.379607193
+0.404692082 0.600975251 0.380580296
+0.405669599 0.600165455 0.381555265
+0.406647116 0.599354429 0.382533989
+0.407624633 0.598541740 0.383516150
+0.408602151 0.597724765 0.384500397
+0.409579668 0.596906338 0.385488433
+0.410557185 0.596086453 0.386480623
+0.411534702 0.595265107 0.387475131
+0.412512219 0.594442248 0.388473492
+0.413489736 0.593613964 0.389476718
+0.414467253 0.592783988 0.390482499
+0.415444770 0.591952316 0.391491555
+0.416422287 0.591118941 0.392504668
+0.417399804 0.590283858 0.393520477
+0.418377322 0.589442972 0.394539685
+0.419354839 0.588599687 0.395563270
+0.420332356 0.587754450 0.396589695
+0.421309873 0.586907257 0.397619709
+0.422287390 0.586058099 0.398654373
+0.423264907 0.585202955 0.399692025
+0.424242424 0.584344508 0.400733540
+0.425219941 0.583483842 0.401779909
+0.426197458 0.582620947 0.402829422
+0.427174976 0.581755815 0.403883177
+0.428152493 0.580884615 0.404941902
+0.429130010 0.580009054 0.406003935
+0.430107527 0.579130986 0.407070716
+0.431085044 0.578250399 0.408142475
+0.432062561 0.577367283 0.409217712
+0.433040078 0.576478121 0.410298357
+0.434017595 0.575583374 0.411383856
+0.434995112 0.574685810 0.412473008
+0.435972630 0.573785416 0.413568413
+0.436950147 0.572882178 0.414668387
+0.437927664 0.571973027 0.415772198
+0.438905181 0.571056884 0.416883317
+0.439882698 0.570137591 0.417998533
+0.440860215 0.569215132 0.419118581
+0.441837732 0.568289490 0.420245634
+0.442815249 0.567358177 0.421376894
+0.443792766 0.566418275 0.422514343
+0.444770283 0.565474860 0.423658069
+0.445747801 0.564527914 0.424806212
+0.446725318 0.563577417 0.425962211
+0.447702835 0.562621612 0.427123480
+0.448680352 0.561655405 0.428290282
+0.449657869 0.560685294 0.429465166
+0.450635386 0.559711253 0.430644890
+0.451612903 0.558733259 0.431832308
+0.452590420 0.557750445 0.433026364
+0.453567937 0.556755188 0.434226000
+0.454545455 0.555755595 0.435434924
+0.455522972 0.554751638 0.436649146
+0.456500489 0.553743287 0.437871753
+0.457478006 0.552730515 0.439101626
+0.458455523 0.551703450 0.440338101
+0.459433040 0.550671354 0.441584214
+0.460410557 0.549634415 0.442836126
+0.461388074 0.548592599 0.444098260
+0.462365591 0.547545872 0.445367270
+0.463343109 0.546484786 0.446645195
+0.464320626 0.545416893 0.447931951
+0.465298143 0.544343629 0.449226535
+0.466275660 0.543264953 0.450531713
+0.467253177 0.542180826 0.451843888
+0.468230694 0.541082374 0.453168194
+0.469208211 0.539975079 0.454499403
+0.470185728 0.538861828 0.455843131
+0.471163245 0.537742573 0.457194500
+0.472140762 0.536617267 0.458558366
+0.473118280 0.535477779 0.459930679
+0.474095797 0.534327120 0.461315854
+0.475073314 0.533169855 0.462709935
+0.476050831 0.532005928 0.464117671
+0.477028348 0.530835281 0.465534381
+0.478005865 0.529650711 0.466952620
+0.478983382 0.528452318 0.468377996
+0.479960899 0.527246594 0.469806093
+0.480938416 0.526033471 0.471239943
+0.481915934 0.524812880 0.472678374
+0.482893451 0.523578752 0.474120606
+0.483870968 0.522327784 0.475569070
+0.484848485 0.521068672 0.477020289
+0.485826002 0.519801335 0.478476759
+0.486803519 0.518525692 0.479938796
+0.487781036 0.517237031 0.481403707
+0.488758553 0.515928105 0.482873363
+0.489736070 0.514610118 0.484347894
+0.490713587 0.513282977 0.485826893
+0.491691105 0.511946585 0.487309221
+0.492668622 0.510597845 0.488795133
+0.493646139 0.509224947 0.490284775
+0.494623656 0.507841954 0.491777716
+0.495601173 0.506448755 0.493273513
+0.496578690 0.505045237 0.494770784
+0.497556207 0.503630203 0.496268873
+0.498533724 0.502186589 0.497766318
+0.499511241 0.500731707 0.499259366
+0.500488759 0.499268293 0.500740634
+0.501466276 0.497813411 0.502233682
+0.502443793 0.496369797 0.503731127
+0.503421310 0.494954763 0.505229216
+0.504398827 0.493551245 0.506726487
+0.505376344 0.492158046 0.508222284
+0.506353861 0.490775053 0.509715225
+0.507331378 0.489402155 0.511204867
+0.508308895 0.488053415 0.512690779
+0.509286413 0.486717023 0.514173107
+0.510263930 0.485389882 0.515652106
+0.511241447 0.484071895 0.517126637
+0.512218964 0.482762969 0.518596293
+0.513196481 0.481474308 0.520061204
+0.514173998 0.480198665 0.521523241
+0.515151515 0.478931328 0.522979711
+0.516129032 0.477672216 0.524430930
+0.517106549 0.476421248 0.525879394
+0.518084066 0.475187120 0.527321626
+0.519061584 0.473966529 0.528760057
+0.520039101 0.472753406 0.530193907
+0.521016618 0.471547682 0.531622004
+0.521994135 0.470349289 0.533047380
+0.522971652 0.469164719 0.534465619
+0.523949169 0.467994072 0.535882329
+0.524926686 0.466830145 0.537290065
+0.525904203 0.465672880 0.538684146
+0.526881720 0.464522221 0.540069321
+0.527859238 0.463382733 0.541441634
+0.528836755 0.462257427 0.542805500
+0.529814272 0.461138172 0.544156869
+0.530791789 0.460024921 0.545500597
+0.531769306 0.458917626 0.546831806
+0.532746823 0.457819174 0.548156112
+0.533724340 0.456735047 0.549468287
+0.534701857 0.455656371 0.550773465
+0.535679374 0.454583107 0.552068049
+0.536656891 0.453515214 0.553354805
+0.537634409 0.452454128 0.554632730
+0.538611926 0.451407401 0.555901740
+0.539589443 0.450365585 0.557163874
+0.540566960 0.449328646 0.558415786
+0.541544477 0.448296550 0.559661899
+0.542521994 0.447269485 0.560898374
+0.543499511 0.446256713 0.562128247
+0.544477028 0.445248362 0.563350854
+0.545454545 0.444244405 0.564565076
+0.546432063 0.443244812 0.565774000
+0.547409580 0.442249555 0.566973636
+0.548387097 0.441266741 0.568167692
+0.549364614 0.440288747 0.569355110
+0.550342131 0.439314706 0.570534834
+0.551319648 0.438344595 0.571709718
+0.552297165 0.437378388 0.572876520
+0.553274682 0.436422583 0.574037789
+0.554252199 0.435472086 0.575193788
+0.555229717 0.434525140 0.576341931
+0.556207234 0.433581725 0.577485657
+0.557184751 0.432641823 0.578623106
+0.558162268 0.431710510 0.579754366
+0.559139785 0.430784868 0.580881419
+0.560117302 0.429862409 0.582001467
+0.561094819 0.428943116 0.583116683
+0.562072336 0.428026973 0.584227802
+0.563049853 0.427117822 0.585331613
+0.564027370 0.426214584 0.586431587
+0.565004888 0.425314190 0.587526992
+0.565982405 0.424416626 0.588616144
+0.566959922 0.423521879 0.589701643
+0.567937439 0.422632717 0.590782288
+0.568914956 0.421749601 0.591857525
+0.569892473 0.420869014 0.592929284
+0.570869990 0.419990946 0.593996065
+0.571847507 0.419115385 0.595058098
+0.572825024 0.418244185 0.596116823
+0.573802542 0.417379053 0.597170578
+0.574780059 0.416516158 0.598220091
+0.575757576 0.415655492 0.599266460
+0.576735093 0.414797045 0.600307975
+0.577712610 0.413941901 0.601345627
+0.578690127 0.413092743 0.602380291
+0.579667644 0.412245550 0.603410305
+0.580645161 0.411400313 0.604436730
+0.581622678 0.410557028 0.605460315
+0.582600196 0.409716142 0.606479523
+0.583577713 0.408881059 0.607495332
+0.584555230 0.408047684 0.608508445
+0.585532747 0.407216012 0.609517501
+0.586510264 0.406386036 0.610523282
+0.587487781 0.405557752 0.611526508
+0.588465298 0.404734893 0.612524869
+0.589442815 0.403913547 0.613519377
+0.590420332 0.403093662 0.614511567
+0.591397849 0.402275235 0.615499603
+0.592375367 0.401458260 0.616483850
+0.593352884 0.400645571 0.617466011
+0.594330401 0.399834545 0.618444735
+0.595307918 0.399024749 0.619419704
+0.596285435 0.398216183 0.620392807
+0.597262952 0.397408843 0.621363177
+0.598240469 0.396604792 0.622329816
+0.599217986 0.395802442 0.623294806
+0.600195503 0.395001104 0.624257728
+0.601173021 0.394200775 0.625216962
+0.602150538 0.393401455 0.626174754
+0.603128055 0.392604564 0.627131094
+0.604105572 0.391809304 0.628083822
+0.605083089 0.391014844 0.629035311
+0.606060606 0.390221182 0.629985565
+0.607038123 0.389428318 0.630932995
+0.608015640 0.388637154 0.631879056
+0.608993157 0.387847442 0.632824079
+0.609970674 0.387058324 0.633767010
+0.610948192 0.386269800 0.634708500
+0.611925709 0.385481870 0.635649147
+0.612903226 0.384695033 0.636588337
+0.613880743 0.383909362 0.637526101
+0.614858260 0.383124086 0.638463211
+0.615835777 0.382339202 0.639399398
+0.616813294 0.381554712 0.640334267
+0.617790811 0.380770829 0.641268671
+0.618768328 0.379987720 0.642202572
+0.619745846 0.379204806 0.643135371
+0.620723363 0.378422088 0.644067892
+0.621700880 0.377639566 0.645000134
+0.622678397 0.376857283 0.645931760
+0.623655914 0.376075269 0.646863213
+0.624633431 0.375293255 0.647794574
+0.625610948 0.374511241 0.648725763
+0.626588465 0.373729228 0.649656963
+0.627565982 0.372947197 0.650588255
+0.628543500 0.372164822 0.651519701
+0.629521017 0.371382251 0.652451460
+0.630498534 0.370599484 0.653383496
+0.631476051 0.369816521 0.654315896
+0.632453568 0.369033362 0.655249029
+0.633431085 0.368249202 0.656182626
+0.634408602 0.367464614 0.657116687
+0.635386119 0.366679632 0.658052008
+0.636363636 0.365894257 0.658987986
+0.637341153 0.365108488 0.659924616
+0.638318671 0.364321203 0.660862755
+0.639296188 0.363533124 0.661801943
+0.640273705 0.362744452 0.662741973
+0.641251222 0.361955186 0.663683663
+0.642228739 0.361165325 0.664626899
+0.643206256 0.360373541 0.665571170
+0.644183773 0.359580477 0.666517165
+0.645161290 0.358786616 0.667465300
+0.646138807 0.357991956 0.668414668
+0.647116325 0.357196495 0.669365744
+0.648093842 0.356398810 0.670319646
+0.649071359 0.355599237 0.671274982
+0.650048876 0.354798657 0.672231950
+0.651026393 0.353997066 0.673192503
+0.652003910 0.353194462 0.674154697
+0.652981427 0.352389437 0.675118537
+0.653958944 0.351581790 0.676086512
+0.654936461 0.350772917 0.677056477
+0.655913978 0.349962814 0.678028302
+0.656891496 0.349151479 0.679004405
+0.657869013 0.348337632 0.679983079
+0.658846530 0.347520295 0.680963833
+0.659824047 0.346701503 0.681949010
+0.660801564 0.345881254 0.682937360
+0.661779081 0.345059542 0.683928019
+0.662756598 0.344235335 0.684923271
+0.663734115 0.343406629 0.685922297
+0.664711632 0.342576230 0.686923870
+0.665689150 0.341744132 0.687929130
+0.666666667 0.340910331 0.688937846
+0.667644184 0.340074160 0.689949246
+0.668621701 0.339232333 0.690964504
+0.669599218 0.338388561 0.691983490
+0.670576735 0.337542836 0.693005305
+0.671554252 0.336695152 0.694031207
+0.672531769 0.335845338 0.695061065
+0.673509286 0.334988551 0.696093900
+0.674486804 0.334129550 0.697131132
+0.675464321 0.333268328 0.698172485
+0.676441838 0.332404874 0.699216970
+0.677419355 0.331539182 0.700266262
+0.678396872 0.330665959 0.701319757
+0.679374389 0.329789773 0.702376545
+0.680351906 0.328911076 0.703438672
+0.681329423 0.328029857 0.704504983
+0.682306940 0.327146107 0.705574753
+0.683284457 0.326254698 0.706650544
+0.684261975 0.325359248 0.707730369
+0.685239492 0.324460977 0.708813895
+0.686217009 0.323559874 0.709904167
+0.687194526 0.322655923 0.710998237
+0.688172043 0.321744286 0.712096862
+0.689149560 0.320827357 0.713201951
+0.690127077 0.319907274 0.714311028
+0.691104594 0.318984020 0.715425744
+0.692082111 0.318057580 0.716546437
+0.693059629 0.317123530 0.717671316
+0.694037146 0.316182751 0.718803182
+0.695014663 0.315238455 0.719940303
+0.695992180 0.314290624 0.721082144
+0.696969697 0.313339235 0.722231969
+0.697947214 0.312380425 0.723386379
+0.698924731 0.311413245 0.724547261
+0.699902248 0.310442153 0.725715054
+0.700879765 0.309467126 0.726887658
+0.701857283 0.308488140 0.728068862
+0.702834800 0.307502035 0.729255560
+0.703812317 0.306505697 0.730448885
+0.704789834 0.305505016 0.731650209
+0.705767351 0.304499963 0.732856799
+0.706744868 0.303490510 0.734072768
+0.707722385 0.302474365 0.735294761
+0.708699902 0.301445879 0.736524473
+0.709677419 0.300412575 0.737762451
+0.710654936 0.299374420 0.739006630
+0.711632454 0.298331379 0.740261200
+0.712609971 0.297282205 0.741521781
+0.713587488 0.296218314 0.742792422
+0.714565005 0.295149082 0.744070482
+0.715542522 0.294074469 0.745357611
+0.716520039 0.292994434 0.746653821
+0.717497556 0.291908937 0.747958353
+0.718475073 0.290806106 0.749273413
+0.719452590 0.289697326 0.750596331
+0.720430108 0.288582579 0.751930974
+0.721407625 0.287461816 0.753273330
+0.722385142 0.286334988 0.754628320
+0.723362659 0.285190730 0.755991241
+0.724340176 0.284038425 0.757367382
+0.725317693 0.282879501 0.758752076
+0.726295210 0.281713899 0.760150208
+0.727272727 0.280541562 0.761557968
+0.728250244 0.279351796 0.762978972
+0.729227761 0.278151577 0.764411182
+0.730205279 0.276944010 0.765855987
+0.731182796 0.275729026 0.767314128
+0.732160313 0.274506558 0.768783708
+0.733137830 0.273266769 0.770269365
+0.734115347 0.272013773 0.771767273
+0.735092864 0.270752612 0.773279617
+0.736070381 0.269483206 0.774807849
+0.737047898 0.268205474 0.776350238
+0.738025415 0.266910644 0.777908241
+0.739002933 0.265599461 0.779484121
+0.739980450 0.264279195 0.781076333
+0.740957967 0.262949750 0.782685839
+0.741935484 0.261611030 0.784313657
+0.742913001 0.260255561 0.785960859
+0.743890518 0.258880149 0.787628578
+0.744868035 0.257494616 0.789318005
+0.745845552 0.256098848 0.791030397
+0.746823069 0.254692732 0.792767079
+0.747800587 0.253270349 0.794529580
+0.748778104 0.251823930 0.796323108
+0.749755621 0.250366211 0.798153793
+0.750733138 0.250000000 0.798619957
+0.751710655 0.250000000 0.798619478
+0.752688172 0.250000000 0.798618827
+0.753665689 0.250000000 0.798618046
+0.754643206 0.250000000 0.798617146
+0.755620723 0.250000000 0.798616146
+0.756598240 0.250000000 0.798615054
+0.757575758 0.250000000 0.798613875
+0.758553275 0.250000000 0.798612615
+0.759530792 0.250000000 0.798611281
+0.760508309 0.250000000 0.798609872
+0.761485826 0.250000000 0.798608379
+0.762463343 0.250000000 0.798606824
+0.763440860 0.250000000 0.798605212
+0.764418377 0.250000000 0.798603523
+0.765395894 0.250000000 0.798601768
+0.766373412 0.250000000 0.798599968
+0.767350929 0.250000000 0.798598087
+0.768328446 0.250000000 0.798596154
+0.769305963 0.250000000 0.798594172
+0.770283480 0.250000000 0.798592109
+0.771260997 0.250000000 0.798590018
+0.772238514 0.250000000 0.798587837
+0.773216031 0.250000000 0.798585625
+0.774193548 0.250000000 0.798583339
+0.775171065 0.250000000 0.798581012
+0.776148583 0.250000000 0.798578619
+0.777126100 0.250000000 0.798576179
+0.778103617 0.250000000 0.798573676
+0.779081134 0.250000000 0.798571128
+0.780058651 0.250000000 0.798568514
+0.781036168 0.250000000 0.798565861
+0.782013685 0.250000000 0.798563134
+0.782991202 0.250000000 0.798560379
+0.783968719 0.250000000 0.798557536
+0.784946237 0.250000000 0.798554682
+0.785923754 0.250000000 0.798551722
+0.786901271 0.250000000 0.798548749
+0.787878788 0.250000000 0.798545693
+0.788856305 0.250000000 0.798542598
+0.789833822 0.250000000 0.798539450
+0.790811339 0.250000000 0.798536231
+0.791788856 0.250000000 0.798532993
+0.792766373 0.250000000 0.798529646
+0.793743891 0.250000000 0.798526284
+0.794721408 0.250000000 0.798522845
+0.795698925 0.250000000 0.798519352
+0.796676442 0.250000000 0.798515828
+0.797653959 0.250000000 0.798512201
+0.798631476 0.250000000 0.798508555
+0.799608993 0.250000000 0.798504830
+0.800586510 0.250000000 0.798501045
+0.801564027 0.250000000 0.798497238
+0.802541544 0.250000000 0.798493312
+0.803519062 0.250000000 0.798489365
+0.804496579 0.250000000 0.798485354
+0.805474096 0.250000000 0.798481260
+0.806451613 0.250000000 0.798477144
+0.807429130 0.250000000 0.798472926
+0.808406647 0.250000000 0.798468658
+0.809384164 0.250000000 0.798464362
+0.810361681 0.250000000 0.798459937
+0.811339198 0.250000000 0.798455487
+0.812316716 0.250000000 0.798450981
+0.813294233 0.250000000 0.798446368
+0.814271750 0.250000000 0.798441728
+0.815249267 0.250000000 0.798437007
+0.816226784 0.250000000 0.798432199
+0.817204301 0.250000000 0.798427360
+0.818181818 0.250000000 0.798422419
+0.819159335 0.250000000 0.798417406
+0.820136852 0.250000000 0.798412362
+0.821114370 0.250000000 0.798407195
+0.822091887 0.250000000 0.798401968
+0.823069404 0.250000000 0.798396707
+0.824046921 0.250000000 0.798391309
+0.825024438 0.250000000 0.798385858
+0.826001955 0.250000000 0.798380370
+0.826979472 0.250000000 0.798374734
+0.827956989 0.250000000 0.798369049
+0.828934506 0.250000000 0.798363324
+0.829912023 0.250000000 0.798357442
+0.830889541 0.250000000 0.798351511
+0.831867058 0.250000000 0.798345537
+0.832844575 0.250000000 0.798339400
+0.833822092 0.250000000 0.798333211
+0.834799609 0.250000000 0.798326976
+0.835777126 0.250000000 0.798320576
+0.836754643 0.250000000 0.798314116
+0.837732160 0.250000000 0.798307606
+0.838709677 0.250000000 0.798300932
+0.839687195 0.250000000 0.798294187
+0.840664712 0.250000000 0.798287388
+0.841642229 0.250000000 0.798280430
+0.842619746 0.250000000 0.798273384
+0.843597263 0.250000000 0.798266281
+0.844574780 0.250000000 0.798259026
+0.845552297 0.250000000 0.798251664
+0.846529814 0.250000000 0.798244240
+0.847507331 0.250000000 0.798236674
+0.848484848 0.250000000 0.798228978
+0.849462366 0.250000000 0.798221215
+0.850439883 0.250000000 0.798213324
+0.851417400 0.250000000 0.798205276
+0.852394917 0.250000000 0.798197155
+0.853372434 0.250000000 0.798188922
+0.854349951 0.250000000 0.798180502
+0.855327468 0.250000000 0.798172002
+0.856304985 0.250000000 0.798163410
+0.857282502 0.250000000 0.798154594
+0.858260020 0.250000000 0.798145693
+0.859237537 0.250000000 0.798136706
+0.860215054 0.250000000 0.798127487
+0.861192571 0.250000000 0.798118161
+0.862170088 0.250000000 0.798108741
+0.863147605 0.250000000 0.798099109
+0.864125122 0.250000000 0.798089331
+0.865102639 0.250000000 0.798079451
+0.866080156 0.250000000 0.798069382
+0.867057674 0.250000000 0.798059123
+0.868035191 0.250000000 0.798048754
+0.869012708 0.250000000 0.798038221
+0.869990225 0.250000000 0.798027449
+0.870967742 0.250000000 0.798016558
+0.871945259 0.250000000 0.798005530
+0.872922776 0.250000000 0.797994212
+0.873900293 0.250000000 0.797982764
+0.874877810 0.250000000 0.797971185
+0.875855327 0.250000000 0.797959306
+0.876832845 0.250000000 0.797947263
+0.877810362 0.250000000 0.797935078
+0.878787879 0.250000000 0.797922616
+0.879765396 0.250000000 0.797909935
+0.880742913 0.250000000 0.797897099
+0.881720430 0.250000000 0.797884012
+0.882697947 0.250000000 0.797870648
+0.883675464 0.250000000 0.797857113
+0.884652981 0.250000000 0.797843354
+0.885630499 0.250000000 0.797829254
+0.886608016 0.250000000 0.797814969
+0.887585533 0.250000000 0.797800485
+0.888563050 0.250000000 0.797785594
+0.889540567 0.250000000 0.797770499
+0.890518084 0.250000000 0.797755197
+0.891495601 0.250000000 0.797739486
+0.892473118 0.250000000 0.797723518
+0.893450635 0.250000000 0.797707323
+0.894428152 0.250000000 0.797690733
+0.895405670 0.250000000 0.797673819
+0.896383187 0.250000000 0.797656655
+0.897360704 0.250000000 0.797639111
+0.898338221 0.250000000 0.797621171
+0.899315738 0.250000000 0.797602957
+0.900293255 0.250000000 0.797584371
+0.901270772 0.250000000 0.797565316
+0.902248289 0.250000000 0.797545958
+0.903225806 0.250000000 0.797526235
+0.904203324 0.250000000 0.797505964
+0.905180841 0.250000000 0.797485358
+0.906158358 0.250000000 0.797464387
+0.907135875 0.250000000 0.797442787
+0.908113392 0.250000000 0.797420816
+0.909090909 0.250000000 0.797398464
+0.910068426 0.250000000 0.797375416
+0.911045943 0.250000000 0.797351947
+0.912023460 0.250000000 0.797328054
+0.913000978 0.250000000 0.797303431
+0.913978495 0.250000000 0.797278312
+0.914956012 0.250000000 0.797252722
+0.915933529 0.250000000 0.797226352
+0.916911046 0.250000000 0.797199412
+0.917888563 0.250000000 0.797171944
+0.918866080 0.250000000 0.797143632
+0.919843597 0.250000000 0.797114674
+0.920821114 0.250000000 0.797085122
+0.921798631 0.250000000 0.797054641
+0.922776149 0.250000000 0.797023436
+0.923753666 0.250000000 0.796991562
+0.924731183 0.250000000 0.796958649
+0.925708700 0.250000000 0.796924934
+0.926686217 0.250000000 0.796890462
+0.927663734 0.250000000 0.796854809
+0.928641251 0.250000000 0.796818277
+0.929618768 0.250000000 0.796780885
+0.930596285 0.250000000 0.796742131
+0.931573803 0.250000000 0.796702422
+0.932551320 0.250000000 0.796661678
+0.933528837 0.250000000 0.796619449
+0.934506354 0.250000000 0.796576138
+0.935483871 0.250000000 0.796531554
+0.936461388 0.250000000 0.796485383
+0.937438905 0.250000000 0.796437966
+0.938416422 0.250000000 0.796388970
+0.939393939 0.250000000 0.796338286
+0.940371457 0.250000000 0.796286158
+0.941348974 0.250000000 0.796232059
+0.942326491 0.250000000 0.796176174
+0.943304008 0.250000000 0.796118602
+0.944281525 0.250000000 0.796058564
+0.945259042 0.250000000 0.795996641
+0.946236559 0.250000000 0.795932487
+0.947214076 0.250000000 0.795865725
+0.948191593 0.250000000 0.795796735
+0.949169110 0.250000000 0.795724810
+0.950146628 0.250000000 0.795650131
+0.951124145 0.250000000 0.795572676
+0.952101662 0.250000000 0.795491611
+0.953079179 0.250000000 0.795407522
+0.954056696 0.250000000 0.795319628
+0.955034213 0.250000000 0.795227898
+0.956011730 0.250000000 0.795132357
+0.956989247 0.250000000 0.795031935
+0.957966764 0.250000000 0.794927282
+0.958944282 0.250000000 0.794817257
+0.959921799 0.250000000 0.794701981
+0.960899316 0.250000000 0.794581006
+0.961876833 0.250000000 0.794453449
+0.962854350 0.250000000 0.794319707
+0.963831867 0.250000000 0.794177846
+0.964809384 0.250000000 0.794028718
+0.965786901 0.250000000 0.793870437
+0.966764418 0.250000000 0.793703113
+0.967741935 0.250000000 0.793525315
+0.968719453 0.250000000 0.793336305
+0.969696970 0.250000000 0.793135013
+0.970674487 0.250000000 0.792919868
+0.971652004 0.250000000 0.792689957
+0.972629521 0.250000000 0.792442910
+0.973607038 0.250000000 0.792177663
+0.974584555 0.250000000 0.791891104
+0.975562072 0.250000000 0.791581540
+0.976539589 0.250000000 0.791245216
+0.977517107 0.250000000 0.790900290
+0.978494624 0.250000000 0.790546727
+0.979472141 0.250000000 0.790189953
+0.980449658 0.250000000 0.789814417
+0.981427175 0.250000000 0.789445023
+0.982404692 0.250000000 0.789052209
+0.983382209 0.250000000 0.788657501
+0.984359726 0.250000000 0.788250203
+0.985337243 0.250000000 0.787818500
+0.986314761 0.250000000 0.787390503
+0.987292278 0.250000000 0.786940347
+0.988269795 0.250000000 0.786464072
+0.989247312 0.250000000 0.785974808
+0.990224829 0.250000000 0.785469812
+0.991202346 0.250000000 0.784933879
+0.992179863 0.250000000 0.784364501
+0.993157380 0.250000000 0.783757951
+0.994134897 0.250000000 0.783108264
+0.995112414 0.250000000 0.782404962
+0.996089932 0.250000000 0.781627407
+0.997067449 0.250000000 0.780727892
+0.998044966 0.250000000 0.779693393
+0.999022483 0.250000000 0.778328498
+1.000000000 nan nan
diff --git a/examples/mamdani/SimpleDimmerInverse.fll b/examples/mamdani/SimpleDimmerInverse.fll
new file mode 100644
index 0000000..4ce7313
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.fll
@@ -0,0 +1,42 @@
+Engine: SimpleDimmerInverse
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+OutputVariable: InversePower
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 500
+ default: nan
+ lock-previous: false
+ term: LOW Cosine 0.200 0.500
+ term: MEDIUM Cosine 0.500 0.500
+ term: HIGH Cosine 0.800 0.500
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
+ rule: if Power is LOW then InversePower is HIGH
+ rule: if Power is MEDIUM then InversePower is MEDIUM
+ rule: if Power is HIGH then InversePower is LOW \ No newline at end of file
diff --git a/examples/mamdani/SimpleDimmerInverse.java b/examples/mamdani/SimpleDimmerInverse.java
new file mode 100644
index 0000000..218f831
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.java
@@ -0,0 +1,81 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class SimpleDimmerInverse{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("SimpleDimmerInverse");
+engine.setDescription("");
+
+InputVariable Ambient = new InputVariable();
+Ambient.setName("Ambient");
+Ambient.setDescription("");
+Ambient.setEnabled(true);
+Ambient.setRange(0.000, 1.000);
+Ambient.setLockValueInRange(false);
+Ambient.addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient.addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine.addInputVariable(Ambient);
+
+OutputVariable Power = new OutputVariable();
+Power.setName("Power");
+Power.setDescription("");
+Power.setEnabled(true);
+Power.setRange(0.000, 1.000);
+Power.setLockValueInRange(false);
+Power.setAggregation(new Maximum());
+Power.setDefuzzifier(new Centroid(200));
+Power.setDefaultValue(Double.NaN);
+Power.setLockPreviousValue(false);
+Power.addTerm(new Triangle("LOW", 0.000, 0.250, 0.500));
+Power.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Power.addTerm(new Triangle("HIGH", 0.500, 0.750, 1.000));
+engine.addOutputVariable(Power);
+
+OutputVariable InversePower = new OutputVariable();
+InversePower.setName("InversePower");
+InversePower.setDescription("");
+InversePower.setEnabled(true);
+InversePower.setRange(0.000, 1.000);
+InversePower.setLockValueInRange(false);
+InversePower.setAggregation(new Maximum());
+InversePower.setDefuzzifier(new Centroid(500));
+InversePower.setDefaultValue(Double.NaN);
+InversePower.setLockPreviousValue(false);
+InversePower.addTerm(new Cosine("LOW", 0.200, 0.500));
+InversePower.addTerm(new Cosine("MEDIUM", 0.500, 0.500));
+InversePower.addTerm(new Cosine("HIGH", 0.800, 0.500));
+engine.addOutputVariable(InversePower);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(new Minimum());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is BRIGHT then Power is LOW", engine));
+ruleBlock.addRule(Rule.parse("if Power is LOW then InversePower is HIGH", engine));
+ruleBlock.addRule(Rule.parse("if Power is MEDIUM then InversePower is MEDIUM", engine));
+ruleBlock.addRule(Rule.parse("if Power is HIGH then InversePower is LOW", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/SimpleDimmerInverse.pdf b/examples/mamdani/SimpleDimmerInverse.pdf
new file mode 100644
index 0000000..0cfb26d
--- /dev/null
+++ b/examples/mamdani/SimpleDimmerInverse.pdf
Binary files differ
diff --git a/examples/mamdani/octave/COPYING b/examples/mamdani/octave/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/examples/mamdani/octave/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/examples/mamdani/octave/DESCRIPTION b/examples/mamdani/octave/DESCRIPTION
new file mode 100644
index 0000000..35df57d
--- /dev/null
+++ b/examples/mamdani/octave/DESCRIPTION
@@ -0,0 +1,12 @@
+Name: fuzzy-logic-toolkit
+Version: 0.4.2
+Date: 2012-10-02
+Author: L. Markowsky <lmarkov@users.sourceforge.net>
+Maintainer: L. Markowsky <lmarkov@users.sourceforge.net>
+Title: Octave Fuzzy Logic Toolkit
+Description: A mostly MATLAB-compatible fuzzy logic toolkit for Octave.
+Depends: octave (>= 3.2.4)
+Autoload: no
+License: GPLv3+
+Url: http://octave.sf.net
+ http://sf.net/projects/octave-fuzzy
diff --git a/examples/mamdani/octave/investment_portfolio.R b/examples/mamdani/octave/investment_portfolio.R
new file mode 100644
index 0000000..c752dab
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.R
@@ -0,0 +1,67 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "investment_portfolio"
+engine.fll = "Engine: investment_portfolio
+InputVariable: Age
+ enabled: true
+ range: 20.000 100.000
+ lock-range: false
+ term: Young ZShape 30.000 90.000
+ term: Old SShape 30.000 90.000
+InputVariable: RiskTolerance
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ term: Low ZShape 2.000 8.000
+ term: High SShape 2.000 8.000
+OutputVariable: PercentageInStocks
+ enabled: true
+ range: 0.000 100.000
+ lock-range: false
+ aggregation: EinsteinSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: AboutFifteen Gaussian 15.000 10.000
+ term: AboutFifty Gaussian 50.000 10.000
+ term: AboutEightyFive Gaussian 85.000 10.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: EinsteinSum
+ implication: EinsteinProduct
+ activation: General
+ rule: if Age is Young or RiskTolerance is High then PercentageInStocks is AboutEightyFive
+ rule: if Age is Old or RiskTolerance is Low then PercentageInStocks is AboutFifteen
+ rule: if Age is not extremely Old and RiskTolerance is not extremely Low then PercentageInStocks is AboutFifty with 0.500
+ rule: if Age is not extremely Young and RiskTolerance is not extremely High then PercentageInStocks is AboutFifty with 0.500"
+
+engine.fldFile = "investment_portfolio.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(Age, RiskTolerance)) +
+ geom_tile(aes(fill=PercentageInStocks)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Age, y=RiskTolerance, z=PercentageInStocks), color="black") +
+ ggtitle("(Age, RiskTolerance) = PercentageInStocks")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(RiskTolerance, Age)) +
+ geom_tile(aes(fill=PercentageInStocks)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=RiskTolerance, y=Age, z=PercentageInStocks), color="black") +
+ ggtitle("(RiskTolerance, Age) = PercentageInStocks")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/octave/investment_portfolio.cpp b/examples/mamdani/octave/investment_portfolio.cpp
new file mode 100644
index 0000000..2b82b8c
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.cpp
@@ -0,0 +1,62 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("investment_portfolio");
+engine->setDescription("");
+
+InputVariable* Age = new InputVariable;
+Age->setName("Age");
+Age->setDescription("");
+Age->setEnabled(true);
+Age->setRange(20.000, 100.000);
+Age->setLockValueInRange(false);
+Age->addTerm(new ZShape("Young", 30.000, 90.000));
+Age->addTerm(new SShape("Old", 30.000, 90.000));
+engine->addInputVariable(Age);
+
+InputVariable* RiskTolerance = new InputVariable;
+RiskTolerance->setName("RiskTolerance");
+RiskTolerance->setDescription("");
+RiskTolerance->setEnabled(true);
+RiskTolerance->setRange(0.000, 10.000);
+RiskTolerance->setLockValueInRange(false);
+RiskTolerance->addTerm(new ZShape("Low", 2.000, 8.000));
+RiskTolerance->addTerm(new SShape("High", 2.000, 8.000));
+engine->addInputVariable(RiskTolerance);
+
+OutputVariable* PercentageInStocks = new OutputVariable;
+PercentageInStocks->setName("PercentageInStocks");
+PercentageInStocks->setDescription("");
+PercentageInStocks->setEnabled(true);
+PercentageInStocks->setRange(0.000, 100.000);
+PercentageInStocks->setLockValueInRange(false);
+PercentageInStocks->setAggregation(new EinsteinSum);
+PercentageInStocks->setDefuzzifier(new Centroid(200));
+PercentageInStocks->setDefaultValue(fl::nan);
+PercentageInStocks->setLockPreviousValue(false);
+PercentageInStocks->addTerm(new Gaussian("AboutFifteen", 15.000, 10.000));
+PercentageInStocks->addTerm(new Gaussian("AboutFifty", 50.000, 10.000));
+PercentageInStocks->addTerm(new Gaussian("AboutEightyFive", 85.000, 10.000));
+engine->addOutputVariable(PercentageInStocks);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new EinsteinProduct);
+ruleBlock->setDisjunction(new EinsteinSum);
+ruleBlock->setImplication(new EinsteinProduct);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if Age is Young or RiskTolerance is High then PercentageInStocks is AboutEightyFive", engine));
+ruleBlock->addRule(Rule::parse("if Age is Old or RiskTolerance is Low then PercentageInStocks is AboutFifteen", engine));
+ruleBlock->addRule(Rule::parse("if Age is not extremely Old and RiskTolerance is not extremely Low then PercentageInStocks is AboutFifty with 0.500", engine));
+ruleBlock->addRule(Rule::parse("if Age is not extremely Young and RiskTolerance is not extremely High then PercentageInStocks is AboutFifty with 0.500", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/octave/investment_portfolio.fcl b/examples/mamdani/octave/investment_portfolio.fcl
new file mode 100644
index 0000000..ec837a7
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.fcl
@@ -0,0 +1,46 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK investment_portfolio
+
+VAR_INPUT
+ Age: REAL;
+ RiskTolerance: REAL;
+END_VAR
+
+VAR_OUTPUT
+ PercentageInStocks: REAL;
+END_VAR
+
+FUZZIFY Age
+ RANGE := (20.000 .. 100.000);
+ TERM Young := ZShape 30.000 90.000;
+ TERM Old := SShape 30.000 90.000;
+END_FUZZIFY
+
+FUZZIFY RiskTolerance
+ RANGE := (0.000 .. 10.000);
+ TERM Low := ZShape 2.000 8.000;
+ TERM High := SShape 2.000 8.000;
+END_FUZZIFY
+
+DEFUZZIFY PercentageInStocks
+ RANGE := (0.000 .. 100.000);
+ TERM AboutFifteen := Gaussian 15.000 10.000;
+ TERM AboutFifty := Gaussian 50.000 10.000;
+ TERM AboutEightyFive := Gaussian 85.000 10.000;
+ METHOD : COG;
+ ACCU : ESUM;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : EPROD;
+ OR : ESUM;
+ ACT : EPROD;
+ RULE 1 : if Age is Young or RiskTolerance is High then PercentageInStocks is AboutEightyFive
+ RULE 2 : if Age is Old or RiskTolerance is Low then PercentageInStocks is AboutFifteen
+ RULE 3 : if Age is not extremely Old and RiskTolerance is not extremely Low then PercentageInStocks is AboutFifty with 0.500
+ RULE 4 : if Age is not extremely Young and RiskTolerance is not extremely High then PercentageInStocks is AboutFifty with 0.500
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/octave/investment_portfolio.fis b/examples/mamdani/octave/investment_portfolio.fis
new file mode 100644
index 0000000..b512a68
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.fis
@@ -0,0 +1,42 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='investment_portfolio'
+Type='mamdani'
+Version=6.0
+NumInputs=2
+NumOutputs=1
+NumRules=4
+AndMethod='einstein_product'
+OrMethod='einstein_sum'
+ImpMethod='einstein_product'
+AggMethod='einstein_sum'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Age'
+Range=[20.000 100.000]
+NumMFs=2
+MF1='Young':'zmf',[30.000 90.000]
+MF2='Old':'smf',[30.000 90.000]
+
+[Input2]
+Name='RiskTolerance'
+Range=[0.000 10.000]
+NumMFs=2
+MF1='Low':'zmf',[2.000 8.000]
+MF2='High':'smf',[2.000 8.000]
+
+[Output1]
+Name='PercentageInStocks'
+Range=[0.000 100.000]
+NumMFs=3
+MF1='AboutFifteen':'gaussmf',[10.000 15.000]
+MF2='AboutFifty':'gaussmf',[10.000 50.000]
+MF3='AboutEightyFive':'gaussmf',[10.000 85.000]
+
+[Rules]
+1.000 2.000 , 3.000 (1.000) : 2
+2.000 1.000 , 1.000 (1.000) : 2
+-2.300 -1.300 , 2.000 (0.500) : 1
+-1.300 -2.300 , 2.000 (0.500) : 1
diff --git a/examples/mamdani/octave/investment_portfolio.fld b/examples/mamdani/octave/investment_portfolio.fld
new file mode 100644
index 0000000..4da9cb9
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.fld
@@ -0,0 +1,1025 @@
+Age RiskTolerance PercentageInStocks
+20.000000000 0.000000000 50.000000000
+20.000000000 0.322580645 50.000000000
+20.000000000 0.645161290 50.000000000
+20.000000000 0.967741935 50.000000000
+20.000000000 1.290322581 50.000000000
+20.000000000 1.612903226 50.000000000
+20.000000000 1.935483871 50.000000000
+20.000000000 2.258064516 50.076648486
+20.000000000 2.580645161 50.390076379
+20.000000000 2.903225806 50.952326813
+20.000000000 3.225806452 51.774928323
+20.000000000 3.548387097 52.870980129
+20.000000000 3.870967742 54.250136129
+20.000000000 4.193548387 55.910060541
+20.000000000 4.516129032 57.823117640
+20.000000000 4.838709677 59.917996684
+20.000000000 5.161290323 62.043162940
+20.000000000 5.483870968 64.006621117
+20.000000000 5.806451613 65.820682078
+20.000000000 6.129032258 67.494976640
+20.000000000 6.451612903 69.013706618
+20.000000000 6.774193548 70.341645817
+20.000000000 7.096774194 71.431615962
+20.000000000 7.419354839 72.233442079
+20.000000000 7.741935484 72.703595829
+20.000000000 8.064516129 72.821314025
+20.000000000 8.387096774 72.821314025
+20.000000000 8.709677419 72.821314025
+20.000000000 9.032258065 72.821314025
+20.000000000 9.354838710 72.821314025
+20.000000000 9.677419355 72.821314025
+20.000000000 10.000000000 72.821314025
+22.580645161 0.000000000 50.000000000
+22.580645161 0.322580645 50.000000000
+22.580645161 0.645161290 50.000000000
+22.580645161 0.967741935 50.000000000
+22.580645161 1.290322581 50.000000000
+22.580645161 1.612903226 50.000000000
+22.580645161 1.935483871 50.000000000
+22.580645161 2.258064516 50.076648486
+22.580645161 2.580645161 50.390076379
+22.580645161 2.903225806 50.952326813
+22.580645161 3.225806452 51.774928323
+22.580645161 3.548387097 52.870980129
+22.580645161 3.870967742 54.250136129
+22.580645161 4.193548387 55.910060541
+22.580645161 4.516129032 57.823117640
+22.580645161 4.838709677 59.917996684
+22.580645161 5.161290323 62.043162940
+22.580645161 5.483870968 64.006621117
+22.580645161 5.806451613 65.820682078
+22.580645161 6.129032258 67.494976640
+22.580645161 6.451612903 69.013706618
+22.580645161 6.774193548 70.341645817
+22.580645161 7.096774194 71.431615962
+22.580645161 7.419354839 72.233442079
+22.580645161 7.741935484 72.703595829
+22.580645161 8.064516129 72.821314025
+22.580645161 8.387096774 72.821314025
+22.580645161 8.709677419 72.821314025
+22.580645161 9.032258065 72.821314025
+22.580645161 9.354838710 72.821314025
+22.580645161 9.677419355 72.821314025
+22.580645161 10.000000000 72.821314025
+25.161290323 0.000000000 50.000000000
+25.161290323 0.322580645 50.000000000
+25.161290323 0.645161290 50.000000000
+25.161290323 0.967741935 50.000000000
+25.161290323 1.290322581 50.000000000
+25.161290323 1.612903226 50.000000000
+25.161290323 1.935483871 50.000000000
+25.161290323 2.258064516 50.076648486
+25.161290323 2.580645161 50.390076379
+25.161290323 2.903225806 50.952326813
+25.161290323 3.225806452 51.774928323
+25.161290323 3.548387097 52.870980129
+25.161290323 3.870967742 54.250136129
+25.161290323 4.193548387 55.910060541
+25.161290323 4.516129032 57.823117640
+25.161290323 4.838709677 59.917996684
+25.161290323 5.161290323 62.043162940
+25.161290323 5.483870968 64.006621117
+25.161290323 5.806451613 65.820682078
+25.161290323 6.129032258 67.494976640
+25.161290323 6.451612903 69.013706618
+25.161290323 6.774193548 70.341645817
+25.161290323 7.096774194 71.431615962
+25.161290323 7.419354839 72.233442079
+25.161290323 7.741935484 72.703595829
+25.161290323 8.064516129 72.821314025
+25.161290323 8.387096774 72.821314025
+25.161290323 8.709677419 72.821314025
+25.161290323 9.032258065 72.821314025
+25.161290323 9.354838710 72.821314025
+25.161290323 9.677419355 72.821314025
+25.161290323 10.000000000 72.821314025
+27.741935484 0.000000000 50.000000000
+27.741935484 0.322580645 50.000000000
+27.741935484 0.645161290 50.000000000
+27.741935484 0.967741935 50.000000000
+27.741935484 1.290322581 50.000000000
+27.741935484 1.612903226 50.000000000
+27.741935484 1.935483871 50.000000000
+27.741935484 2.258064516 50.076648486
+27.741935484 2.580645161 50.390076379
+27.741935484 2.903225806 50.952326813
+27.741935484 3.225806452 51.774928323
+27.741935484 3.548387097 52.870980129
+27.741935484 3.870967742 54.250136129
+27.741935484 4.193548387 55.910060541
+27.741935484 4.516129032 57.823117640
+27.741935484 4.838709677 59.917996684
+27.741935484 5.161290323 62.043162940
+27.741935484 5.483870968 64.006621117
+27.741935484 5.806451613 65.820682078
+27.741935484 6.129032258 67.494976640
+27.741935484 6.451612903 69.013706618
+27.741935484 6.774193548 70.341645817
+27.741935484 7.096774194 71.431615962
+27.741935484 7.419354839 72.233442079
+27.741935484 7.741935484 72.703595829
+27.741935484 8.064516129 72.821314025
+27.741935484 8.387096774 72.821314025
+27.741935484 8.709677419 72.821314025
+27.741935484 9.032258065 72.821314025
+27.741935484 9.354838710 72.821314025
+27.741935484 9.677419355 72.821314025
+27.741935484 10.000000000 72.821314025
+30.322580645 0.000000000 49.998803919
+30.322580645 0.322580645 49.998803919
+30.322580645 0.645161290 49.998803919
+30.322580645 0.967741935 49.998803919
+30.322580645 1.290322581 49.998803919
+30.322580645 1.612903226 49.998803919
+30.322580645 1.935483871 49.998803919
+30.322580645 2.258064516 50.075452379
+30.322580645 2.580645161 50.388879647
+30.322580645 2.903225806 50.951126990
+30.322580645 3.225806452 51.773719919
+30.322580645 3.548387097 52.869753955
+30.322580645 3.870967742 54.248879432
+30.322580645 4.193548387 55.908758472
+30.322580645 4.516129032 57.821756837
+30.322580645 4.838709677 59.916571839
+30.322580645 5.161290323 62.041682326
+30.322580645 5.483870968 64.005085024
+30.322580645 5.806451613 65.819089933
+30.322580645 6.129032258 67.493329173
+30.322580645 6.451612903 69.012006089
+30.322580645 6.774193548 70.339896659
+30.322580645 7.096774194 71.429825333
+30.322580645 7.419354839 72.231620048
+30.322580645 7.741935484 72.701755036
+30.322580645 8.064516129 72.819468494
+30.322580645 8.387096774 72.819468494
+30.322580645 8.709677419 72.819468494
+30.322580645 9.032258065 72.819468494
+30.322580645 9.354838710 72.819468494
+30.322580645 9.677419355 72.819468494
+30.322580645 10.000000000 72.819468494
+32.903225806 0.000000000 49.902957979
+32.903225806 0.322580645 49.902957979
+32.903225806 0.645161290 49.902957979
+32.903225806 0.967741935 49.902957979
+32.903225806 1.290322581 49.902957979
+32.903225806 1.612903226 49.902957979
+32.903225806 1.935483871 49.902957979
+32.903225806 2.258064516 49.979607017
+32.903225806 2.580645161 50.292994821
+32.903225806 2.903225806 50.855013655
+32.903225806 3.225806452 51.676947279
+32.903225806 3.548387097 52.771596216
+32.903225806 3.870967742 54.148327846
+32.903225806 4.193548387 55.804640065
+32.903225806 4.516129032 57.713021387
+32.903225806 4.838709677 59.802814253
+32.903225806 5.161290323 61.923569792
+32.903225806 5.483870968 63.882614176
+32.903225806 5.806451613 65.692193202
+32.903225806 6.129032258 67.362058048
+32.903225806 6.451612903 68.876521949
+32.903225806 6.774193548 70.200548955
+32.903225806 7.096774194 71.287181858
+32.903225806 7.419354839 72.086480819
+32.903225806 7.741935484 72.555124481
+32.903225806 8.064516129 72.672461319
+32.903225806 8.387096774 72.672461319
+32.903225806 8.709677419 72.672461319
+32.903225806 9.032258065 72.672461319
+32.903225806 9.354838710 72.672461319
+32.903225806 9.677419355 72.672461319
+32.903225806 10.000000000 72.672461319
+35.483870968 0.000000000 49.652304243
+35.483870968 0.322580645 49.652304243
+35.483870968 0.645161290 49.652304243
+35.483870968 0.967741935 49.652304243
+35.483870968 1.290322581 49.652304243
+35.483870968 1.612903226 49.652304243
+35.483870968 1.935483871 49.652304243
+35.483870968 2.258064516 49.728978589
+35.483870968 2.580645161 50.042360495
+35.483870968 2.903225806 50.603956690
+35.483870968 3.225806452 51.424424786
+35.483870968 3.548387097 52.515806201
+35.483870968 3.870967742 53.886750889
+35.483870968 4.193548387 55.534360928
+35.483870968 4.516129032 57.431479038
+35.483870968 4.838709677 59.509129544
+35.483870968 5.161290323 61.619524277
+35.483870968 5.483870968 63.567960518
+35.483870968 5.806451613 65.366559879
+35.483870968 6.129032258 67.025427611
+35.483870968 6.451612903 68.529270750
+35.483870968 6.774193548 69.843520900
+35.483870968 7.096774194 70.921801863
+35.483870968 7.419354839 71.714759421
+35.483870968 7.741935484 72.179613221
+35.483870968 8.064516129 72.295992918
+35.483870968 8.387096774 72.295992918
+35.483870968 8.709677419 72.295992918
+35.483870968 9.032258065 72.295992918
+35.483870968 9.354838710 72.295992918
+35.483870968 9.677419355 72.295992918
+35.483870968 10.000000000 72.295992918
+38.064516129 0.000000000 49.243098952
+38.064516129 0.322580645 49.243098952
+38.064516129 0.645161290 49.243098952
+38.064516129 0.967741935 49.243098952
+38.064516129 1.290322581 49.243098952
+38.064516129 1.612903226 49.243098952
+38.064516129 1.935483871 49.243098952
+38.064516129 2.258064516 49.319884816
+38.064516129 2.580645161 49.633543934
+38.064516129 2.903225806 50.194964997
+38.064516129 3.225806452 51.013799907
+38.064516129 3.548387097 52.100885441
+38.064516129 3.870967742 53.463764454
+38.064516129 4.193548387 55.098988836
+38.064516129 4.516129032 56.980073530
+38.064516129 4.838709677 59.040771242
+38.064516129 5.161290323 61.137226881
+38.064516129 5.483870968 63.070642355
+38.064516129 5.806451613 64.853053568
+38.064516129 6.129032258 66.495347777
+38.064516129 6.451612903 67.982967596
+38.064516129 6.774193548 69.282183577
+38.064516129 7.096774194 70.347560475
+38.064516129 7.419354839 71.130729588
+38.064516129 7.741935484 71.589715449
+38.064516129 8.064516129 71.704613000
+38.064516129 8.387096774 71.704613000
+38.064516129 8.709677419 71.704613000
+38.064516129 9.032258065 71.704613000
+38.064516129 9.354838710 71.704613000
+38.064516129 9.677419355 71.704613000
+38.064516129 10.000000000 71.704613000
+40.645161290 0.000000000 48.669743020
+40.645161290 0.322580645 48.669743020
+40.645161290 0.645161290 48.669743020
+40.645161290 0.967741935 48.669743020
+40.645161290 1.290322581 48.669743020
+40.645161290 1.612903226 48.669743020
+40.645161290 1.935483871 48.669743020
+40.645161290 2.258064516 48.746819724
+40.645161290 2.580645161 49.061416258
+40.645161290 2.903225806 49.623573900
+40.645161290 3.225806452 50.441561774
+40.645161290 3.548387097 51.524588313
+40.645161290 3.870967742 52.878759776
+40.645161290 4.193548387 54.500031239
+40.645161290 4.516129032 56.363029835
+40.645161290 4.838709677 58.405298469
+40.645161290 5.161290323 60.487754513
+40.645161290 5.483870968 62.404445671
+40.645161290 5.806451613 64.167465175
+40.645161290 6.129032258 65.789133360
+40.645161290 6.451612903 67.256143706
+40.645161290 6.774193548 68.536047010
+40.645161290 7.096774194 69.584753827
+40.645161290 7.419354839 70.355212405
+40.645161290 7.741935484 70.806584970
+40.645161290 8.064516129 70.919555525
+40.645161290 8.387096774 70.919555525
+40.645161290 8.709677419 70.919555525
+40.645161290 9.032258065 70.919555525
+40.645161290 9.354838710 70.919555525
+40.645161290 9.677419355 70.919555525
+40.645161290 10.000000000 70.919555525
+43.225806452 0.000000000 47.925533624
+43.225806452 0.322580645 47.925533624
+43.225806452 0.645161290 47.925533624
+43.225806452 0.967741935 47.925533624
+43.225806452 1.290322581 47.925533624
+43.225806452 1.612903226 47.925533624
+43.225806452 1.935483871 47.925533624
+43.225806452 2.258064516 48.003196119
+43.225806452 2.580645161 48.319856471
+43.225806452 2.903225806 48.884475705
+43.225806452 3.225806452 49.703554418
+43.225806452 3.548387097 50.784261421
+43.225806452 3.870967742 52.130995284
+43.225806452 4.193548387 53.739185104
+43.225806452 4.516129032 55.585152066
+43.225806452 4.838709677 57.611329633
+43.225806452 5.161290323 59.683821844
+43.225806452 5.483870968 61.585369310
+43.225806452 5.806451613 63.328281417
+43.225806452 6.129032258 64.927182028
+43.225806452 6.451612903 66.370699474
+43.225806452 6.774193548 67.628203974
+43.225806452 7.096774194 68.657390741
+43.225806452 7.419354839 69.412890949
+43.225806452 7.741935484 69.855269182
+43.225806452 8.064516129 69.965961562
+43.225806452 8.387096774 69.965961562
+43.225806452 8.709677419 69.965961562
+43.225806452 9.032258065 69.965961562
+43.225806452 9.354838710 69.965961562
+43.225806452 9.677419355 69.965961562
+43.225806452 10.000000000 69.965961562
+45.806451613 0.000000000 47.003934865
+45.806451613 0.322580645 47.003934865
+45.806451613 0.645161290 47.003934865
+45.806451613 0.967741935 47.003934865
+45.806451613 1.290322581 47.003934865
+45.806451613 1.612903226 47.003934865
+45.806451613 1.935483871 47.003934865
+45.806451613 2.258064516 47.082602480
+45.806451613 2.580645161 47.402950274
+45.806451613 2.903225806 47.972607613
+45.806451613 3.225806452 48.795888161
+45.806451613 3.548387097 49.877495327
+45.806451613 3.870967742 51.219883421
+45.806451613 4.193548387 52.818130271
+45.806451613 4.516129032 54.650985755
+45.806451613 4.838709677 56.666980792
+45.806451613 5.161290323 58.737589822
+45.806451613 5.483870968 60.629114424
+45.806451613 5.806451613 62.354014142
+45.806451613 6.129032258 63.930194608
+45.806451613 6.451612903 65.349040002
+45.806451613 6.774193548 66.582379353
+45.806451613 7.096774194 67.590187304
+45.806451613 7.419354839 68.329162947
+45.806451613 7.741935484 68.761558609
+45.806451613 8.064516129 68.869717097
+45.806451613 8.387096774 68.869717097
+45.806451613 8.709677419 68.869717097
+45.806451613 9.032258065 68.869717097
+45.806451613 9.354838710 68.869717097
+45.806451613 9.677419355 68.869717097
+45.806451613 10.000000000 68.869717097
+48.387096774 0.000000000 45.900598613
+48.387096774 0.322580645 45.900598613
+48.387096774 0.645161290 45.900598613
+48.387096774 0.967741935 45.900598613
+48.387096774 1.290322581 45.900598613
+48.387096774 1.612903226 45.900598613
+48.387096774 1.935483871 45.900598613
+48.387096774 2.258064516 45.980803355
+48.387096774 2.580645161 46.306905089
+48.387096774 2.903225806 46.884906961
+48.387096774 3.225806452 47.716447362
+48.387096774 3.548387097 48.803279055
+48.387096774 3.870967742 50.145663256
+48.387096774 4.193548387 51.738567788
+48.387096774 4.516129032 53.564064802
+48.387096774 4.838709677 55.578226605
+48.387096774 5.161290323 57.658283364
+48.387096774 5.483870968 59.548370180
+48.387096774 5.806451613 61.260362735
+48.387096774 6.129032258 62.816285423
+48.387096774 6.451612903 64.211142848
+48.387096774 6.774193548 65.419944811
+48.387096774 7.096774194 66.405514442
+48.387096774 7.419354839 67.127059853
+48.387096774 7.741935484 67.548845082
+48.387096774 8.064516129 67.654301037
+48.387096774 8.387096774 67.654301037
+48.387096774 8.709677419 67.654301037
+48.387096774 9.032258065 67.654301037
+48.387096774 9.354838710 67.654301037
+48.387096774 9.677419355 67.654301037
+48.387096774 10.000000000 67.654301037
+50.967741935 0.000000000 44.616415770
+50.967741935 0.322580645 44.616415770
+50.967741935 0.645161290 44.616415770
+50.967741935 0.967741935 44.616415770
+50.967741935 1.290322581 44.616415770
+50.967741935 1.612903226 44.616415770
+50.967741935 1.935483871 44.616415770
+50.967741935 2.258064516 44.698760304
+50.967741935 2.580645161 45.032946883
+50.967741935 2.903225806 45.622985345
+50.967741935 3.225806452 46.467238467
+50.967741935 3.548387097 47.563910116
+50.967741935 3.870967742 48.910743445
+50.967741935 4.193548387 50.502840212
+50.967741935 4.516129032 52.326633965
+50.967741935 4.838709677 54.347588260
+50.967741935 5.161290323 56.449954685
+50.967741935 5.483870968 58.350161475
+50.967741935 5.806451613 60.057440330
+50.967741935 6.129032258 61.598198804
+50.967741935 6.451612903 62.971785017
+50.967741935 6.774193548 64.157141145
+50.967741935 7.096774194 65.120596669
+50.967741935 7.419354839 65.824409419
+50.967741935 7.741935484 66.235264649
+50.967741935 8.064516129 66.337921286
+50.967741935 8.387096774 66.337921286
+50.967741935 8.709677419 66.337921286
+50.967741935 9.032258065 66.337921286
+50.967741935 9.354838710 66.337921286
+50.967741935 9.677419355 66.337921286
+50.967741935 10.000000000 66.337921286
+53.548387097 0.000000000 43.161863967
+53.548387097 0.322580645 43.161863967
+53.548387097 0.645161290 43.161863967
+53.548387097 0.967741935 43.161863967
+53.548387097 1.290322581 43.161863967
+53.548387097 1.612903226 43.161863967
+53.548387097 1.935483871 43.161863967
+53.548387097 2.258064516 43.246935669
+53.548387097 2.580645161 43.591449152
+53.548387097 2.903225806 44.196962107
+53.548387097 3.225806452 45.057826729
+53.548387097 3.548387097 46.167949378
+53.548387097 3.870967742 47.522086534
+53.548387097 4.193548387 49.115617384
+53.548387097 4.516129032 50.940434962
+53.548387097 4.838709677 52.973755088
+53.548387097 5.161290323 55.109848682
+53.548387097 5.483870968 57.033537819
+53.548387097 5.806451613 58.747231415
+53.548387097 6.129032258 60.280747236
+53.548387097 6.451612903 61.638028848
+53.548387097 6.774193548 62.802609961
+53.548387097 7.096774194 63.745066439
+53.548387097 7.419354839 64.431393253
+53.548387097 7.741935484 64.831240735
+53.548387097 8.064516129 64.931066230
+53.548387097 8.387096774 64.931066230
+53.548387097 8.709677419 64.931066230
+53.548387097 9.032258065 64.931066230
+53.548387097 9.354838710 64.931066230
+53.548387097 9.677419355 64.931066230
+53.548387097 10.000000000 64.931066230
+56.129032258 0.000000000 41.562757424
+56.129032258 0.322580645 41.562757424
+56.129032258 0.645161290 41.562757424
+56.129032258 0.967741935 41.562757424
+56.129032258 1.290322581 41.562757424
+56.129032258 1.612903226 41.562757424
+56.129032258 1.935483871 41.562757424
+56.129032258 2.258064516 41.650983104
+56.129032258 2.580645161 42.007394877
+56.129032258 2.903225806 42.630567878
+56.129032258 3.225806452 43.510014838
+56.129032258 3.548387097 44.634466681
+56.129032258 3.870967742 45.995029495
+56.129032258 4.193548387 47.587232438
+56.129032258 4.516129032 49.409320054
+56.129032258 4.838709677 51.452965804
+56.129032258 5.161290323 53.627995525
+56.129032258 5.483870968 55.587931245
+56.129032258 5.806451613 57.321397482
+56.129032258 6.129032258 58.858477926
+56.129032258 6.451612903 60.206932126
+56.129032258 6.774193548 61.355194390
+56.129032258 7.096774194 62.278842892
+56.129032258 7.419354839 62.948475434
+56.129032258 7.741935484 63.337473295
+56.129032258 8.064516129 63.434463522
+56.129032258 8.387096774 63.434463522
+56.129032258 8.709677419 63.434463522
+56.129032258 9.032258065 63.434463522
+56.129032258 9.354838710 63.434463522
+56.129032258 9.677419355 63.434463522
+56.129032258 10.000000000 63.434463522
+58.709677419 0.000000000 39.867082291
+58.709677419 0.322580645 39.867082291
+58.709677419 0.645161290 39.867082291
+58.709677419 0.967741935 39.867082291
+58.709677419 1.290322581 39.867082291
+58.709677419 1.612903226 39.867082291
+58.709677419 1.935483871 39.867082291
+58.709677419 2.258064516 39.958513244
+58.709677419 2.580645161 40.326884614
+58.709677419 2.903225806 40.967289350
+58.709677419 3.225806452 41.863642692
+58.709677419 3.548387097 42.998628756
+58.709677419 3.870967742 44.358835965
+58.709677419 4.193548387 45.939269950
+58.709677419 4.516129032 47.744614100
+58.709677419 4.838709677 49.783268810
+58.709677419 5.161290323 51.988970730
+58.709677419 5.483870968 53.992678480
+58.709677419 5.806451613 55.759559804
+58.709677419 6.129032258 57.313492323
+58.709677419 6.451612903 58.663327822
+58.709677419 6.774193548 59.801844372
+58.709677419 7.096774194 60.710189164
+58.709677419 7.419354839 61.364580282
+58.709677419 7.741935484 61.743138699
+58.709677419 8.064516129 61.837345788
+58.709677419 8.387096774 61.837345788
+58.709677419 8.709677419 61.837345788
+58.709677419 9.032258065 61.837345788
+58.709677419 9.354838710 61.837345788
+58.709677419 9.677419355 61.837345788
+58.709677419 10.000000000 61.837345788
+61.290322581 0.000000000 38.162654212
+61.290322581 0.322580645 38.162654212
+61.290322581 0.645161290 38.162654212
+61.290322581 0.967741935 38.162654212
+61.290322581 1.290322581 38.162654212
+61.290322581 1.612903226 38.162654212
+61.290322581 1.935483871 38.162654212
+61.290322581 2.258064516 38.256861301
+61.290322581 2.580645161 38.635419718
+61.290322581 2.903225806 39.289810836
+61.290322581 3.225806452 40.198155628
+61.290322581 3.548387097 41.336672178
+61.290322581 3.870967742 42.686507677
+61.290322581 4.193548387 44.240440196
+61.290322581 4.516129032 46.007321520
+61.290322581 4.838709677 48.011029270
+61.290322581 5.161290323 50.216731190
+61.290322581 5.483870968 52.255385900
+61.290322581 5.806451613 54.060730050
+61.290322581 6.129032258 55.641164035
+61.290322581 6.451612903 57.001371244
+61.290322581 6.774193548 58.136357308
+61.290322581 7.096774194 59.032710650
+61.290322581 7.419354839 59.673115386
+61.290322581 7.741935484 60.041486756
+61.290322581 8.064516129 60.132917709
+61.290322581 8.387096774 60.132917709
+61.290322581 8.709677419 60.132917709
+61.290322581 9.032258065 60.132917709
+61.290322581 9.354838710 60.132917709
+61.290322581 9.677419355 60.132917709
+61.290322581 10.000000000 60.132917709
+63.870967742 0.000000000 36.565536478
+63.870967742 0.322580645 36.565536478
+63.870967742 0.645161290 36.565536478
+63.870967742 0.967741935 36.565536478
+63.870967742 1.290322581 36.565536478
+63.870967742 1.612903226 36.565536478
+63.870967742 1.935483871 36.565536478
+63.870967742 2.258064516 36.662526705
+63.870967742 2.580645161 37.051524566
+63.870967742 2.903225806 37.721157108
+63.870967742 3.225806452 38.644805610
+63.870967742 3.548387097 39.793067874
+63.870967742 3.870967742 41.141522074
+63.870967742 4.193548387 42.678602518
+63.870967742 4.516129032 44.412068755
+63.870967742 4.838709677 46.372004475
+63.870967742 5.161290323 48.547034196
+63.870967742 5.483870968 50.590679946
+63.870967742 5.806451613 52.412767562
+63.870967742 6.129032258 54.004970505
+63.870967742 6.451612903 55.365533319
+63.870967742 6.774193548 56.489985162
+63.870967742 7.096774194 57.369432122
+63.870967742 7.419354839 57.992605123
+63.870967742 7.741935484 58.349016896
+63.870967742 8.064516129 58.437242576
+63.870967742 8.387096774 58.437242576
+63.870967742 8.709677419 58.437242576
+63.870967742 9.032258065 58.437242576
+63.870967742 9.354838710 58.437242576
+63.870967742 9.677419355 58.437242576
+63.870967742 10.000000000 58.437242576
+66.451612903 0.000000000 35.068933770
+66.451612903 0.322580645 35.068933770
+66.451612903 0.645161290 35.068933770
+66.451612903 0.967741935 35.068933770
+66.451612903 1.290322581 35.068933770
+66.451612903 1.612903226 35.068933770
+66.451612903 1.935483871 35.068933770
+66.451612903 2.258064516 35.168759265
+66.451612903 2.580645161 35.568606747
+66.451612903 2.903225806 36.254933561
+66.451612903 3.225806452 37.197390039
+66.451612903 3.548387097 38.361971152
+66.451612903 3.870967742 39.719252764
+66.451612903 4.193548387 41.252768585
+66.451612903 4.516129032 42.966462181
+66.451612903 4.838709677 44.890151318
+66.451612903 5.161290323 47.026244912
+66.451612903 5.483870968 49.059565038
+66.451612903 5.806451613 50.884382616
+66.451612903 6.129032258 52.477913466
+66.451612903 6.451612903 53.832050622
+66.451612903 6.774193548 54.942173271
+66.451612903 7.096774194 55.803037893
+66.451612903 7.419354839 56.408550848
+66.451612903 7.741935484 56.753064331
+66.451612903 8.064516129 56.838136033
+66.451612903 8.387096774 56.838136033
+66.451612903 8.709677419 56.838136033
+66.451612903 9.032258065 56.838136033
+66.451612903 9.354838710 56.838136033
+66.451612903 9.677419355 56.838136033
+66.451612903 10.000000000 56.838136033
+69.032258065 0.000000000 33.662078714
+69.032258065 0.322580645 33.662078714
+69.032258065 0.645161290 33.662078714
+69.032258065 0.967741935 33.662078714
+69.032258065 1.290322581 33.662078714
+69.032258065 1.612903226 33.662078714
+69.032258065 1.935483871 33.662078714
+69.032258065 2.258064516 33.764735351
+69.032258065 2.580645161 34.175590581
+69.032258065 2.903225806 34.879403331
+69.032258065 3.225806452 35.842858855
+69.032258065 3.548387097 37.028214983
+69.032258065 3.870967742 38.401801196
+69.032258065 4.193548387 39.942559670
+69.032258065 4.516129032 41.649838525
+69.032258065 4.838709677 43.550045315
+69.032258065 5.161290323 45.652411740
+69.032258065 5.483870968 47.673366035
+69.032258065 5.806451613 49.497159788
+69.032258065 6.129032258 51.089256555
+69.032258065 6.451612903 52.436089884
+69.032258065 6.774193548 53.532761533
+69.032258065 7.096774194 54.377014655
+69.032258065 7.419354839 54.967053117
+69.032258065 7.741935484 55.301239696
+69.032258065 8.064516129 55.383584230
+69.032258065 8.387096774 55.383584230
+69.032258065 8.709677419 55.383584230
+69.032258065 9.032258065 55.383584230
+69.032258065 9.354838710 55.383584230
+69.032258065 9.677419355 55.383584230
+69.032258065 10.000000000 55.383584230
+71.612903226 0.000000000 32.345698963
+71.612903226 0.322580645 32.345698963
+71.612903226 0.645161290 32.345698963
+71.612903226 0.967741935 32.345698963
+71.612903226 1.290322581 32.345698963
+71.612903226 1.612903226 32.345698963
+71.612903226 1.935483871 32.345698963
+71.612903226 2.258064516 32.451154918
+71.612903226 2.580645161 32.872940147
+71.612903226 2.903225806 33.594485558
+71.612903226 3.225806452 34.580055189
+71.612903226 3.548387097 35.788857152
+71.612903226 3.870967742 37.183714577
+71.612903226 4.193548387 38.739637265
+71.612903226 4.516129032 40.451629820
+71.612903226 4.838709677 42.341716636
+71.612903226 5.161290323 44.421773395
+71.612903226 5.483870968 46.435935198
+71.612903226 5.806451613 48.261432212
+71.612903226 6.129032258 49.854336744
+71.612903226 6.451612903 51.196720945
+71.612903226 6.774193548 52.283552638
+71.612903226 7.096774194 53.115093039
+71.612903226 7.419354839 53.693094911
+71.612903226 7.741935484 54.019196645
+71.612903226 8.064516129 54.099401387
+71.612903226 8.387096774 54.099401387
+71.612903226 8.709677419 54.099401387
+71.612903226 9.032258065 54.099401387
+71.612903226 9.354838710 54.099401387
+71.612903226 9.677419355 54.099401387
+71.612903226 10.000000000 54.099401387
+74.193548387 0.000000000 31.130282903
+74.193548387 0.322580645 31.130282903
+74.193548387 0.645161290 31.130282903
+74.193548387 0.967741935 31.130282903
+74.193548387 1.290322581 31.130282903
+74.193548387 1.612903226 31.130282903
+74.193548387 1.935483871 31.130282903
+74.193548387 2.258064516 31.238441391
+74.193548387 2.580645161 31.670837053
+74.193548387 2.903225806 32.409812696
+74.193548387 3.225806452 33.417620647
+74.193548387 3.548387097 34.650959998
+74.193548387 3.870967742 36.069805392
+74.193548387 4.193548387 37.645985858
+74.193548387 4.516129032 39.370885576
+74.193548387 4.838709677 41.262410178
+74.193548387 5.161290323 43.333019208
+74.193548387 5.483870968 45.349014245
+74.193548387 5.806451613 47.181869729
+74.193548387 6.129032258 48.780116579
+74.193548387 6.451612903 50.122504673
+74.193548387 6.774193548 51.204111839
+74.193548387 7.096774194 52.027392387
+74.193548387 7.419354839 52.597049726
+74.193548387 7.741935484 52.917397520
+74.193548387 8.064516129 52.996065135
+74.193548387 8.387096774 52.996065135
+74.193548387 8.709677419 52.996065135
+74.193548387 9.032258065 52.996065135
+74.193548387 9.354838710 52.996065135
+74.193548387 9.677419355 52.996065135
+74.193548387 10.000000000 52.996065135
+76.774193548 0.000000000 30.034038438
+76.774193548 0.322580645 30.034038438
+76.774193548 0.645161290 30.034038438
+76.774193548 0.967741935 30.034038438
+76.774193548 1.290322581 30.034038438
+76.774193548 1.612903226 30.034038438
+76.774193548 1.935483871 30.034038438
+76.774193548 2.258064516 30.144730818
+76.774193548 2.580645161 30.587109051
+76.774193548 2.903225806 31.342609259
+76.774193548 3.225806452 32.371796026
+76.774193548 3.548387097 33.629300526
+76.774193548 3.870967742 35.072817972
+76.774193548 4.193548387 36.671718583
+76.774193548 4.516129032 38.414630690
+76.774193548 4.838709677 40.316178156
+76.774193548 5.161290323 42.388670367
+76.774193548 5.483870968 44.414847934
+76.774193548 5.806451613 46.260814896
+76.774193548 6.129032258 47.869004716
+76.774193548 6.451612903 49.215738579
+76.774193548 6.774193548 50.296445582
+76.774193548 7.096774194 51.115524295
+76.774193548 7.419354839 51.680143529
+76.774193548 7.741935484 51.996803881
+76.774193548 8.064516129 52.074466376
+76.774193548 8.387096774 52.074466376
+76.774193548 8.709677419 52.074466376
+76.774193548 9.032258065 52.074466376
+76.774193548 9.354838710 52.074466376
+76.774193548 9.677419355 52.074466376
+76.774193548 10.000000000 52.074466376
+79.354838710 0.000000000 29.080444475
+79.354838710 0.322580645 29.080444475
+79.354838710 0.645161290 29.080444475
+79.354838710 0.967741935 29.080444475
+79.354838710 1.290322581 29.080444475
+79.354838710 1.612903226 29.080444475
+79.354838710 1.935483871 29.080444475
+79.354838710 2.258064516 29.193415030
+79.354838710 2.580645161 29.644787595
+79.354838710 2.903225806 30.415246173
+79.354838710 3.225806452 31.463952990
+79.354838710 3.548387097 32.743856294
+79.354838710 3.870967742 34.210866640
+79.354838710 4.193548387 35.832534825
+79.354838710 4.516129032 37.595554329
+79.354838710 4.838709677 39.512245487
+79.354838710 5.161290323 41.594701531
+79.354838710 5.483870968 43.636970165
+79.354838710 5.806451613 45.499968761
+79.354838710 6.129032258 47.121240224
+79.354838710 6.451612903 48.475411687
+79.354838710 6.774193548 49.558438226
+79.354838710 7.096774194 50.376426100
+79.354838710 7.419354839 50.938583742
+79.354838710 7.741935484 51.253180276
+79.354838710 8.064516129 51.330256980
+79.354838710 8.387096774 51.330256980
+79.354838710 8.709677419 51.330256980
+79.354838710 9.032258065 51.330256980
+79.354838710 9.354838710 51.330256980
+79.354838710 9.677419355 51.330256980
+79.354838710 10.000000000 51.330256980
+81.935483871 0.000000000 28.295387000
+81.935483871 0.322580645 28.295387000
+81.935483871 0.645161290 28.295387000
+81.935483871 0.967741935 28.295387000
+81.935483871 1.290322581 28.295387000
+81.935483871 1.612903226 28.295387000
+81.935483871 1.935483871 28.295387000
+81.935483871 2.258064516 28.410284551
+81.935483871 2.580645161 28.869270412
+81.935483871 2.903225806 29.652439525
+81.935483871 3.225806452 30.717816423
+81.935483871 3.548387097 32.017032404
+81.935483871 3.870967742 33.504652223
+81.935483871 4.193548387 35.146946432
+81.935483871 4.516129032 36.929357645
+81.935483871 4.838709677 38.862773119
+81.935483871 5.161290323 40.959228758
+81.935483871 5.483870968 43.019926470
+81.935483871 5.806451613 44.901011164
+81.935483871 6.129032258 46.536235546
+81.935483871 6.451612903 47.899114559
+81.935483871 6.774193548 48.986200093
+81.935483871 7.096774194 49.805035003
+81.935483871 7.419354839 50.366456066
+81.935483871 7.741935484 50.680115184
+81.935483871 8.064516129 50.756901048
+81.935483871 8.387096774 50.756901048
+81.935483871 8.709677419 50.756901048
+81.935483871 9.032258065 50.756901048
+81.935483871 9.354838710 50.756901048
+81.935483871 9.677419355 50.756901048
+81.935483871 10.000000000 50.756901048
+84.516129032 0.000000000 27.704007082
+84.516129032 0.322580645 27.704007082
+84.516129032 0.645161290 27.704007082
+84.516129032 0.967741935 27.704007082
+84.516129032 1.290322581 27.704007082
+84.516129032 1.612903226 27.704007082
+84.516129032 1.935483871 27.704007082
+84.516129032 2.258064516 27.820386779
+84.516129032 2.580645161 28.285240579
+84.516129032 2.903225806 29.078198137
+84.516129032 3.225806452 30.156479100
+84.516129032 3.548387097 31.470729250
+84.516129032 3.870967742 32.974572389
+84.516129032 4.193548387 34.633440121
+84.516129032 4.516129032 36.432039482
+84.516129032 4.838709677 38.380475723
+84.516129032 5.161290323 40.490870456
+84.516129032 5.483870968 42.568520962
+84.516129032 5.806451613 44.465639072
+84.516129032 6.129032258 46.113249111
+84.516129032 6.451612903 47.484193799
+84.516129032 6.774193548 48.575575214
+84.516129032 7.096774194 49.396043310
+84.516129032 7.419354839 49.957639505
+84.516129032 7.741935484 50.271021411
+84.516129032 8.064516129 50.347695757
+84.516129032 8.387096774 50.347695757
+84.516129032 8.709677419 50.347695757
+84.516129032 9.032258065 50.347695757
+84.516129032 9.354838710 50.347695757
+84.516129032 9.677419355 50.347695757
+84.516129032 10.000000000 50.347695757
+87.096774194 0.000000000 27.327538681
+87.096774194 0.322580645 27.327538681
+87.096774194 0.645161290 27.327538681
+87.096774194 0.967741935 27.327538681
+87.096774194 1.290322581 27.327538681
+87.096774194 1.612903226 27.327538681
+87.096774194 1.935483871 27.327538681
+87.096774194 2.258064516 27.444875519
+87.096774194 2.580645161 27.913519181
+87.096774194 2.903225806 28.712818142
+87.096774194 3.225806452 29.799451045
+87.096774194 3.548387097 31.123478051
+87.096774194 3.870967742 32.637941952
+87.096774194 4.193548387 34.307806798
+87.096774194 4.516129032 36.117385824
+87.096774194 4.838709677 38.076430208
+87.096774194 5.161290323 40.197185747
+87.096774194 5.483870968 42.286978613
+87.096774194 5.806451613 44.195359935
+87.096774194 6.129032258 45.851672154
+87.096774194 6.451612903 47.228403784
+87.096774194 6.774193548 48.323052721
+87.096774194 7.096774194 49.144986345
+87.096774194 7.419354839 49.707005179
+87.096774194 7.741935484 50.020392983
+87.096774194 8.064516129 50.097042021
+87.096774194 8.387096774 50.097042021
+87.096774194 8.709677419 50.097042021
+87.096774194 9.032258065 50.097042021
+87.096774194 9.354838710 50.097042021
+87.096774194 9.677419355 50.097042021
+87.096774194 10.000000000 50.097042021
+89.677419355 0.000000000 27.180531506
+89.677419355 0.322580645 27.180531506
+89.677419355 0.645161290 27.180531506
+89.677419355 0.967741935 27.180531506
+89.677419355 1.290322581 27.180531506
+89.677419355 1.612903226 27.180531506
+89.677419355 1.935483871 27.180531506
+89.677419355 2.258064516 27.298244964
+89.677419355 2.580645161 27.768379952
+89.677419355 2.903225806 28.570174667
+89.677419355 3.225806452 29.660103341
+89.677419355 3.548387097 30.987993911
+89.677419355 3.870967742 32.506670827
+89.677419355 4.193548387 34.180910067
+89.677419355 4.516129032 35.994914976
+89.677419355 4.838709677 37.958317674
+89.677419355 5.161290323 40.083428161
+89.677419355 5.483870968 42.178243163
+89.677419355 5.806451613 44.091241528
+89.677419355 6.129032258 45.751120568
+89.677419355 6.451612903 47.130246045
+89.677419355 6.774193548 48.226280081
+89.677419355 7.096774194 49.048873010
+89.677419355 7.419354839 49.611120353
+89.677419355 7.741935484 49.924547621
+89.677419355 8.064516129 50.001196081
+89.677419355 8.387096774 50.001196081
+89.677419355 8.709677419 50.001196081
+89.677419355 9.032258065 50.001196081
+89.677419355 9.354838710 50.001196081
+89.677419355 9.677419355 50.001196081
+89.677419355 10.000000000 50.001196081
+92.258064516 0.000000000 27.178685975
+92.258064516 0.322580645 27.178685975
+92.258064516 0.645161290 27.178685975
+92.258064516 0.967741935 27.178685975
+92.258064516 1.290322581 27.178685975
+92.258064516 1.612903226 27.178685975
+92.258064516 1.935483871 27.178685975
+92.258064516 2.258064516 27.296404171
+92.258064516 2.580645161 27.766557921
+92.258064516 2.903225806 28.568384038
+92.258064516 3.225806452 29.658354183
+92.258064516 3.548387097 30.986293382
+92.258064516 3.870967742 32.505023360
+92.258064516 4.193548387 34.179317922
+92.258064516 4.516129032 35.993378883
+92.258064516 4.838709677 37.956837060
+92.258064516 5.161290323 40.082003316
+92.258064516 5.483870968 42.176882360
+92.258064516 5.806451613 44.089939459
+92.258064516 6.129032258 45.749863871
+92.258064516 6.451612903 47.129019871
+92.258064516 6.774193548 48.225071677
+92.258064516 7.096774194 49.047673187
+92.258064516 7.419354839 49.609923621
+92.258064516 7.741935484 49.923351514
+92.258064516 8.064516129 50.000000000
+92.258064516 8.387096774 50.000000000
+92.258064516 8.709677419 50.000000000
+92.258064516 9.032258065 50.000000000
+92.258064516 9.354838710 50.000000000
+92.258064516 9.677419355 50.000000000
+92.258064516 10.000000000 50.000000000
+94.838709677 0.000000000 27.178685975
+94.838709677 0.322580645 27.178685975
+94.838709677 0.645161290 27.178685975
+94.838709677 0.967741935 27.178685975
+94.838709677 1.290322581 27.178685975
+94.838709677 1.612903226 27.178685975
+94.838709677 1.935483871 27.178685975
+94.838709677 2.258064516 27.296404171
+94.838709677 2.580645161 27.766557921
+94.838709677 2.903225806 28.568384038
+94.838709677 3.225806452 29.658354183
+94.838709677 3.548387097 30.986293382
+94.838709677 3.870967742 32.505023360
+94.838709677 4.193548387 34.179317922
+94.838709677 4.516129032 35.993378883
+94.838709677 4.838709677 37.956837060
+94.838709677 5.161290323 40.082003316
+94.838709677 5.483870968 42.176882360
+94.838709677 5.806451613 44.089939459
+94.838709677 6.129032258 45.749863871
+94.838709677 6.451612903 47.129019871
+94.838709677 6.774193548 48.225071677
+94.838709677 7.096774194 49.047673187
+94.838709677 7.419354839 49.609923621
+94.838709677 7.741935484 49.923351514
+94.838709677 8.064516129 50.000000000
+94.838709677 8.387096774 50.000000000
+94.838709677 8.709677419 50.000000000
+94.838709677 9.032258065 50.000000000
+94.838709677 9.354838710 50.000000000
+94.838709677 9.677419355 50.000000000
+94.838709677 10.000000000 50.000000000
+97.419354839 0.000000000 27.178685975
+97.419354839 0.322580645 27.178685975
+97.419354839 0.645161290 27.178685975
+97.419354839 0.967741935 27.178685975
+97.419354839 1.290322581 27.178685975
+97.419354839 1.612903226 27.178685975
+97.419354839 1.935483871 27.178685975
+97.419354839 2.258064516 27.296404171
+97.419354839 2.580645161 27.766557921
+97.419354839 2.903225806 28.568384038
+97.419354839 3.225806452 29.658354183
+97.419354839 3.548387097 30.986293382
+97.419354839 3.870967742 32.505023360
+97.419354839 4.193548387 34.179317922
+97.419354839 4.516129032 35.993378883
+97.419354839 4.838709677 37.956837060
+97.419354839 5.161290323 40.082003316
+97.419354839 5.483870968 42.176882360
+97.419354839 5.806451613 44.089939459
+97.419354839 6.129032258 45.749863871
+97.419354839 6.451612903 47.129019871
+97.419354839 6.774193548 48.225071677
+97.419354839 7.096774194 49.047673187
+97.419354839 7.419354839 49.609923621
+97.419354839 7.741935484 49.923351514
+97.419354839 8.064516129 50.000000000
+97.419354839 8.387096774 50.000000000
+97.419354839 8.709677419 50.000000000
+97.419354839 9.032258065 50.000000000
+97.419354839 9.354838710 50.000000000
+97.419354839 9.677419355 50.000000000
+97.419354839 10.000000000 50.000000000
+100.000000000 0.000000000 27.178685975
+100.000000000 0.322580645 27.178685975
+100.000000000 0.645161290 27.178685975
+100.000000000 0.967741935 27.178685975
+100.000000000 1.290322581 27.178685975
+100.000000000 1.612903226 27.178685975
+100.000000000 1.935483871 27.178685975
+100.000000000 2.258064516 27.296404171
+100.000000000 2.580645161 27.766557921
+100.000000000 2.903225806 28.568384038
+100.000000000 3.225806452 29.658354183
+100.000000000 3.548387097 30.986293382
+100.000000000 3.870967742 32.505023360
+100.000000000 4.193548387 34.179317922
+100.000000000 4.516129032 35.993378883
+100.000000000 4.838709677 37.956837060
+100.000000000 5.161290323 40.082003316
+100.000000000 5.483870968 42.176882360
+100.000000000 5.806451613 44.089939459
+100.000000000 6.129032258 45.749863871
+100.000000000 6.451612903 47.129019871
+100.000000000 6.774193548 48.225071677
+100.000000000 7.096774194 49.047673187
+100.000000000 7.419354839 49.609923621
+100.000000000 7.741935484 49.923351514
+100.000000000 8.064516129 50.000000000
+100.000000000 8.387096774 50.000000000
+100.000000000 8.709677419 50.000000000
+100.000000000 9.032258065 50.000000000
+100.000000000 9.354838710 50.000000000
+100.000000000 9.677419355 50.000000000
+100.000000000 10.000000000 50.000000000
diff --git a/examples/mamdani/octave/investment_portfolio.fll b/examples/mamdani/octave/investment_portfolio.fll
new file mode 100644
index 0000000..628fdef
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.fll
@@ -0,0 +1,34 @@
+Engine: investment_portfolio
+InputVariable: Age
+ enabled: true
+ range: 20.000 100.000
+ lock-range: false
+ term: Young ZShape 30.000 90.000
+ term: Old SShape 30.000 90.000
+InputVariable: RiskTolerance
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ term: Low ZShape 2.000 8.000
+ term: High SShape 2.000 8.000
+OutputVariable: PercentageInStocks
+ enabled: true
+ range: 0.000 100.000
+ lock-range: false
+ aggregation: EinsteinSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: AboutFifteen Gaussian 15.000 10.000
+ term: AboutFifty Gaussian 50.000 10.000
+ term: AboutEightyFive Gaussian 85.000 10.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: EinsteinSum
+ implication: EinsteinProduct
+ activation: General
+ rule: if Age is Young or RiskTolerance is High then PercentageInStocks is AboutEightyFive
+ rule: if Age is Old or RiskTolerance is Low then PercentageInStocks is AboutFifteen
+ rule: if Age is not extremely Old and RiskTolerance is not extremely Low then PercentageInStocks is AboutFifty with 0.500
+ rule: if Age is not extremely Young and RiskTolerance is not extremely High then PercentageInStocks is AboutFifty with 0.500 \ No newline at end of file
diff --git a/examples/mamdani/octave/investment_portfolio.java b/examples/mamdani/octave/investment_portfolio.java
new file mode 100644
index 0000000..9dff687
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.java
@@ -0,0 +1,73 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class investment_portfolio{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("investment_portfolio");
+engine.setDescription("");
+
+InputVariable Age = new InputVariable();
+Age.setName("Age");
+Age.setDescription("");
+Age.setEnabled(true);
+Age.setRange(20.000, 100.000);
+Age.setLockValueInRange(false);
+Age.addTerm(new ZShape("Young", 30.000, 90.000));
+Age.addTerm(new SShape("Old", 30.000, 90.000));
+engine.addInputVariable(Age);
+
+InputVariable RiskTolerance = new InputVariable();
+RiskTolerance.setName("RiskTolerance");
+RiskTolerance.setDescription("");
+RiskTolerance.setEnabled(true);
+RiskTolerance.setRange(0.000, 10.000);
+RiskTolerance.setLockValueInRange(false);
+RiskTolerance.addTerm(new ZShape("Low", 2.000, 8.000));
+RiskTolerance.addTerm(new SShape("High", 2.000, 8.000));
+engine.addInputVariable(RiskTolerance);
+
+OutputVariable PercentageInStocks = new OutputVariable();
+PercentageInStocks.setName("PercentageInStocks");
+PercentageInStocks.setDescription("");
+PercentageInStocks.setEnabled(true);
+PercentageInStocks.setRange(0.000, 100.000);
+PercentageInStocks.setLockValueInRange(false);
+PercentageInStocks.setAggregation(new EinsteinSum());
+PercentageInStocks.setDefuzzifier(new Centroid(200));
+PercentageInStocks.setDefaultValue(Double.NaN);
+PercentageInStocks.setLockPreviousValue(false);
+PercentageInStocks.addTerm(new Gaussian("AboutFifteen", 15.000, 10.000));
+PercentageInStocks.addTerm(new Gaussian("AboutFifty", 50.000, 10.000));
+PercentageInStocks.addTerm(new Gaussian("AboutEightyFive", 85.000, 10.000));
+engine.addOutputVariable(PercentageInStocks);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new EinsteinProduct());
+ruleBlock.setDisjunction(new EinsteinSum());
+ruleBlock.setImplication(new EinsteinProduct());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if Age is Young or RiskTolerance is High then PercentageInStocks is AboutEightyFive", engine));
+ruleBlock.addRule(Rule.parse("if Age is Old or RiskTolerance is Low then PercentageInStocks is AboutFifteen", engine));
+ruleBlock.addRule(Rule.parse("if Age is not extremely Old and RiskTolerance is not extremely Low then PercentageInStocks is AboutFifty with 0.500", engine));
+ruleBlock.addRule(Rule.parse("if Age is not extremely Young and RiskTolerance is not extremely High then PercentageInStocks is AboutFifty with 0.500", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/octave/investment_portfolio.pdf b/examples/mamdani/octave/investment_portfolio.pdf
new file mode 100644
index 0000000..c9c897e
--- /dev/null
+++ b/examples/mamdani/octave/investment_portfolio.pdf
Binary files differ
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.R b/examples/mamdani/octave/mamdani_tip_calculator.R
new file mode 100644
index 0000000..81eabe2
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.R
@@ -0,0 +1,90 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "mamdani_tip_calculator"
+engine.fll = "Engine: mamdani_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: Tip
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: AlgebraicSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: AboutTenPercent Gaussian 10.000 2.000
+ term: AboutFifteenPercent Gaussian 15.000 2.000
+ term: AboutTwentyPercent Gaussian 20.000 2.000
+OutputVariable: CheckPlusTip
+ enabled: true
+ range: 1.000 1.300
+ lock-range: false
+ aggregation: AlgebraicSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: PlusAboutTenPercent Gaussian 1.100 0.020
+ term: PlusAboutFifteenPercent Gaussian 1.150 0.020
+ term: PlusAboutTwentyPercent Gaussian 1.200 0.020
+RuleBlock:
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if FoodQuality is Bad and Service is Bad then Tip is AboutTenPercent and CheckPlusTip is PlusAboutTenPercent
+ rule: if FoodQuality is Bad and Service is Good then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ rule: if FoodQuality is Good and Service is Bad then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ rule: if FoodQuality is Good and Service is Good then Tip is AboutTwentyPercent and CheckPlusTip is PlusAboutTwentyPercent"
+
+engine.fldFile = "mamdani_tip_calculator.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(FoodQuality, Service)) +
+ geom_tile(aes(fill=Tip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=FoodQuality, y=Service, z=Tip), color="black") +
+ ggtitle("(FoodQuality, Service) = Tip")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(Service, FoodQuality)) +
+ geom_tile(aes(fill=Tip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Service, y=FoodQuality, z=Tip), color="black") +
+ ggtitle("(Service, FoodQuality) = Tip")
+
+engine.plot.i1i2_o2 = ggplot(engine.df, aes(FoodQuality, Service)) +
+ geom_tile(aes(fill=CheckPlusTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=FoodQuality, y=Service, z=CheckPlusTip), color="black") +
+ ggtitle("(FoodQuality, Service) = CheckPlusTip")
+
+engine.plot.i2i1_o2 = ggplot(engine.df, aes(Service, FoodQuality)) +
+ geom_tile(aes(fill=CheckPlusTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Service, y=FoodQuality, z=CheckPlusTip), color="black") +
+ ggtitle("(Service, FoodQuality) = CheckPlusTip")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, engine.plot.i1i2_o2, engine.plot.i2i1_o2, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.cpp b/examples/mamdani/octave/mamdani_tip_calculator.cpp
new file mode 100644
index 0000000..86d6464
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.cpp
@@ -0,0 +1,77 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("mamdani_tip_calculator");
+engine->setDescription("");
+
+InputVariable* FoodQuality = new InputVariable;
+FoodQuality->setName("FoodQuality");
+FoodQuality->setDescription("");
+FoodQuality->setEnabled(true);
+FoodQuality->setRange(1.000, 10.000);
+FoodQuality->setLockValueInRange(false);
+FoodQuality->addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+FoodQuality->addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine->addInputVariable(FoodQuality);
+
+InputVariable* Service = new InputVariable;
+Service->setName("Service");
+Service->setDescription("");
+Service->setEnabled(true);
+Service->setRange(1.000, 10.000);
+Service->setLockValueInRange(false);
+Service->addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+Service->addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine->addInputVariable(Service);
+
+OutputVariable* Tip = new OutputVariable;
+Tip->setName("Tip");
+Tip->setDescription("");
+Tip->setEnabled(true);
+Tip->setRange(0.000, 30.000);
+Tip->setLockValueInRange(false);
+Tip->setAggregation(new AlgebraicSum);
+Tip->setDefuzzifier(new Centroid(200));
+Tip->setDefaultValue(fl::nan);
+Tip->setLockPreviousValue(false);
+Tip->addTerm(new Gaussian("AboutTenPercent", 10.000, 2.000));
+Tip->addTerm(new Gaussian("AboutFifteenPercent", 15.000, 2.000));
+Tip->addTerm(new Gaussian("AboutTwentyPercent", 20.000, 2.000));
+engine->addOutputVariable(Tip);
+
+OutputVariable* CheckPlusTip = new OutputVariable;
+CheckPlusTip->setName("CheckPlusTip");
+CheckPlusTip->setDescription("");
+CheckPlusTip->setEnabled(true);
+CheckPlusTip->setRange(1.000, 1.300);
+CheckPlusTip->setLockValueInRange(false);
+CheckPlusTip->setAggregation(new AlgebraicSum);
+CheckPlusTip->setDefuzzifier(new Centroid(200));
+CheckPlusTip->setDefaultValue(fl::nan);
+CheckPlusTip->setLockPreviousValue(false);
+CheckPlusTip->addTerm(new Gaussian("PlusAboutTenPercent", 1.100, 0.020));
+CheckPlusTip->addTerm(new Gaussian("PlusAboutFifteenPercent", 1.150, 0.020));
+CheckPlusTip->addTerm(new Gaussian("PlusAboutTwentyPercent", 1.200, 0.020));
+engine->addOutputVariable(CheckPlusTip);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new AlgebraicProduct);
+ruleBlock->setDisjunction(new Maximum);
+ruleBlock->setImplication(new Minimum);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if FoodQuality is Bad and Service is Bad then Tip is AboutTenPercent and CheckPlusTip is PlusAboutTenPercent", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Bad and Service is Good then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is Bad then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is Good then Tip is AboutTwentyPercent and CheckPlusTip is PlusAboutTwentyPercent", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.fcl b/examples/mamdani/octave/mamdani_tip_calculator.fcl
new file mode 100644
index 0000000..0265bc2
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.fcl
@@ -0,0 +1,57 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK mamdani_tip_calculator
+
+VAR_INPUT
+ FoodQuality: REAL;
+ Service: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Tip: REAL;
+ CheckPlusTip: REAL;
+END_VAR
+
+FUZZIFY FoodQuality
+ RANGE := (1.000 .. 10.000);
+ TERM Bad := Trapezoid 0.000 1.000 3.000 7.000;
+ TERM Good := Trapezoid 3.000 7.000 10.000 11.000;
+END_FUZZIFY
+
+FUZZIFY Service
+ RANGE := (1.000 .. 10.000);
+ TERM Bad := Trapezoid 0.000 1.000 3.000 7.000;
+ TERM Good := Trapezoid 3.000 7.000 10.000 11.000;
+END_FUZZIFY
+
+DEFUZZIFY Tip
+ RANGE := (0.000 .. 30.000);
+ TERM AboutTenPercent := Gaussian 10.000 2.000;
+ TERM AboutFifteenPercent := Gaussian 15.000 2.000;
+ TERM AboutTwentyPercent := Gaussian 20.000 2.000;
+ METHOD : COG;
+ ACCU : ASUM;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY CheckPlusTip
+ RANGE := (1.000 .. 1.300);
+ TERM PlusAboutTenPercent := Gaussian 1.100 0.020;
+ TERM PlusAboutFifteenPercent := Gaussian 1.150 0.020;
+ TERM PlusAboutTwentyPercent := Gaussian 1.200 0.020;
+ METHOD : COG;
+ ACCU : ASUM;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : PROD;
+ OR : MAX;
+ ACT : MIN;
+ RULE 1 : if FoodQuality is Bad and Service is Bad then Tip is AboutTenPercent and CheckPlusTip is PlusAboutTenPercent
+ RULE 2 : if FoodQuality is Bad and Service is Good then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ RULE 3 : if FoodQuality is Good and Service is Bad then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ RULE 4 : if FoodQuality is Good and Service is Good then Tip is AboutTwentyPercent and CheckPlusTip is PlusAboutTwentyPercent
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.fis b/examples/mamdani/octave/mamdani_tip_calculator.fis
new file mode 100644
index 0000000..13cd802
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.fis
@@ -0,0 +1,50 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='mamdani_tip_calculator'
+Type='mamdani'
+Version=6.0
+NumInputs=2
+NumOutputs=2
+NumRules=4
+AndMethod='prod'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='probor'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='FoodQuality'
+Range=[1.000 10.000]
+NumMFs=2
+MF1='Bad':'trapmf',[0.000 1.000 3.000 7.000]
+MF2='Good':'trapmf',[3.000 7.000 10.000 11.000]
+
+[Input2]
+Name='Service'
+Range=[1.000 10.000]
+NumMFs=2
+MF1='Bad':'trapmf',[0.000 1.000 3.000 7.000]
+MF2='Good':'trapmf',[3.000 7.000 10.000 11.000]
+
+[Output1]
+Name='Tip'
+Range=[0.000 30.000]
+NumMFs=3
+MF1='AboutTenPercent':'gaussmf',[2.000 10.000]
+MF2='AboutFifteenPercent':'gaussmf',[2.000 15.000]
+MF3='AboutTwentyPercent':'gaussmf',[2.000 20.000]
+
+[Output2]
+Name='CheckPlusTip'
+Range=[1.000 1.300]
+NumMFs=3
+MF1='PlusAboutTenPercent':'gaussmf',[0.020 1.100]
+MF2='PlusAboutFifteenPercent':'gaussmf',[0.020 1.150]
+MF3='PlusAboutTwentyPercent':'gaussmf',[0.020 1.200]
+
+[Rules]
+1.000 1.000 , 1.000 1.000 (1.000) : 1
+1.000 2.000 , 2.000 2.000 (1.000) : 1
+2.000 1.000 , 2.000 2.000 (1.000) : 1
+2.000 2.000 , 3.000 3.000 (1.000) : 1
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.fld b/examples/mamdani/octave/mamdani_tip_calculator.fld
new file mode 100644
index 0000000..9d87eab
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.fld
@@ -0,0 +1,1025 @@
+FoodQuality Service Tip CheckPlusTip
+1.000000000 1.000000000 10.000002957 1.100000030
+1.000000000 1.290322581 10.000002957 1.100000030
+1.000000000 1.580645161 10.000002957 1.100000030
+1.000000000 1.870967742 10.000002957 1.100000030
+1.000000000 2.161290323 10.000002957 1.100000030
+1.000000000 2.451612903 10.000002957 1.100000030
+1.000000000 2.741935484 10.000002957 1.100000030
+1.000000000 3.032258065 10.103612040 1.101036120
+1.000000000 3.322580645 10.708467388 1.107084674
+1.000000000 3.612903226 11.133945555 1.111339456
+1.000000000 3.903225806 11.479248807 1.114792488
+1.000000000 4.193548387 11.778370516 1.117783705
+1.000000000 4.483870968 12.050104922 1.120501049
+1.000000000 4.774193548 12.305762763 1.123057628
+1.000000000 5.064516129 12.555175445 1.125551754
+1.000000000 5.354838710 12.806659860 1.128066599
+1.000000000 5.645161290 13.068093230 1.130680932
+1.000000000 5.935483871 13.350561957 1.133505620
+1.000000000 6.225806452 13.666570669 1.136665707
+1.000000000 6.516129032 14.042124914 1.140421249
+1.000000000 6.806451613 14.524928709 1.145249287
+1.000000000 7.096774194 15.000000000 1.150000000
+1.000000000 7.387096774 15.000000000 1.150000000
+1.000000000 7.677419355 15.000000000 1.150000000
+1.000000000 7.967741935 15.000000000 1.150000000
+1.000000000 8.258064516 15.000000000 1.150000000
+1.000000000 8.548387097 15.000000000 1.150000000
+1.000000000 8.838709677 15.000000000 1.150000000
+1.000000000 9.129032258 15.000000000 1.150000000
+1.000000000 9.419354839 15.000000000 1.150000000
+1.000000000 9.709677419 15.000000000 1.150000000
+1.000000000 10.000000000 15.000000000 1.150000000
+1.290322581 1.000000000 10.000002957 1.100000030
+1.290322581 1.290322581 10.000002957 1.100000030
+1.290322581 1.580645161 10.000002957 1.100000030
+1.290322581 1.870967742 10.000002957 1.100000030
+1.290322581 2.161290323 10.000002957 1.100000030
+1.290322581 2.451612903 10.000002957 1.100000030
+1.290322581 2.741935484 10.000002957 1.100000030
+1.290322581 3.032258065 10.103612040 1.101036120
+1.290322581 3.322580645 10.708467388 1.107084674
+1.290322581 3.612903226 11.133945555 1.111339456
+1.290322581 3.903225806 11.479248807 1.114792488
+1.290322581 4.193548387 11.778370516 1.117783705
+1.290322581 4.483870968 12.050104922 1.120501049
+1.290322581 4.774193548 12.305762763 1.123057628
+1.290322581 5.064516129 12.555175445 1.125551754
+1.290322581 5.354838710 12.806659860 1.128066599
+1.290322581 5.645161290 13.068093230 1.130680932
+1.290322581 5.935483871 13.350561957 1.133505620
+1.290322581 6.225806452 13.666570669 1.136665707
+1.290322581 6.516129032 14.042124914 1.140421249
+1.290322581 6.806451613 14.524928709 1.145249287
+1.290322581 7.096774194 15.000000000 1.150000000
+1.290322581 7.387096774 15.000000000 1.150000000
+1.290322581 7.677419355 15.000000000 1.150000000
+1.290322581 7.967741935 15.000000000 1.150000000
+1.290322581 8.258064516 15.000000000 1.150000000
+1.290322581 8.548387097 15.000000000 1.150000000
+1.290322581 8.838709677 15.000000000 1.150000000
+1.290322581 9.129032258 15.000000000 1.150000000
+1.290322581 9.419354839 15.000000000 1.150000000
+1.290322581 9.709677419 15.000000000 1.150000000
+1.290322581 10.000000000 15.000000000 1.150000000
+1.580645161 1.000000000 10.000002957 1.100000030
+1.580645161 1.290322581 10.000002957 1.100000030
+1.580645161 1.580645161 10.000002957 1.100000030
+1.580645161 1.870967742 10.000002957 1.100000030
+1.580645161 2.161290323 10.000002957 1.100000030
+1.580645161 2.451612903 10.000002957 1.100000030
+1.580645161 2.741935484 10.000002957 1.100000030
+1.580645161 3.032258065 10.103612040 1.101036120
+1.580645161 3.322580645 10.708467388 1.107084674
+1.580645161 3.612903226 11.133945555 1.111339456
+1.580645161 3.903225806 11.479248807 1.114792488
+1.580645161 4.193548387 11.778370516 1.117783705
+1.580645161 4.483870968 12.050104922 1.120501049
+1.580645161 4.774193548 12.305762763 1.123057628
+1.580645161 5.064516129 12.555175445 1.125551754
+1.580645161 5.354838710 12.806659860 1.128066599
+1.580645161 5.645161290 13.068093230 1.130680932
+1.580645161 5.935483871 13.350561957 1.133505620
+1.580645161 6.225806452 13.666570669 1.136665707
+1.580645161 6.516129032 14.042124914 1.140421249
+1.580645161 6.806451613 14.524928709 1.145249287
+1.580645161 7.096774194 15.000000000 1.150000000
+1.580645161 7.387096774 15.000000000 1.150000000
+1.580645161 7.677419355 15.000000000 1.150000000
+1.580645161 7.967741935 15.000000000 1.150000000
+1.580645161 8.258064516 15.000000000 1.150000000
+1.580645161 8.548387097 15.000000000 1.150000000
+1.580645161 8.838709677 15.000000000 1.150000000
+1.580645161 9.129032258 15.000000000 1.150000000
+1.580645161 9.419354839 15.000000000 1.150000000
+1.580645161 9.709677419 15.000000000 1.150000000
+1.580645161 10.000000000 15.000000000 1.150000000
+1.870967742 1.000000000 10.000002957 1.100000030
+1.870967742 1.290322581 10.000002957 1.100000030
+1.870967742 1.580645161 10.000002957 1.100000030
+1.870967742 1.870967742 10.000002957 1.100000030
+1.870967742 2.161290323 10.000002957 1.100000030
+1.870967742 2.451612903 10.000002957 1.100000030
+1.870967742 2.741935484 10.000002957 1.100000030
+1.870967742 3.032258065 10.103612040 1.101036120
+1.870967742 3.322580645 10.708467388 1.107084674
+1.870967742 3.612903226 11.133945555 1.111339456
+1.870967742 3.903225806 11.479248807 1.114792488
+1.870967742 4.193548387 11.778370516 1.117783705
+1.870967742 4.483870968 12.050104922 1.120501049
+1.870967742 4.774193548 12.305762763 1.123057628
+1.870967742 5.064516129 12.555175445 1.125551754
+1.870967742 5.354838710 12.806659860 1.128066599
+1.870967742 5.645161290 13.068093230 1.130680932
+1.870967742 5.935483871 13.350561957 1.133505620
+1.870967742 6.225806452 13.666570669 1.136665707
+1.870967742 6.516129032 14.042124914 1.140421249
+1.870967742 6.806451613 14.524928709 1.145249287
+1.870967742 7.096774194 15.000000000 1.150000000
+1.870967742 7.387096774 15.000000000 1.150000000
+1.870967742 7.677419355 15.000000000 1.150000000
+1.870967742 7.967741935 15.000000000 1.150000000
+1.870967742 8.258064516 15.000000000 1.150000000
+1.870967742 8.548387097 15.000000000 1.150000000
+1.870967742 8.838709677 15.000000000 1.150000000
+1.870967742 9.129032258 15.000000000 1.150000000
+1.870967742 9.419354839 15.000000000 1.150000000
+1.870967742 9.709677419 15.000000000 1.150000000
+1.870967742 10.000000000 15.000000000 1.150000000
+2.161290323 1.000000000 10.000002957 1.100000030
+2.161290323 1.290322581 10.000002957 1.100000030
+2.161290323 1.580645161 10.000002957 1.100000030
+2.161290323 1.870967742 10.000002957 1.100000030
+2.161290323 2.161290323 10.000002957 1.100000030
+2.161290323 2.451612903 10.000002957 1.100000030
+2.161290323 2.741935484 10.000002957 1.100000030
+2.161290323 3.032258065 10.103612040 1.101036120
+2.161290323 3.322580645 10.708467388 1.107084674
+2.161290323 3.612903226 11.133945555 1.111339456
+2.161290323 3.903225806 11.479248807 1.114792488
+2.161290323 4.193548387 11.778370516 1.117783705
+2.161290323 4.483870968 12.050104922 1.120501049
+2.161290323 4.774193548 12.305762763 1.123057628
+2.161290323 5.064516129 12.555175445 1.125551754
+2.161290323 5.354838710 12.806659860 1.128066599
+2.161290323 5.645161290 13.068093230 1.130680932
+2.161290323 5.935483871 13.350561957 1.133505620
+2.161290323 6.225806452 13.666570669 1.136665707
+2.161290323 6.516129032 14.042124914 1.140421249
+2.161290323 6.806451613 14.524928709 1.145249287
+2.161290323 7.096774194 15.000000000 1.150000000
+2.161290323 7.387096774 15.000000000 1.150000000
+2.161290323 7.677419355 15.000000000 1.150000000
+2.161290323 7.967741935 15.000000000 1.150000000
+2.161290323 8.258064516 15.000000000 1.150000000
+2.161290323 8.548387097 15.000000000 1.150000000
+2.161290323 8.838709677 15.000000000 1.150000000
+2.161290323 9.129032258 15.000000000 1.150000000
+2.161290323 9.419354839 15.000000000 1.150000000
+2.161290323 9.709677419 15.000000000 1.150000000
+2.161290323 10.000000000 15.000000000 1.150000000
+2.451612903 1.000000000 10.000002957 1.100000030
+2.451612903 1.290322581 10.000002957 1.100000030
+2.451612903 1.580645161 10.000002957 1.100000030
+2.451612903 1.870967742 10.000002957 1.100000030
+2.451612903 2.161290323 10.000002957 1.100000030
+2.451612903 2.451612903 10.000002957 1.100000030
+2.451612903 2.741935484 10.000002957 1.100000030
+2.451612903 3.032258065 10.103612040 1.101036120
+2.451612903 3.322580645 10.708467388 1.107084674
+2.451612903 3.612903226 11.133945555 1.111339456
+2.451612903 3.903225806 11.479248807 1.114792488
+2.451612903 4.193548387 11.778370516 1.117783705
+2.451612903 4.483870968 12.050104922 1.120501049
+2.451612903 4.774193548 12.305762763 1.123057628
+2.451612903 5.064516129 12.555175445 1.125551754
+2.451612903 5.354838710 12.806659860 1.128066599
+2.451612903 5.645161290 13.068093230 1.130680932
+2.451612903 5.935483871 13.350561957 1.133505620
+2.451612903 6.225806452 13.666570669 1.136665707
+2.451612903 6.516129032 14.042124914 1.140421249
+2.451612903 6.806451613 14.524928709 1.145249287
+2.451612903 7.096774194 15.000000000 1.150000000
+2.451612903 7.387096774 15.000000000 1.150000000
+2.451612903 7.677419355 15.000000000 1.150000000
+2.451612903 7.967741935 15.000000000 1.150000000
+2.451612903 8.258064516 15.000000000 1.150000000
+2.451612903 8.548387097 15.000000000 1.150000000
+2.451612903 8.838709677 15.000000000 1.150000000
+2.451612903 9.129032258 15.000000000 1.150000000
+2.451612903 9.419354839 15.000000000 1.150000000
+2.451612903 9.709677419 15.000000000 1.150000000
+2.451612903 10.000000000 15.000000000 1.150000000
+2.741935484 1.000000000 10.000002957 1.100000030
+2.741935484 1.290322581 10.000002957 1.100000030
+2.741935484 1.580645161 10.000002957 1.100000030
+2.741935484 1.870967742 10.000002957 1.100000030
+2.741935484 2.161290323 10.000002957 1.100000030
+2.741935484 2.451612903 10.000002957 1.100000030
+2.741935484 2.741935484 10.000002957 1.100000030
+2.741935484 3.032258065 10.103612040 1.101036120
+2.741935484 3.322580645 10.708467388 1.107084674
+2.741935484 3.612903226 11.133945555 1.111339456
+2.741935484 3.903225806 11.479248807 1.114792488
+2.741935484 4.193548387 11.778370516 1.117783705
+2.741935484 4.483870968 12.050104922 1.120501049
+2.741935484 4.774193548 12.305762763 1.123057628
+2.741935484 5.064516129 12.555175445 1.125551754
+2.741935484 5.354838710 12.806659860 1.128066599
+2.741935484 5.645161290 13.068093230 1.130680932
+2.741935484 5.935483871 13.350561957 1.133505620
+2.741935484 6.225806452 13.666570669 1.136665707
+2.741935484 6.516129032 14.042124914 1.140421249
+2.741935484 6.806451613 14.524928709 1.145249287
+2.741935484 7.096774194 15.000000000 1.150000000
+2.741935484 7.387096774 15.000000000 1.150000000
+2.741935484 7.677419355 15.000000000 1.150000000
+2.741935484 7.967741935 15.000000000 1.150000000
+2.741935484 8.258064516 15.000000000 1.150000000
+2.741935484 8.548387097 15.000000000 1.150000000
+2.741935484 8.838709677 15.000000000 1.150000000
+2.741935484 9.129032258 15.000000000 1.150000000
+2.741935484 9.419354839 15.000000000 1.150000000
+2.741935484 9.709677419 15.000000000 1.150000000
+2.741935484 10.000000000 15.000000000 1.150000000
+3.032258065 1.000000000 10.103612040 1.101036120
+3.032258065 1.290322581 10.103612040 1.101036120
+3.032258065 1.580645161 10.103612040 1.101036120
+3.032258065 1.870967742 10.103612040 1.101036120
+3.032258065 2.161290323 10.103612040 1.101036120
+3.032258065 2.451612903 10.103612040 1.101036120
+3.032258065 2.741935484 10.103612040 1.101036120
+3.032258065 3.032258065 10.204358113 1.102043581
+3.032258065 3.322580645 10.796018218 1.107960182
+3.032258065 3.612903226 11.215358735 1.112153587
+3.032258065 3.903225806 11.557846462 1.115578465
+3.032258065 4.193548387 11.855790361 1.118557904
+3.032258065 4.483870968 12.127240434 1.121272404
+3.032258065 4.774193548 12.384052580 1.123840526
+3.032258065 5.064516129 12.634997421 1.126349974
+3.032258065 5.354838710 12.888585631 1.128885856
+3.032258065 5.645161290 13.153230669 1.131532307
+3.032258065 5.935483871 13.438880990 1.134388810
+3.032258065 6.225806452 13.759265462 1.137592655
+3.032258065 6.516129032 14.139344845 1.141393448
+3.032258065 6.806451613 14.626746497 1.146267465
+3.032258065 7.096774194 15.103574890 1.151035749
+3.032258065 7.387096774 15.103574890 1.151035749
+3.032258065 7.677419355 15.103574890 1.151035749
+3.032258065 7.967741935 15.103574890 1.151035749
+3.032258065 8.258064516 15.103574890 1.151035749
+3.032258065 8.548387097 15.103574890 1.151035749
+3.032258065 8.838709677 15.103574890 1.151035749
+3.032258065 9.129032258 15.103574890 1.151035749
+3.032258065 9.419354839 15.103574890 1.151035749
+3.032258065 9.709677419 15.103574890 1.151035749
+3.032258065 10.000000000 15.103574890 1.151035749
+3.322580645 1.000000000 10.708467388 1.107084674
+3.322580645 1.290322581 10.708467388 1.107084674
+3.322580645 1.580645161 10.708467388 1.107084674
+3.322580645 1.870967742 10.708467388 1.107084674
+3.322580645 2.161290323 10.708467388 1.107084674
+3.322580645 2.451612903 10.708467388 1.107084674
+3.322580645 2.741935484 10.708467388 1.107084674
+3.322580645 3.032258065 10.796018218 1.107960182
+3.322580645 3.322580645 11.322661747 1.113226617
+3.322580645 3.612903226 11.712913158 1.117129132
+3.322580645 3.903225806 12.043415217 1.120434152
+3.322580645 4.193548387 12.339709404 1.123397094
+3.322580645 4.483870968 12.615733153 1.126157332
+3.322580645 4.774193548 12.881223868 1.128812239
+3.322580645 5.064516129 13.144835022 1.131448350
+3.322580645 5.354838710 13.414082467 1.134140825
+3.322580645 5.645161290 13.696138923 1.136961389
+3.322580645 5.935483871 14.000777693 1.140007777
+3.322580645 6.225806452 14.342258539 1.143422585
+3.322580645 6.516129032 14.739964250 1.147399642
+3.322580645 6.806451613 15.239164015 1.152391640
+3.322580645 7.096774194 15.708449495 1.157084495
+3.322580645 7.387096774 15.708449495 1.157084495
+3.322580645 7.677419355 15.708449495 1.157084495
+3.322580645 7.967741935 15.708449495 1.157084495
+3.322580645 8.258064516 15.708449495 1.157084495
+3.322580645 8.548387097 15.708449495 1.157084495
+3.322580645 8.838709677 15.708449495 1.157084495
+3.322580645 9.129032258 15.708449495 1.157084495
+3.322580645 9.419354839 15.708449495 1.157084495
+3.322580645 9.709677419 15.708449495 1.157084495
+3.322580645 10.000000000 15.708449495 1.157084495
+3.612903226 1.000000000 11.133945555 1.111339456
+3.612903226 1.290322581 11.133945555 1.111339456
+3.612903226 1.580645161 11.133945555 1.111339456
+3.612903226 1.870967742 11.133945555 1.111339456
+3.612903226 2.161290323 11.133945555 1.111339456
+3.612903226 2.451612903 11.133945555 1.111339456
+3.612903226 2.741935484 11.133945555 1.111339456
+3.612903226 3.032258065 11.215358735 1.112153587
+3.612903226 3.322580645 11.712913158 1.117129132
+3.612903226 3.612903226 12.090486886 1.120904869
+3.612903226 3.903225806 12.417951094 1.124179511
+3.612903226 4.193548387 12.717020386 1.127170204
+3.612903226 4.483870968 12.999111631 1.129991116
+3.612903226 4.774193548 13.273780609 1.132737806
+3.612903226 5.064516129 13.547717972 1.135477180
+3.612903226 5.354838710 13.827512227 1.138275122
+3.612903226 5.645161290 14.120187657 1.141201877
+3.612903226 5.935483871 14.435371678 1.144353717
+3.612903226 6.225806452 14.784914127 1.147849141
+3.612903226 6.516129032 15.187004870 1.151870049
+3.612903226 6.806451613 15.681548005 1.156815480
+3.612903226 7.096774194 16.133823742 1.161338237
+3.612903226 7.387096774 16.133823742 1.161338237
+3.612903226 7.677419355 16.133823742 1.161338237
+3.612903226 7.967741935 16.133823742 1.161338237
+3.612903226 8.258064516 16.133823742 1.161338237
+3.612903226 8.548387097 16.133823742 1.161338237
+3.612903226 8.838709677 16.133823742 1.161338237
+3.612903226 9.129032258 16.133823742 1.161338237
+3.612903226 9.419354839 16.133823742 1.161338237
+3.612903226 9.709677419 16.133823742 1.161338237
+3.612903226 10.000000000 16.133823742 1.161338237
+3.903225806 1.000000000 11.479248807 1.114792488
+3.903225806 1.290322581 11.479248807 1.114792488
+3.903225806 1.580645161 11.479248807 1.114792488
+3.903225806 1.870967742 11.479248807 1.114792488
+3.903225806 2.161290323 11.479248807 1.114792488
+3.903225806 2.451612903 11.479248807 1.114792488
+3.903225806 2.741935484 11.479248807 1.114792488
+3.903225806 3.032258065 11.557846462 1.115578465
+3.903225806 3.322580645 12.043415217 1.120434152
+3.903225806 3.612903226 12.417951094 1.124179511
+3.903225806 3.903225806 12.746299057 1.127462991
+3.903225806 4.193548387 13.049696353 1.130496964
+3.903225806 4.483870968 13.337970486 1.133379705
+3.903225806 4.774193548 13.620159587 1.136201596
+3.903225806 5.064516129 13.901946604 1.139019466
+3.903225806 5.354838710 14.188883155 1.141888832
+3.903225806 5.645161290 14.489540684 1.144895407
+3.903225806 5.935483871 14.809822020 1.148098220
+3.903225806 6.225806452 15.160748839 1.151607488
+3.903225806 6.516129032 15.560871420 1.155608714
+3.903225806 6.806451613 16.043900181 1.160439002
+3.903225806 7.096774194 16.479227686 1.164792277
+3.903225806 7.387096774 16.479227686 1.164792277
+3.903225806 7.677419355 16.479227686 1.164792277
+3.903225806 7.967741935 16.479227686 1.164792277
+3.903225806 8.258064516 16.479227686 1.164792277
+3.903225806 8.548387097 16.479227686 1.164792277
+3.903225806 8.838709677 16.479227686 1.164792277
+3.903225806 9.129032258 16.479227686 1.164792277
+3.903225806 9.419354839 16.479227686 1.164792277
+3.903225806 9.709677419 16.479227686 1.164792277
+3.903225806 10.000000000 16.479227686 1.164792277
+4.193548387 1.000000000 11.778370516 1.117783705
+4.193548387 1.290322581 11.778370516 1.117783705
+4.193548387 1.580645161 11.778370516 1.117783705
+4.193548387 1.870967742 11.778370516 1.117783705
+4.193548387 2.161290323 11.778370516 1.117783705
+4.193548387 2.451612903 11.778370516 1.117783705
+4.193548387 2.741935484 11.778370516 1.117783705
+4.193548387 3.032258065 11.855790361 1.118557904
+4.193548387 3.322580645 12.339709404 1.123397094
+4.193548387 3.612903226 12.717020386 1.127170204
+4.193548387 3.903225806 13.049696353 1.130496964
+4.193548387 4.193548387 13.357895418 1.133578954
+4.193548387 4.483870968 13.652146644 1.136521466
+4.193548387 4.774193548 13.940357897 1.139403579
+4.193548387 5.064516129 14.228197117 1.142281971
+4.193548387 5.354838710 14.520452601 1.145204526
+4.193548387 5.645161290 14.824425958 1.148244260
+4.193548387 5.935483871 15.146110946 1.151461109
+4.193548387 6.225806452 15.495840162 1.154958402
+4.193548387 6.516129032 15.889898831 1.158898988
+4.193548387 6.806451613 16.360710958 1.163607110
+4.193548387 7.096774194 16.778452741 1.167784527
+4.193548387 7.387096774 16.778452741 1.167784527
+4.193548387 7.677419355 16.778452741 1.167784527
+4.193548387 7.967741935 16.778452741 1.167784527
+4.193548387 8.258064516 16.778452741 1.167784527
+4.193548387 8.548387097 16.778452741 1.167784527
+4.193548387 8.838709677 16.778452741 1.167784527
+4.193548387 9.129032258 16.778452741 1.167784527
+4.193548387 9.419354839 16.778452741 1.167784527
+4.193548387 9.709677419 16.778452741 1.167784527
+4.193548387 10.000000000 16.778452741 1.167784527
+4.483870968 1.000000000 12.050104922 1.120501049
+4.483870968 1.290322581 12.050104922 1.120501049
+4.483870968 1.580645161 12.050104922 1.120501049
+4.483870968 1.870967742 12.050104922 1.120501049
+4.483870968 2.161290323 12.050104922 1.120501049
+4.483870968 2.451612903 12.050104922 1.120501049
+4.483870968 2.741935484 12.050104922 1.120501049
+4.483870968 3.032258065 12.127240434 1.121272404
+4.483870968 3.322580645 12.615733153 1.126157332
+4.483870968 3.612903226 12.999111631 1.129991116
+4.483870968 3.903225806 13.337970486 1.133379705
+4.483870968 4.193548387 13.652146644 1.136521466
+4.483870968 4.483870968 13.951679758 1.139516798
+4.483870968 4.774193548 14.245365454 1.142453655
+4.483870968 5.064516129 14.537425993 1.145374260
+4.483870968 5.354838710 14.832538034 1.148325380
+4.483870968 5.645161290 15.137036426 1.151370364
+4.483870968 5.935483871 15.457098960 1.154570990
+4.483870968 6.225806452 15.803334671 1.158033347
+4.483870968 6.516129032 16.189645887 1.161896459
+4.483870968 6.806451613 16.646502949 1.166465029
+4.483870968 7.096774194 17.050023823 1.170500238
+4.483870968 7.387096774 17.050023823 1.170500238
+4.483870968 7.677419355 17.050023823 1.170500238
+4.483870968 7.967741935 17.050023823 1.170500238
+4.483870968 8.258064516 17.050023823 1.170500238
+4.483870968 8.548387097 17.050023823 1.170500238
+4.483870968 8.838709677 17.050023823 1.170500238
+4.483870968 9.129032258 17.050023823 1.170500238
+4.483870968 9.419354839 17.050023823 1.170500238
+4.483870968 9.709677419 17.050023823 1.170500238
+4.483870968 10.000000000 17.050023823 1.170500238
+4.774193548 1.000000000 12.305762763 1.123057628
+4.774193548 1.290322581 12.305762763 1.123057628
+4.774193548 1.580645161 12.305762763 1.123057628
+4.774193548 1.870967742 12.305762763 1.123057628
+4.774193548 2.161290323 12.305762763 1.123057628
+4.774193548 2.451612903 12.305762763 1.123057628
+4.774193548 2.741935484 12.305762763 1.123057628
+4.774193548 3.032258065 12.384052580 1.123840526
+4.774193548 3.322580645 12.881223868 1.128812239
+4.774193548 3.612903226 13.273780609 1.132737806
+4.774193548 3.903225806 13.620159587 1.136201596
+4.774193548 4.193548387 13.940357897 1.139403579
+4.774193548 4.483870968 14.245365454 1.142453655
+4.774193548 4.774193548 14.542253555 1.145422536
+4.774193548 5.064516129 14.836186297 1.148361863
+4.774193548 5.354838710 15.132216948 1.151322169
+4.774193548 5.645161290 15.435976637 1.154359766
+4.774193548 5.935483871 15.753650335 1.157536503
+4.774193548 6.225806452 16.094398574 1.160943986
+4.774193548 6.516129032 16.472016458 1.164720165
+4.774193548 6.806451613 16.915328759 1.169153288
+4.774193548 7.096774194 17.305719073 1.173057191
+4.774193548 7.387096774 17.305719073 1.173057191
+4.774193548 7.677419355 17.305719073 1.173057191
+4.774193548 7.967741935 17.305719073 1.173057191
+4.774193548 8.258064516 17.305719073 1.173057191
+4.774193548 8.548387097 17.305719073 1.173057191
+4.774193548 8.838709677 17.305719073 1.173057191
+4.774193548 9.129032258 17.305719073 1.173057191
+4.774193548 9.419354839 17.305719073 1.173057191
+4.774193548 9.709677419 17.305719073 1.173057191
+4.774193548 10.000000000 17.305719073 1.173057191
+5.064516129 1.000000000 12.555175445 1.125551754
+5.064516129 1.290322581 12.555175445 1.125551754
+5.064516129 1.580645161 12.555175445 1.125551754
+5.064516129 1.870967742 12.555175445 1.125551754
+5.064516129 2.161290323 12.555175445 1.125551754
+5.064516129 2.451612903 12.555175445 1.125551754
+5.064516129 2.741935484 12.555175445 1.125551754
+5.064516129 3.032258065 12.634997421 1.126349974
+5.064516129 3.322580645 13.144835022 1.131448350
+5.064516129 3.612903226 13.547717972 1.135477180
+5.064516129 3.903225806 13.901946604 1.139019466
+5.064516129 4.193548387 14.228197117 1.142281971
+5.064516129 4.483870968 14.537425993 1.145374260
+5.064516129 4.774193548 14.836186297 1.148361863
+5.064516129 5.064516129 15.130822202 1.151308222
+5.064516129 5.354838710 15.426134812 1.154261348
+5.064516129 5.645161290 15.727608429 1.157276084
+5.064516129 5.935483871 16.040918075 1.160409181
+5.064516129 6.225806452 16.374971626 1.163749716
+5.064516129 6.516129032 16.743479696 1.167434797
+5.064516129 6.806451613 17.175031887 1.171750319
+5.064516129 7.096774194 17.555546435 1.175555464
+5.064516129 7.387096774 17.555546435 1.175555464
+5.064516129 7.677419355 17.555546435 1.175555464
+5.064516129 7.967741935 17.555546435 1.175555464
+5.064516129 8.258064516 17.555546435 1.175555464
+5.064516129 8.548387097 17.555546435 1.175555464
+5.064516129 8.838709677 17.555546435 1.175555464
+5.064516129 9.129032258 17.555546435 1.175555464
+5.064516129 9.419354839 17.555546435 1.175555464
+5.064516129 9.709677419 17.555546435 1.175555464
+5.064516129 10.000000000 17.555546435 1.175555464
+5.354838710 1.000000000 12.806659860 1.128066599
+5.354838710 1.290322581 12.806659860 1.128066599
+5.354838710 1.580645161 12.806659860 1.128066599
+5.354838710 1.870967742 12.806659860 1.128066599
+5.354838710 2.161290323 12.806659860 1.128066599
+5.354838710 2.451612903 12.806659860 1.128066599
+5.354838710 2.741935484 12.806659860 1.128066599
+5.354838710 3.032258065 12.888585631 1.128885856
+5.354838710 3.322580645 13.414082467 1.134140825
+5.354838710 3.612903226 13.827512227 1.138275122
+5.354838710 3.903225806 14.188883155 1.141888832
+5.354838710 4.193548387 14.520452601 1.145204526
+5.354838710 4.483870968 14.832538034 1.148325380
+5.354838710 4.774193548 15.132216948 1.151322169
+5.354838710 5.064516129 15.426134812 1.154261348
+5.354838710 5.354838710 15.719361905 1.157193619
+5.354838710 5.645161290 16.017791161 1.160177912
+5.354838710 5.935483871 16.325903819 1.163259038
+5.354838710 6.225806452 16.653358486 1.166533585
+5.354838710 6.516129032 17.013348713 1.170133487
+5.354838710 6.806451613 17.434097089 1.174340971
+5.354838710 7.096774194 17.806398651 1.178063987
+5.354838710 7.387096774 17.806398651 1.178063987
+5.354838710 7.677419355 17.806398651 1.178063987
+5.354838710 7.967741935 17.806398651 1.178063987
+5.354838710 8.258064516 17.806398651 1.178063987
+5.354838710 8.548387097 17.806398651 1.178063987
+5.354838710 8.838709677 17.806398651 1.178063987
+5.354838710 9.129032258 17.806398651 1.178063987
+5.354838710 9.419354839 17.806398651 1.178063987
+5.354838710 9.709677419 17.806398651 1.178063987
+5.354838710 10.000000000 17.806398651 1.178063987
+5.645161290 1.000000000 13.068093230 1.130680932
+5.645161290 1.290322581 13.068093230 1.130680932
+5.645161290 1.580645161 13.068093230 1.130680932
+5.645161290 1.870967742 13.068093230 1.130680932
+5.645161290 2.161290323 13.068093230 1.130680932
+5.645161290 2.451612903 13.068093230 1.130680932
+5.645161290 2.741935484 13.068093230 1.130680932
+5.645161290 3.032258065 13.153230669 1.131532307
+5.645161290 3.322580645 13.696138923 1.136961389
+5.645161290 3.612903226 14.120187657 1.141201877
+5.645161290 3.903225806 14.489540684 1.144895407
+5.645161290 4.193548387 14.824425958 1.148244260
+5.645161290 4.483870968 15.137036426 1.151370364
+5.645161290 4.774193548 15.435976637 1.154359766
+5.645161290 5.064516129 15.727608429 1.157276084
+5.645161290 5.354838710 16.017791161 1.160177912
+5.645161290 5.645161290 16.311598605 1.163115986
+5.645161290 5.935483871 16.613732570 1.166137326
+5.645161290 6.225806452 16.933994986 1.169339950
+5.645161290 6.516129032 17.286819066 1.172868191
+5.645161290 6.806451613 17.700020869 1.177000209
+5.645161290 7.096774194 18.068098179 1.180680982
+5.645161290 7.387096774 18.068098179 1.180680982
+5.645161290 7.677419355 18.068098179 1.180680982
+5.645161290 7.967741935 18.068098179 1.180680982
+5.645161290 8.258064516 18.068098179 1.180680982
+5.645161290 8.548387097 18.068098179 1.180680982
+5.645161290 8.838709677 18.068098179 1.180680982
+5.645161290 9.129032258 18.068098179 1.180680982
+5.645161290 9.419354839 18.068098179 1.180680982
+5.645161290 9.709677419 18.068098179 1.180680982
+5.645161290 10.000000000 18.068098179 1.180680982
+5.935483871 1.000000000 13.350561957 1.133505620
+5.935483871 1.290322581 13.350561957 1.133505620
+5.935483871 1.580645161 13.350561957 1.133505620
+5.935483871 1.870967742 13.350561957 1.133505620
+5.935483871 2.161290323 13.350561957 1.133505620
+5.935483871 2.451612903 13.350561957 1.133505620
+5.935483871 2.741935484 13.350561957 1.133505620
+5.935483871 3.032258065 13.438880990 1.134388810
+5.935483871 3.322580645 14.000777693 1.140007777
+5.935483871 3.612903226 14.435371678 1.144353717
+5.935483871 3.903225806 14.809822020 1.148098220
+5.935483871 4.193548387 15.146110946 1.151461109
+5.935483871 4.483870968 15.457098960 1.154570990
+5.935483871 4.774193548 15.753650335 1.157536503
+5.935483871 5.064516129 16.040918075 1.160409181
+5.935483871 5.354838710 16.325903819 1.163259038
+5.935483871 5.645161290 16.613732570 1.166137326
+5.935483871 5.935483871 16.911019483 1.169110195
+5.935483871 6.225806452 17.225563024 1.172255630
+5.935483871 6.516129032 17.572635415 1.175726354
+5.935483871 6.806451613 17.982106473 1.179821065
+5.935483871 7.096774194 18.349962605 1.183499626
+5.935483871 7.387096774 18.349962605 1.183499626
+5.935483871 7.677419355 18.349962605 1.183499626
+5.935483871 7.967741935 18.349962605 1.183499626
+5.935483871 8.258064516 18.349962605 1.183499626
+5.935483871 8.548387097 18.349962605 1.183499626
+5.935483871 8.838709677 18.349962605 1.183499626
+5.935483871 9.129032258 18.349962605 1.183499626
+5.935483871 9.419354839 18.349962605 1.183499626
+5.935483871 9.709677419 18.349962605 1.183499626
+5.935483871 10.000000000 18.349962605 1.183499626
+6.225806452 1.000000000 13.666570669 1.136665707
+6.225806452 1.290322581 13.666570669 1.136665707
+6.225806452 1.580645161 13.666570669 1.136665707
+6.225806452 1.870967742 13.666570669 1.136665707
+6.225806452 2.161290323 13.666570669 1.136665707
+6.225806452 2.451612903 13.666570669 1.136665707
+6.225806452 2.741935484 13.666570669 1.136665707
+6.225806452 3.032258065 13.759265462 1.137592655
+6.225806452 3.322580645 14.342258539 1.143422585
+6.225806452 3.612903226 14.784914127 1.147849141
+6.225806452 3.903225806 15.160748839 1.151607488
+6.225806452 4.193548387 15.495840162 1.154958402
+6.225806452 4.483870968 15.803334671 1.158033347
+6.225806452 4.774193548 16.094398574 1.160943986
+6.225806452 5.064516129 16.374971626 1.163749716
+6.225806452 5.354838710 16.653358486 1.166533585
+6.225806452 5.645161290 16.933994986 1.169339950
+6.225806452 5.935483871 17.225563024 1.172255630
+6.225806452 6.225806452 17.536694601 1.175366946
+6.225806452 6.516129032 17.882140340 1.178821403
+6.225806452 6.806451613 18.292111531 1.182921115
+6.225806452 7.096774194 18.667017714 1.186670177
+6.225806452 7.387096774 18.667017714 1.186670177
+6.225806452 7.677419355 18.667017714 1.186670177
+6.225806452 7.967741935 18.667017714 1.186670177
+6.225806452 8.258064516 18.667017714 1.186670177
+6.225806452 8.548387097 18.667017714 1.186670177
+6.225806452 8.838709677 18.667017714 1.186670177
+6.225806452 9.129032258 18.667017714 1.186670177
+6.225806452 9.419354839 18.667017714 1.186670177
+6.225806452 9.709677419 18.667017714 1.186670177
+6.225806452 10.000000000 18.667017714 1.186670177
+6.516129032 1.000000000 14.042124914 1.140421249
+6.516129032 1.290322581 14.042124914 1.140421249
+6.516129032 1.580645161 14.042124914 1.140421249
+6.516129032 1.870967742 14.042124914 1.140421249
+6.516129032 2.161290323 14.042124914 1.140421249
+6.516129032 2.451612903 14.042124914 1.140421249
+6.516129032 2.741935484 14.042124914 1.140421249
+6.516129032 3.032258065 14.139344845 1.141393448
+6.516129032 3.322580645 14.739964250 1.147399642
+6.516129032 3.612903226 15.187004870 1.151870049
+6.516129032 3.903225806 15.560871420 1.155608714
+6.516129032 4.193548387 15.889898831 1.158898988
+6.516129032 4.483870968 16.189645887 1.161896459
+6.516129032 4.774193548 16.472016458 1.164720165
+6.516129032 5.064516129 16.743479696 1.167434797
+6.516129032 5.354838710 17.013348713 1.170133487
+6.516129032 5.645161290 17.286819066 1.172868191
+6.516129032 5.935483871 17.572635415 1.175726354
+6.516129032 6.225806452 17.882140340 1.178821403
+6.516129032 6.516129032 18.229995875 1.182299959
+6.516129032 6.806451613 18.651088969 1.186510890
+6.516129032 7.096774194 19.041899081 1.190418991
+6.516129032 7.387096774 19.041899081 1.190418991
+6.516129032 7.677419355 19.041899081 1.190418991
+6.516129032 7.967741935 19.041899081 1.190418991
+6.516129032 8.258064516 19.041899081 1.190418991
+6.516129032 8.548387097 19.041899081 1.190418991
+6.516129032 8.838709677 19.041899081 1.190418991
+6.516129032 9.129032258 19.041899081 1.190418991
+6.516129032 9.419354839 19.041899081 1.190418991
+6.516129032 9.709677419 19.041899081 1.190418991
+6.516129032 10.000000000 19.041899081 1.190418991
+6.806451613 1.000000000 14.524928709 1.145249287
+6.806451613 1.290322581 14.524928709 1.145249287
+6.806451613 1.580645161 14.524928709 1.145249287
+6.806451613 1.870967742 14.524928709 1.145249287
+6.806451613 2.161290323 14.524928709 1.145249287
+6.806451613 2.451612903 14.524928709 1.145249287
+6.806451613 2.741935484 14.524928709 1.145249287
+6.806451613 3.032258065 14.626746497 1.146267465
+6.806451613 3.322580645 15.239164015 1.152391640
+6.806451613 3.612903226 15.681548005 1.156815480
+6.806451613 3.903225806 16.043900181 1.160439002
+6.806451613 4.193548387 16.360710958 1.163607110
+6.806451613 4.483870968 16.646502949 1.166465029
+6.806451613 4.774193548 16.915328759 1.169153288
+6.806451613 5.064516129 17.175031887 1.171750319
+6.806451613 5.354838710 17.434097089 1.174340971
+6.806451613 5.645161290 17.700020869 1.177000209
+6.806451613 5.935483871 17.982106473 1.179821065
+6.806451613 6.225806452 18.292111531 1.182921115
+6.806451613 6.516129032 18.651088969 1.186510890
+6.806451613 6.806451613 19.098880252 1.190988803
+6.806451613 7.096774194 19.524964154 1.195249642
+6.806451613 7.387096774 19.524964154 1.195249642
+6.806451613 7.677419355 19.524964154 1.195249642
+6.806451613 7.967741935 19.524964154 1.195249642
+6.806451613 8.258064516 19.524964154 1.195249642
+6.806451613 8.548387097 19.524964154 1.195249642
+6.806451613 8.838709677 19.524964154 1.195249642
+6.806451613 9.129032258 19.524964154 1.195249642
+6.806451613 9.419354839 19.524964154 1.195249642
+6.806451613 9.709677419 19.524964154 1.195249642
+6.806451613 10.000000000 19.524964154 1.195249642
+7.096774194 1.000000000 15.000000000 1.150000000
+7.096774194 1.290322581 15.000000000 1.150000000
+7.096774194 1.580645161 15.000000000 1.150000000
+7.096774194 1.870967742 15.000000000 1.150000000
+7.096774194 2.161290323 15.000000000 1.150000000
+7.096774194 2.451612903 15.000000000 1.150000000
+7.096774194 2.741935484 15.000000000 1.150000000
+7.096774194 3.032258065 15.103574890 1.151035749
+7.096774194 3.322580645 15.708449495 1.157084495
+7.096774194 3.612903226 16.133823742 1.161338237
+7.096774194 3.903225806 16.479227686 1.164792277
+7.096774194 4.193548387 16.778452741 1.167784527
+7.096774194 4.483870968 17.050023823 1.170500238
+7.096774194 4.774193548 17.305719073 1.173057191
+7.096774194 5.064516129 17.555546435 1.175555464
+7.096774194 5.354838710 17.806398651 1.178063987
+7.096774194 5.645161290 18.068098179 1.180680982
+7.096774194 5.935483871 18.349962605 1.183499626
+7.096774194 6.225806452 18.667017714 1.186670177
+7.096774194 6.516129032 19.041899081 1.190418991
+7.096774194 6.806451613 19.524964154 1.195249642
+7.096774194 7.096774194 19.999997043 1.199999970
+7.096774194 7.387096774 19.999997043 1.199999970
+7.096774194 7.677419355 19.999997043 1.199999970
+7.096774194 7.967741935 19.999997043 1.199999970
+7.096774194 8.258064516 19.999997043 1.199999970
+7.096774194 8.548387097 19.999997043 1.199999970
+7.096774194 8.838709677 19.999997043 1.199999970
+7.096774194 9.129032258 19.999997043 1.199999970
+7.096774194 9.419354839 19.999997043 1.199999970
+7.096774194 9.709677419 19.999997043 1.199999970
+7.096774194 10.000000000 19.999997043 1.199999970
+7.387096774 1.000000000 15.000000000 1.150000000
+7.387096774 1.290322581 15.000000000 1.150000000
+7.387096774 1.580645161 15.000000000 1.150000000
+7.387096774 1.870967742 15.000000000 1.150000000
+7.387096774 2.161290323 15.000000000 1.150000000
+7.387096774 2.451612903 15.000000000 1.150000000
+7.387096774 2.741935484 15.000000000 1.150000000
+7.387096774 3.032258065 15.103574890 1.151035749
+7.387096774 3.322580645 15.708449495 1.157084495
+7.387096774 3.612903226 16.133823742 1.161338237
+7.387096774 3.903225806 16.479227686 1.164792277
+7.387096774 4.193548387 16.778452741 1.167784527
+7.387096774 4.483870968 17.050023823 1.170500238
+7.387096774 4.774193548 17.305719073 1.173057191
+7.387096774 5.064516129 17.555546435 1.175555464
+7.387096774 5.354838710 17.806398651 1.178063987
+7.387096774 5.645161290 18.068098179 1.180680982
+7.387096774 5.935483871 18.349962605 1.183499626
+7.387096774 6.225806452 18.667017714 1.186670177
+7.387096774 6.516129032 19.041899081 1.190418991
+7.387096774 6.806451613 19.524964154 1.195249642
+7.387096774 7.096774194 19.999997043 1.199999970
+7.387096774 7.387096774 19.999997043 1.199999970
+7.387096774 7.677419355 19.999997043 1.199999970
+7.387096774 7.967741935 19.999997043 1.199999970
+7.387096774 8.258064516 19.999997043 1.199999970
+7.387096774 8.548387097 19.999997043 1.199999970
+7.387096774 8.838709677 19.999997043 1.199999970
+7.387096774 9.129032258 19.999997043 1.199999970
+7.387096774 9.419354839 19.999997043 1.199999970
+7.387096774 9.709677419 19.999997043 1.199999970
+7.387096774 10.000000000 19.999997043 1.199999970
+7.677419355 1.000000000 15.000000000 1.150000000
+7.677419355 1.290322581 15.000000000 1.150000000
+7.677419355 1.580645161 15.000000000 1.150000000
+7.677419355 1.870967742 15.000000000 1.150000000
+7.677419355 2.161290323 15.000000000 1.150000000
+7.677419355 2.451612903 15.000000000 1.150000000
+7.677419355 2.741935484 15.000000000 1.150000000
+7.677419355 3.032258065 15.103574890 1.151035749
+7.677419355 3.322580645 15.708449495 1.157084495
+7.677419355 3.612903226 16.133823742 1.161338237
+7.677419355 3.903225806 16.479227686 1.164792277
+7.677419355 4.193548387 16.778452741 1.167784527
+7.677419355 4.483870968 17.050023823 1.170500238
+7.677419355 4.774193548 17.305719073 1.173057191
+7.677419355 5.064516129 17.555546435 1.175555464
+7.677419355 5.354838710 17.806398651 1.178063987
+7.677419355 5.645161290 18.068098179 1.180680982
+7.677419355 5.935483871 18.349962605 1.183499626
+7.677419355 6.225806452 18.667017714 1.186670177
+7.677419355 6.516129032 19.041899081 1.190418991
+7.677419355 6.806451613 19.524964154 1.195249642
+7.677419355 7.096774194 19.999997043 1.199999970
+7.677419355 7.387096774 19.999997043 1.199999970
+7.677419355 7.677419355 19.999997043 1.199999970
+7.677419355 7.967741935 19.999997043 1.199999970
+7.677419355 8.258064516 19.999997043 1.199999970
+7.677419355 8.548387097 19.999997043 1.199999970
+7.677419355 8.838709677 19.999997043 1.199999970
+7.677419355 9.129032258 19.999997043 1.199999970
+7.677419355 9.419354839 19.999997043 1.199999970
+7.677419355 9.709677419 19.999997043 1.199999970
+7.677419355 10.000000000 19.999997043 1.199999970
+7.967741935 1.000000000 15.000000000 1.150000000
+7.967741935 1.290322581 15.000000000 1.150000000
+7.967741935 1.580645161 15.000000000 1.150000000
+7.967741935 1.870967742 15.000000000 1.150000000
+7.967741935 2.161290323 15.000000000 1.150000000
+7.967741935 2.451612903 15.000000000 1.150000000
+7.967741935 2.741935484 15.000000000 1.150000000
+7.967741935 3.032258065 15.103574890 1.151035749
+7.967741935 3.322580645 15.708449495 1.157084495
+7.967741935 3.612903226 16.133823742 1.161338237
+7.967741935 3.903225806 16.479227686 1.164792277
+7.967741935 4.193548387 16.778452741 1.167784527
+7.967741935 4.483870968 17.050023823 1.170500238
+7.967741935 4.774193548 17.305719073 1.173057191
+7.967741935 5.064516129 17.555546435 1.175555464
+7.967741935 5.354838710 17.806398651 1.178063987
+7.967741935 5.645161290 18.068098179 1.180680982
+7.967741935 5.935483871 18.349962605 1.183499626
+7.967741935 6.225806452 18.667017714 1.186670177
+7.967741935 6.516129032 19.041899081 1.190418991
+7.967741935 6.806451613 19.524964154 1.195249642
+7.967741935 7.096774194 19.999997043 1.199999970
+7.967741935 7.387096774 19.999997043 1.199999970
+7.967741935 7.677419355 19.999997043 1.199999970
+7.967741935 7.967741935 19.999997043 1.199999970
+7.967741935 8.258064516 19.999997043 1.199999970
+7.967741935 8.548387097 19.999997043 1.199999970
+7.967741935 8.838709677 19.999997043 1.199999970
+7.967741935 9.129032258 19.999997043 1.199999970
+7.967741935 9.419354839 19.999997043 1.199999970
+7.967741935 9.709677419 19.999997043 1.199999970
+7.967741935 10.000000000 19.999997043 1.199999970
+8.258064516 1.000000000 15.000000000 1.150000000
+8.258064516 1.290322581 15.000000000 1.150000000
+8.258064516 1.580645161 15.000000000 1.150000000
+8.258064516 1.870967742 15.000000000 1.150000000
+8.258064516 2.161290323 15.000000000 1.150000000
+8.258064516 2.451612903 15.000000000 1.150000000
+8.258064516 2.741935484 15.000000000 1.150000000
+8.258064516 3.032258065 15.103574890 1.151035749
+8.258064516 3.322580645 15.708449495 1.157084495
+8.258064516 3.612903226 16.133823742 1.161338237
+8.258064516 3.903225806 16.479227686 1.164792277
+8.258064516 4.193548387 16.778452741 1.167784527
+8.258064516 4.483870968 17.050023823 1.170500238
+8.258064516 4.774193548 17.305719073 1.173057191
+8.258064516 5.064516129 17.555546435 1.175555464
+8.258064516 5.354838710 17.806398651 1.178063987
+8.258064516 5.645161290 18.068098179 1.180680982
+8.258064516 5.935483871 18.349962605 1.183499626
+8.258064516 6.225806452 18.667017714 1.186670177
+8.258064516 6.516129032 19.041899081 1.190418991
+8.258064516 6.806451613 19.524964154 1.195249642
+8.258064516 7.096774194 19.999997043 1.199999970
+8.258064516 7.387096774 19.999997043 1.199999970
+8.258064516 7.677419355 19.999997043 1.199999970
+8.258064516 7.967741935 19.999997043 1.199999970
+8.258064516 8.258064516 19.999997043 1.199999970
+8.258064516 8.548387097 19.999997043 1.199999970
+8.258064516 8.838709677 19.999997043 1.199999970
+8.258064516 9.129032258 19.999997043 1.199999970
+8.258064516 9.419354839 19.999997043 1.199999970
+8.258064516 9.709677419 19.999997043 1.199999970
+8.258064516 10.000000000 19.999997043 1.199999970
+8.548387097 1.000000000 15.000000000 1.150000000
+8.548387097 1.290322581 15.000000000 1.150000000
+8.548387097 1.580645161 15.000000000 1.150000000
+8.548387097 1.870967742 15.000000000 1.150000000
+8.548387097 2.161290323 15.000000000 1.150000000
+8.548387097 2.451612903 15.000000000 1.150000000
+8.548387097 2.741935484 15.000000000 1.150000000
+8.548387097 3.032258065 15.103574890 1.151035749
+8.548387097 3.322580645 15.708449495 1.157084495
+8.548387097 3.612903226 16.133823742 1.161338237
+8.548387097 3.903225806 16.479227686 1.164792277
+8.548387097 4.193548387 16.778452741 1.167784527
+8.548387097 4.483870968 17.050023823 1.170500238
+8.548387097 4.774193548 17.305719073 1.173057191
+8.548387097 5.064516129 17.555546435 1.175555464
+8.548387097 5.354838710 17.806398651 1.178063987
+8.548387097 5.645161290 18.068098179 1.180680982
+8.548387097 5.935483871 18.349962605 1.183499626
+8.548387097 6.225806452 18.667017714 1.186670177
+8.548387097 6.516129032 19.041899081 1.190418991
+8.548387097 6.806451613 19.524964154 1.195249642
+8.548387097 7.096774194 19.999997043 1.199999970
+8.548387097 7.387096774 19.999997043 1.199999970
+8.548387097 7.677419355 19.999997043 1.199999970
+8.548387097 7.967741935 19.999997043 1.199999970
+8.548387097 8.258064516 19.999997043 1.199999970
+8.548387097 8.548387097 19.999997043 1.199999970
+8.548387097 8.838709677 19.999997043 1.199999970
+8.548387097 9.129032258 19.999997043 1.199999970
+8.548387097 9.419354839 19.999997043 1.199999970
+8.548387097 9.709677419 19.999997043 1.199999970
+8.548387097 10.000000000 19.999997043 1.199999970
+8.838709677 1.000000000 15.000000000 1.150000000
+8.838709677 1.290322581 15.000000000 1.150000000
+8.838709677 1.580645161 15.000000000 1.150000000
+8.838709677 1.870967742 15.000000000 1.150000000
+8.838709677 2.161290323 15.000000000 1.150000000
+8.838709677 2.451612903 15.000000000 1.150000000
+8.838709677 2.741935484 15.000000000 1.150000000
+8.838709677 3.032258065 15.103574890 1.151035749
+8.838709677 3.322580645 15.708449495 1.157084495
+8.838709677 3.612903226 16.133823742 1.161338237
+8.838709677 3.903225806 16.479227686 1.164792277
+8.838709677 4.193548387 16.778452741 1.167784527
+8.838709677 4.483870968 17.050023823 1.170500238
+8.838709677 4.774193548 17.305719073 1.173057191
+8.838709677 5.064516129 17.555546435 1.175555464
+8.838709677 5.354838710 17.806398651 1.178063987
+8.838709677 5.645161290 18.068098179 1.180680982
+8.838709677 5.935483871 18.349962605 1.183499626
+8.838709677 6.225806452 18.667017714 1.186670177
+8.838709677 6.516129032 19.041899081 1.190418991
+8.838709677 6.806451613 19.524964154 1.195249642
+8.838709677 7.096774194 19.999997043 1.199999970
+8.838709677 7.387096774 19.999997043 1.199999970
+8.838709677 7.677419355 19.999997043 1.199999970
+8.838709677 7.967741935 19.999997043 1.199999970
+8.838709677 8.258064516 19.999997043 1.199999970
+8.838709677 8.548387097 19.999997043 1.199999970
+8.838709677 8.838709677 19.999997043 1.199999970
+8.838709677 9.129032258 19.999997043 1.199999970
+8.838709677 9.419354839 19.999997043 1.199999970
+8.838709677 9.709677419 19.999997043 1.199999970
+8.838709677 10.000000000 19.999997043 1.199999970
+9.129032258 1.000000000 15.000000000 1.150000000
+9.129032258 1.290322581 15.000000000 1.150000000
+9.129032258 1.580645161 15.000000000 1.150000000
+9.129032258 1.870967742 15.000000000 1.150000000
+9.129032258 2.161290323 15.000000000 1.150000000
+9.129032258 2.451612903 15.000000000 1.150000000
+9.129032258 2.741935484 15.000000000 1.150000000
+9.129032258 3.032258065 15.103574890 1.151035749
+9.129032258 3.322580645 15.708449495 1.157084495
+9.129032258 3.612903226 16.133823742 1.161338237
+9.129032258 3.903225806 16.479227686 1.164792277
+9.129032258 4.193548387 16.778452741 1.167784527
+9.129032258 4.483870968 17.050023823 1.170500238
+9.129032258 4.774193548 17.305719073 1.173057191
+9.129032258 5.064516129 17.555546435 1.175555464
+9.129032258 5.354838710 17.806398651 1.178063987
+9.129032258 5.645161290 18.068098179 1.180680982
+9.129032258 5.935483871 18.349962605 1.183499626
+9.129032258 6.225806452 18.667017714 1.186670177
+9.129032258 6.516129032 19.041899081 1.190418991
+9.129032258 6.806451613 19.524964154 1.195249642
+9.129032258 7.096774194 19.999997043 1.199999970
+9.129032258 7.387096774 19.999997043 1.199999970
+9.129032258 7.677419355 19.999997043 1.199999970
+9.129032258 7.967741935 19.999997043 1.199999970
+9.129032258 8.258064516 19.999997043 1.199999970
+9.129032258 8.548387097 19.999997043 1.199999970
+9.129032258 8.838709677 19.999997043 1.199999970
+9.129032258 9.129032258 19.999997043 1.199999970
+9.129032258 9.419354839 19.999997043 1.199999970
+9.129032258 9.709677419 19.999997043 1.199999970
+9.129032258 10.000000000 19.999997043 1.199999970
+9.419354839 1.000000000 15.000000000 1.150000000
+9.419354839 1.290322581 15.000000000 1.150000000
+9.419354839 1.580645161 15.000000000 1.150000000
+9.419354839 1.870967742 15.000000000 1.150000000
+9.419354839 2.161290323 15.000000000 1.150000000
+9.419354839 2.451612903 15.000000000 1.150000000
+9.419354839 2.741935484 15.000000000 1.150000000
+9.419354839 3.032258065 15.103574890 1.151035749
+9.419354839 3.322580645 15.708449495 1.157084495
+9.419354839 3.612903226 16.133823742 1.161338237
+9.419354839 3.903225806 16.479227686 1.164792277
+9.419354839 4.193548387 16.778452741 1.167784527
+9.419354839 4.483870968 17.050023823 1.170500238
+9.419354839 4.774193548 17.305719073 1.173057191
+9.419354839 5.064516129 17.555546435 1.175555464
+9.419354839 5.354838710 17.806398651 1.178063987
+9.419354839 5.645161290 18.068098179 1.180680982
+9.419354839 5.935483871 18.349962605 1.183499626
+9.419354839 6.225806452 18.667017714 1.186670177
+9.419354839 6.516129032 19.041899081 1.190418991
+9.419354839 6.806451613 19.524964154 1.195249642
+9.419354839 7.096774194 19.999997043 1.199999970
+9.419354839 7.387096774 19.999997043 1.199999970
+9.419354839 7.677419355 19.999997043 1.199999970
+9.419354839 7.967741935 19.999997043 1.199999970
+9.419354839 8.258064516 19.999997043 1.199999970
+9.419354839 8.548387097 19.999997043 1.199999970
+9.419354839 8.838709677 19.999997043 1.199999970
+9.419354839 9.129032258 19.999997043 1.199999970
+9.419354839 9.419354839 19.999997043 1.199999970
+9.419354839 9.709677419 19.999997043 1.199999970
+9.419354839 10.000000000 19.999997043 1.199999970
+9.709677419 1.000000000 15.000000000 1.150000000
+9.709677419 1.290322581 15.000000000 1.150000000
+9.709677419 1.580645161 15.000000000 1.150000000
+9.709677419 1.870967742 15.000000000 1.150000000
+9.709677419 2.161290323 15.000000000 1.150000000
+9.709677419 2.451612903 15.000000000 1.150000000
+9.709677419 2.741935484 15.000000000 1.150000000
+9.709677419 3.032258065 15.103574890 1.151035749
+9.709677419 3.322580645 15.708449495 1.157084495
+9.709677419 3.612903226 16.133823742 1.161338237
+9.709677419 3.903225806 16.479227686 1.164792277
+9.709677419 4.193548387 16.778452741 1.167784527
+9.709677419 4.483870968 17.050023823 1.170500238
+9.709677419 4.774193548 17.305719073 1.173057191
+9.709677419 5.064516129 17.555546435 1.175555464
+9.709677419 5.354838710 17.806398651 1.178063987
+9.709677419 5.645161290 18.068098179 1.180680982
+9.709677419 5.935483871 18.349962605 1.183499626
+9.709677419 6.225806452 18.667017714 1.186670177
+9.709677419 6.516129032 19.041899081 1.190418991
+9.709677419 6.806451613 19.524964154 1.195249642
+9.709677419 7.096774194 19.999997043 1.199999970
+9.709677419 7.387096774 19.999997043 1.199999970
+9.709677419 7.677419355 19.999997043 1.199999970
+9.709677419 7.967741935 19.999997043 1.199999970
+9.709677419 8.258064516 19.999997043 1.199999970
+9.709677419 8.548387097 19.999997043 1.199999970
+9.709677419 8.838709677 19.999997043 1.199999970
+9.709677419 9.129032258 19.999997043 1.199999970
+9.709677419 9.419354839 19.999997043 1.199999970
+9.709677419 9.709677419 19.999997043 1.199999970
+9.709677419 10.000000000 19.999997043 1.199999970
+10.000000000 1.000000000 15.000000000 1.150000000
+10.000000000 1.290322581 15.000000000 1.150000000
+10.000000000 1.580645161 15.000000000 1.150000000
+10.000000000 1.870967742 15.000000000 1.150000000
+10.000000000 2.161290323 15.000000000 1.150000000
+10.000000000 2.451612903 15.000000000 1.150000000
+10.000000000 2.741935484 15.000000000 1.150000000
+10.000000000 3.032258065 15.103574890 1.151035749
+10.000000000 3.322580645 15.708449495 1.157084495
+10.000000000 3.612903226 16.133823742 1.161338237
+10.000000000 3.903225806 16.479227686 1.164792277
+10.000000000 4.193548387 16.778452741 1.167784527
+10.000000000 4.483870968 17.050023823 1.170500238
+10.000000000 4.774193548 17.305719073 1.173057191
+10.000000000 5.064516129 17.555546435 1.175555464
+10.000000000 5.354838710 17.806398651 1.178063987
+10.000000000 5.645161290 18.068098179 1.180680982
+10.000000000 5.935483871 18.349962605 1.183499626
+10.000000000 6.225806452 18.667017714 1.186670177
+10.000000000 6.516129032 19.041899081 1.190418991
+10.000000000 6.806451613 19.524964154 1.195249642
+10.000000000 7.096774194 19.999997043 1.199999970
+10.000000000 7.387096774 19.999997043 1.199999970
+10.000000000 7.677419355 19.999997043 1.199999970
+10.000000000 7.967741935 19.999997043 1.199999970
+10.000000000 8.258064516 19.999997043 1.199999970
+10.000000000 8.548387097 19.999997043 1.199999970
+10.000000000 8.838709677 19.999997043 1.199999970
+10.000000000 9.129032258 19.999997043 1.199999970
+10.000000000 9.419354839 19.999997043 1.199999970
+10.000000000 9.709677419 19.999997043 1.199999970
+10.000000000 10.000000000 19.999997043 1.199999970
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.fll b/examples/mamdani/octave/mamdani_tip_calculator.fll
new file mode 100644
index 0000000..516d870
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.fll
@@ -0,0 +1,45 @@
+Engine: mamdani_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: Tip
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: AlgebraicSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: AboutTenPercent Gaussian 10.000 2.000
+ term: AboutFifteenPercent Gaussian 15.000 2.000
+ term: AboutTwentyPercent Gaussian 20.000 2.000
+OutputVariable: CheckPlusTip
+ enabled: true
+ range: 1.000 1.300
+ lock-range: false
+ aggregation: AlgebraicSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: PlusAboutTenPercent Gaussian 1.100 0.020
+ term: PlusAboutFifteenPercent Gaussian 1.150 0.020
+ term: PlusAboutTwentyPercent Gaussian 1.200 0.020
+RuleBlock:
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if FoodQuality is Bad and Service is Bad then Tip is AboutTenPercent and CheckPlusTip is PlusAboutTenPercent
+ rule: if FoodQuality is Bad and Service is Good then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ rule: if FoodQuality is Good and Service is Bad then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ rule: if FoodQuality is Good and Service is Good then Tip is AboutTwentyPercent and CheckPlusTip is PlusAboutTwentyPercent \ No newline at end of file
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.java b/examples/mamdani/octave/mamdani_tip_calculator.java
new file mode 100644
index 0000000..faea466
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.java
@@ -0,0 +1,88 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class mamdani_tip_calculator{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("mamdani_tip_calculator");
+engine.setDescription("");
+
+InputVariable FoodQuality = new InputVariable();
+FoodQuality.setName("FoodQuality");
+FoodQuality.setDescription("");
+FoodQuality.setEnabled(true);
+FoodQuality.setRange(1.000, 10.000);
+FoodQuality.setLockValueInRange(false);
+FoodQuality.addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+FoodQuality.addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine.addInputVariable(FoodQuality);
+
+InputVariable Service = new InputVariable();
+Service.setName("Service");
+Service.setDescription("");
+Service.setEnabled(true);
+Service.setRange(1.000, 10.000);
+Service.setLockValueInRange(false);
+Service.addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+Service.addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine.addInputVariable(Service);
+
+OutputVariable Tip = new OutputVariable();
+Tip.setName("Tip");
+Tip.setDescription("");
+Tip.setEnabled(true);
+Tip.setRange(0.000, 30.000);
+Tip.setLockValueInRange(false);
+Tip.setAggregation(new AlgebraicSum());
+Tip.setDefuzzifier(new Centroid(200));
+Tip.setDefaultValue(Double.NaN);
+Tip.setLockPreviousValue(false);
+Tip.addTerm(new Gaussian("AboutTenPercent", 10.000, 2.000));
+Tip.addTerm(new Gaussian("AboutFifteenPercent", 15.000, 2.000));
+Tip.addTerm(new Gaussian("AboutTwentyPercent", 20.000, 2.000));
+engine.addOutputVariable(Tip);
+
+OutputVariable CheckPlusTip = new OutputVariable();
+CheckPlusTip.setName("CheckPlusTip");
+CheckPlusTip.setDescription("");
+CheckPlusTip.setEnabled(true);
+CheckPlusTip.setRange(1.000, 1.300);
+CheckPlusTip.setLockValueInRange(false);
+CheckPlusTip.setAggregation(new AlgebraicSum());
+CheckPlusTip.setDefuzzifier(new Centroid(200));
+CheckPlusTip.setDefaultValue(Double.NaN);
+CheckPlusTip.setLockPreviousValue(false);
+CheckPlusTip.addTerm(new Gaussian("PlusAboutTenPercent", 1.100, 0.020));
+CheckPlusTip.addTerm(new Gaussian("PlusAboutFifteenPercent", 1.150, 0.020));
+CheckPlusTip.addTerm(new Gaussian("PlusAboutTwentyPercent", 1.200, 0.020));
+engine.addOutputVariable(CheckPlusTip);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new AlgebraicProduct());
+ruleBlock.setDisjunction(new Maximum());
+ruleBlock.setImplication(new Minimum());
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if FoodQuality is Bad and Service is Bad then Tip is AboutTenPercent and CheckPlusTip is PlusAboutTenPercent", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Bad and Service is Good then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is Bad then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is Good then Tip is AboutTwentyPercent and CheckPlusTip is PlusAboutTwentyPercent", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/mamdani/octave/mamdani_tip_calculator.pdf b/examples/mamdani/octave/mamdani_tip_calculator.pdf
new file mode 100644
index 0000000..d62a142
--- /dev/null
+++ b/examples/mamdani/octave/mamdani_tip_calculator.pdf
Binary files differ
diff --git a/examples/original/mamdani/AllTerms.fis b/examples/original/mamdani/AllTerms.fis
new file mode 100644
index 0000000..04a36f1
--- /dev/null
+++ b/examples/original/mamdani/AllTerms.fis
@@ -0,0 +1,84 @@
+[System]
+Name='qtfuzzylite'
+Type='mamdani'
+NumInputs=1
+NumOutputs=1
+NumRules=16
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='AllInputTerms'
+Range=[0.000 6.500]
+NumMFs=20
+MF1='A':'sigmf',[-20.000 0.500]
+MF2='B':'zmf',[0.000 1.000]
+MF3='C':'rampmf',[1.000 0.000]
+MF4='D':'trimf',[0.500 1.000 1.500]
+MF5='E':'trapmf',[1.000 1.250 1.750 2.000]
+MF6='F':'concavemf',[0.850 0.250]
+MF7='G':'rectmf',[1.750 2.250]
+MF8='H':'discretemf',[2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000]
+MF9='I':'gaussmf',[0.200 3.000]
+MF10='J':'cosinemf',[3.250 0.650]
+MF11='K':'gauss2mf',[0.100 3.500 0.300 3.300]
+MF12='L':'spikemf',[3.640 1.040]
+MF13='M':'gbellmf',[0.250 3.000 4.000]
+MF14='N':'pimf',[4.000 4.500 4.500 5.000]
+MF15='O':'concavemf',[5.650 6.250]
+MF16='P':'dsigmf',[10.000 4.750 30.000 5.250]
+MF17='Q':'psigmf',[20.000 5.250 -10.000 5.750]
+MF18='R':'rampmf',[5.500 6.500]
+MF19='S':'smf',[5.500 6.500]
+MF20='T':'sigmf',[20.000 6.000]
+
+[Output1]
+Name='AllOutputTerms'
+Range=[0.000 6.500]
+NumMFs=16
+MF1='A':'sigmf',[-20.000 0.500]
+MF2='B':'zmf',[0.000 1.000]
+MF3='C':'rampmf',[1.000 0.000]
+MF4='D':'trimf',[0.500 1.000 1.500]
+MF5='E':'trapmf',[1.000 1.250 1.750 2.000]
+MF6='F':'concavemf',[0.850 0.250]
+MF7='G':'rectmf',[1.750 2.250]
+MF8='H':'discretemf',[2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000]
+MF9='I':'gaussmf',[0.200 3.000]
+MF10='J':'cosinemf',[3.250 0.650]
+MF11='K':'gauss2mf',[0.100 3.500 0.300 3.300]
+MF12='L':'spikemf',[3.640 1.040]
+MF13='M':'gbellmf',[0.250 3.000 4.000]
+MF14='N':'pimf',[4.000 4.500 4.500 5.000]
+MF15='O':'concavemf',[5.650 6.250]
+MF16='P':'dsigmf',[10.000 4.750 30.000 5.250]
+MF17='Q':'psigmf',[20.000 5.250 -10.000 5.750]
+MF18='R':'rampmf',[5.500 6.500]
+MF19='S':'smf',[5.500 6.500]
+MF20='T':'sigmf',[20.000 6.000]
+
+
+[Rules]
+1.000 , 20.000 (1.000) : 1
+2.000 , 19.000 (1.000) : 1
+3.000 , 18.000 (1.000) : 1
+4.000 , 17.000 (1.000) : 1
+5.000 , 16.000 (1.000) : 1
+6.000 , 15.000 (1.000) : 1
+7.000 , 14.000 (1.000) : 1
+8.000 , 13.000 (1.000) : 1
+9.000 , 12.000 (1.000) : 1
+10.000 , 11.000 (1.000) : 1
+11.000 , 10.000 (1.000) : 1
+12.000 , 9.000 (1.000) : 1
+13.000 , 8.000 (1.000) : 1
+14.000 , 7.000 (1.000) : 1
+15.000 , 6.000 (1.000) : 1
+16.000 , 5.000 (1.000) : 1
+17.000 , 4.000 (1.000) : 1
+18.000 , 3.000 (1.000) : 1
+19.000 , 2.000 (1.000) : 1
+20.000 , 1.000 (1.000) : 1
diff --git a/examples/original/mamdani/AllTerms.fll b/examples/original/mamdani/AllTerms.fll
new file mode 100644
index 0000000..bed89c8
--- /dev/null
+++ b/examples/original/mamdani/AllTerms.fll
@@ -0,0 +1,78 @@
+Engine: AllTerms
+InputVariable: AllInputTerms
+ enabled: true
+ range: 0.000 6.500
+ term: A Sigmoid 0.500 -20.000
+ term: B ZShape 0.000 1.000
+ term: C Ramp 1.000 0.000
+ term: D Triangle 0.500 1.000 1.500
+ term: E Trapezoid 1.000 1.250 1.750 2.000
+ term: F Concave 0.850 0.250
+ term: G Rectangle 1.750 2.250
+ term: H Discrete 2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000
+ term: I Gaussian 3.000 0.200
+ term: J Cosine 3.250 0.650
+ term: K GaussianProduct 3.500 0.100 3.300 0.300
+ term: L Spike 3.640 1.040
+ term: M Bell 4.000 0.250 3.000
+ term: N PiShape 4.000 4.500 4.500 5.000
+ term: O Concave 5.650 6.250
+ term: P SigmoidDifference 4.750 10.000 30.000 5.250
+ term: Q SigmoidProduct 5.250 20.000 -10.000 5.750
+ term: R Ramp 5.500 6.500
+ term: S SShape 5.500 6.500
+ term: T Sigmoid 6.000 20.000
+OutputVariable: AllOutputTerms
+ enabled: true
+ range: 0.000 6.500
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: A Sigmoid 0.500 -20.000
+ term: B ZShape 0.000 1.000
+ term: C Ramp 1.000 0.000
+ term: D Triangle 0.500 1.000 1.500
+ term: E Trapezoid 1.000 1.250 1.750 2.000
+ term: F Concave 0.850 0.250
+ term: G Rectangle 1.750 2.250
+ term: H Discrete 2.000 0.000 2.250 1.000 2.500 0.500 2.750 1.000 3.000 0.000
+ term: I Gaussian 3.000 0.200
+ term: J Cosine 3.250 0.650
+ term: K GaussianProduct 3.500 0.100 3.300 0.300
+ term: L Spike 3.640 1.040
+ term: M Bell 4.000 0.250 3.000
+ term: N PiShape 4.000 4.500 4.500 5.000
+ term: O Concave 5.650 6.250
+ term: P SigmoidDifference 4.750 10.000 30.000 5.250
+ term: Q SigmoidProduct 5.250 20.000 -10.000 5.750
+ term: R Ramp 5.500 6.500
+ term: S SShape 5.500 6.500
+ term: T Sigmoid 6.000 20.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if AllInputTerms is A then AllOutputTerms is T
+ rule: if AllInputTerms is B then AllOutputTerms is S
+ rule: if AllInputTerms is C then AllOutputTerms is R
+ rule: if AllInputTerms is D then AllOutputTerms is Q
+ rule: if AllInputTerms is E then AllOutputTerms is P
+ rule: if AllInputTerms is F then AllOutputTerms is O
+ rule: if AllInputTerms is G then AllOutputTerms is N
+ rule: if AllInputTerms is H then AllOutputTerms is M
+ rule: if AllInputTerms is I then AllOutputTerms is L
+ rule: if AllInputTerms is J then AllOutputTerms is K
+ rule: if AllInputTerms is K then AllOutputTerms is J
+ rule: if AllInputTerms is L then AllOutputTerms is I
+ rule: if AllInputTerms is M then AllOutputTerms is H
+ rule: if AllInputTerms is N then AllOutputTerms is G
+ rule: if AllInputTerms is O then AllOutputTerms is F
+ rule: if AllInputTerms is P then AllOutputTerms is E
+ rule: if AllInputTerms is Q then AllOutputTerms is D
+ rule: if AllInputTerms is R then AllOutputTerms is C
+ rule: if AllInputTerms is S then AllOutputTerms is B
+ rule: if AllInputTerms is T then AllOutputTerms is A
diff --git a/examples/original/mamdani/Laundry.fll b/examples/original/mamdani/Laundry.fll
new file mode 100644
index 0000000..36e67d5
--- /dev/null
+++ b/examples/original/mamdani/Laundry.fll
@@ -0,0 +1,44 @@
+Engine: Laundry
+InputVariable: Load
+ enabled: true
+ range: 0.000 6.000
+ term: small Discrete 0.000 1.000 1.000 1.000 2.000 0.800 5.000 0.000
+ term: normal Discrete 3.000 0.000 4.000 1.000 6.000 0.000
+InputVariable: Dirt
+ enabled: true
+ range: 0.000 6.000
+ term: low Discrete 0.000 1.000 2.000 0.800 5.000 0.000
+ term: high Discrete 1.000 0.000 2.000 0.200 4.000 0.800 6.000 1.000
+OutputVariable: Detergent
+ enabled: true
+ range: 0.000 80.000
+ aggregation: Maximum
+ defuzzifier: MeanOfMaximum 500
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: less_than_usual Discrete 10.000 0.000 40.000 1.000 50.000 0.000
+ term: usual Discrete 40.000 0.000 50.000 1.000 60.000 1.000 80.000 0.000
+ term: more_than_usual Discrete 50.000 0.000 80.000 1.000
+OutputVariable: Cycle
+ enabled: true
+ range: 0.000 20.000
+ aggregation: Maximum
+ defuzzifier: MeanOfMaximum 500
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: short Discrete 0.000 1.000 10.000 1.000 20.000 0.000
+ term: long Discrete 10.000 0.000 20.000 1.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if Load is small and Dirt is not high then Detergent is less_than_usual
+ rule: if Load is small and Dirt is high then Detergent is usual
+ rule: if Load is normal and Dirt is low then Detergent is less_than_usual
+ rule: if Load is normal and Dirt is high then Detergent is more_than_usual
+ rule: if Detergent is usual or Detergent is less_than_usual then Cycle is short
+ rule: if Detergent is more_than_usual then Cycle is long
diff --git a/examples/original/mamdani/SimpleDimmer.fis b/examples/original/mamdani/SimpleDimmer.fis
new file mode 100644
index 0000000..d3d229a
--- /dev/null
+++ b/examples/original/mamdani/SimpleDimmer.fis
@@ -0,0 +1,39 @@
+[System]
+Name='simple-dimmer'
+Type='mamdani'
+Version=3.0
+NumInputs=1
+NumOutputs=1
+NumRules=3
+AndMethod=''
+OrMethod=''
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Ambient'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='DARK':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='BRIGHT':'trimf',[0.500 0.750 1.000]
+
+
+[Output1]
+Name='Power'
+Range=[0.000 1.000]
+Default=nan
+LockPrevious=0
+LockRange=0
+NumMFs=3
+MF1='LOW':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='HIGH':'trimf',[0.500 0.750 1.000]
+
+
+[Rules]
+1 , 3 (1) : 1
+2 , 2 (1) : 1
+3 , 1 (1) : 1
+
diff --git a/examples/original/mamdani/SimpleDimmer.fll b/examples/original/mamdani/SimpleDimmer.fll
new file mode 100644
index 0000000..ab91b72
--- /dev/null
+++ b/examples/original/mamdani/SimpleDimmer.fll
@@ -0,0 +1,27 @@
+Engine: SimpleDimmer
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
diff --git a/examples/original/mamdani/SimpleDimmerInverse.fll b/examples/original/mamdani/SimpleDimmerInverse.fll
new file mode 100644
index 0000000..3cd7a4a
--- /dev/null
+++ b/examples/original/mamdani/SimpleDimmerInverse.fll
@@ -0,0 +1,41 @@
+Engine: SimpleDimmerInverse
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: LOW Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: HIGH Triangle 0.500 0.750 1.000
+OutputVariable: InversePower
+ enabled: true
+ range: 0.000 1.000
+ aggregation: Maximum
+ defuzzifier: Centroid 500
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: LOW Cosine 0.200 0.500
+ term: MEDIUM Cosine 0.500 0.500
+ term: HIGH Cosine 0.800 0.500
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: Minimum
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
+ rule: if Power is LOW then InversePower is HIGH
+ rule: if Power is MEDIUM then InversePower is MEDIUM
+ rule: if Power is HIGH then InversePower is LOW
diff --git a/examples/original/mamdani/octave/COPYING b/examples/original/mamdani/octave/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/examples/original/mamdani/octave/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/examples/original/mamdani/octave/DESCRIPTION b/examples/original/mamdani/octave/DESCRIPTION
new file mode 100644
index 0000000..35df57d
--- /dev/null
+++ b/examples/original/mamdani/octave/DESCRIPTION
@@ -0,0 +1,12 @@
+Name: fuzzy-logic-toolkit
+Version: 0.4.2
+Date: 2012-10-02
+Author: L. Markowsky <lmarkov@users.sourceforge.net>
+Maintainer: L. Markowsky <lmarkov@users.sourceforge.net>
+Title: Octave Fuzzy Logic Toolkit
+Description: A mostly MATLAB-compatible fuzzy logic toolkit for Octave.
+Depends: octave (>= 3.2.4)
+Autoload: no
+License: GPLv3+
+Url: http://octave.sf.net
+ http://sf.net/projects/octave-fuzzy
diff --git a/examples/original/mamdani/octave/investment_portfolio.fis b/examples/original/mamdani/octave/investment_portfolio.fis
new file mode 100644
index 0000000..49a01fd
--- /dev/null
+++ b/examples/original/mamdani/octave/investment_portfolio.fis
@@ -0,0 +1,64 @@
+## Copyright (C) 2011-2012 L. Markowsky <lmarkov@users.sourceforge.net>
+##
+## This file is part of the fuzzy-logic-toolkit.
+##
+## The fuzzy-logic-toolkit is free software; you can redistribute it
+## and/or modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 3 of
+## the License, or (at your option) any later version.
+##
+## The fuzzy-logic-toolkit is distributed in the hope that it will be
+## useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with the fuzzy-logic-toolkit; see the file COPYING. If not,
+## see <http://www.gnu.org/licenses/>.
+
+## Author: L. Markowsky
+## Keywords: fuzzy-logic-toolkit fis
+## Directory: fuzzy-logic-toolkit/inst/
+## Filename: investment_portfolio.fis
+## Last-Modified: 28 Aug 2012
+
+[System]
+Name='Investment-Portfolio'
+Type='mamdani'
+Version=2.0
+NumInputs=2
+NumOutputs=1
+NumRules=4
+AndMethod='einstein_product'
+OrMethod='einstein_sum'
+ImpMethod='einstein_product'
+AggMethod='einstein_sum'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Age'
+Range=[20 100]
+NumMFs=2
+MF1='Young':'zmf',[30 90]
+MF2='Old':'smf',[30 90]
+
+[Input2]
+Name='Risk-Tolerance'
+Range=[0 10]
+NumMFs=2
+MF1='Low':'zmf',[2 8]
+MF2='High':'smf',[2 8]
+
+[Output1]
+Name='Percentage-In-Stocks'
+Range=[0 100]
+NumMFs=3
+MF1='About-Fifteen':'gaussmf',[10 15]
+MF2='About-Fifty':'gaussmf',[10 50]
+MF3='About-Eighty-Five':'gaussmf',[10 85]
+
+[Rules]
+1 2, 3 (1) : 2
+2 1, 1 (1) : 2
+-2.3 -1.3, 2 (0.5) : 1
+-1.3 -2.3, 2 (0.5) : 1
diff --git a/examples/original/mamdani/octave/investment_portfolio.fll b/examples/original/mamdani/octave/investment_portfolio.fll
new file mode 100644
index 0000000..a383512
--- /dev/null
+++ b/examples/original/mamdani/octave/investment_portfolio.fll
@@ -0,0 +1,32 @@
+Engine: investment_portfolio
+InputVariable: Age
+ enabled: true
+ range: 20.000 100.000
+ term: Young ZShape 30.000 90.000
+ term: Old SShape 30.000 90.000
+InputVariable: RiskTolerance
+ enabled: true
+ range: 0.000 10.000
+ term: Low ZShape 2.000 8.000
+ term: High SShape 2.000 8.000
+OutputVariable: PercentageInStocks
+ enabled: true
+ range: 0.000 100.000
+ aggregation: EinsteinSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: AboutFifteen Gaussian 15.000 10.000
+ term: AboutFifty Gaussian 50.000 10.000
+ term: AboutEightyFive Gaussian 85.000 10.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: EinsteinSum
+ implication: EinsteinProduct
+ activation: General
+ rule: if Age is Young or RiskTolerance is High then PercentageInStocks is AboutEightyFive
+ rule: if Age is Old or RiskTolerance is Low then PercentageInStocks is AboutFifteen
+ rule: if Age is not extremely Old and RiskTolerance is not extremely Low then PercentageInStocks is AboutFifty with 0.500
+ rule: if Age is not extremely Young and RiskTolerance is not extremely High then PercentageInStocks is AboutFifty with 0.500
diff --git a/examples/original/mamdani/octave/mamdani_tip_calculator.fis b/examples/original/mamdani/octave/mamdani_tip_calculator.fis
new file mode 100644
index 0000000..7029c58
--- /dev/null
+++ b/examples/original/mamdani/octave/mamdani_tip_calculator.fis
@@ -0,0 +1,72 @@
+## Copyright (C) 2011-2012 L. Markowsky <lmarkov@users.sourceforge.net>
+##
+## This file is part of the fuzzy-logic-toolkit.
+##
+## The fuzzy-logic-toolkit is free software; you can redistribute it
+## and/or modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 3 of
+## the License, or (at your option) any later version.
+##
+## The fuzzy-logic-toolkit is distributed in the hope that it will be
+## useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with the fuzzy-logic-toolkit; see the file COPYING. If not,
+## see <http://www.gnu.org/licenses/>.
+
+## Author: L. Markowsky
+## Keywords: fuzzy-logic-toolkit fis
+## Directory: fuzzy-logic-toolkit/inst/
+## Filename: mamdani_tip_calculator.fis
+## Last-Modified: 28 Aug 2012
+
+[System]
+Name='Mamdani-Tip-Calculator'
+Type='mamdani'
+Version=2.0
+NumInputs=2
+NumOutputs=2
+NumRules=4
+AndMethod='prod'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='sum'
+DefuzzMethod='centroid'
+
+[Input1]
+Name='Food-Quality'
+Range=[1 10]
+NumMFs=2
+MF1='Bad':'trapmf',[0 1 3 7]
+MF2='Good':'trapmf',[3 7 10 11]
+
+[Input2]
+Name='Service'
+Range=[1 10]
+NumMFs=2
+MF1='Bad':'trapmf',[0 1 3 7]
+MF2='Good':'trapmf',[3 7 10 11]
+
+[Output1]
+Name='Tip'
+Range=[0 30]
+NumMFs=3
+MF1='About-Ten-Percent':'gaussmf',[2 10]
+MF2='About-Fifteen-Percent':'gaussmf',[2 15]
+MF3='About-Twenty-Percent':'gaussmf',[2 20]
+
+[Output2]
+Name='Check-Plus-Tip'
+Range=[1 1.3]
+NumMFs=3
+MF1='Plus-About-Ten-Percent':'gaussmf',[0.02 1.10]
+MF2='Plus-About-Fifteen-Percent':'gaussmf',[0.02 1.15]
+MF3='Plus-About-Twenty-Percent':'gaussmf',[0.02 1.20]
+
+[Rules]
+1 1, 1 1 (1) : 1
+1 2, 2 2 (1) : 1
+2 1, 2 2 (1) : 1
+2 2, 3 3 (1) : 1
diff --git a/examples/original/mamdani/octave/mamdani_tip_calculator.fll b/examples/original/mamdani/octave/mamdani_tip_calculator.fll
new file mode 100644
index 0000000..15a94b9
--- /dev/null
+++ b/examples/original/mamdani/octave/mamdani_tip_calculator.fll
@@ -0,0 +1,43 @@
+Engine: mamdani_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: Tip
+ enabled: true
+ range: 0.000 30.000
+ aggregation: AlgebraicSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: AboutTenPercent Gaussian 10.000 2.000
+ term: AboutFifteenPercent Gaussian 15.000 2.000
+ term: AboutTwentyPercent Gaussian 20.000 2.000
+OutputVariable: CheckPlusTip
+ enabled: true
+ range: 1.000 1.300
+ aggregation: AlgebraicSum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: PlusAboutTenPercent Gaussian 1.100 0.020
+ term: PlusAboutFifteenPercent Gaussian 1.150 0.020
+ term: PlusAboutTwentyPercent Gaussian 1.200 0.020
+RuleBlock:
+ enabled: true
+ conjunction: AlgebraicProduct
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if FoodQuality is Bad and Service is Bad then Tip is AboutTenPercent and CheckPlusTip is PlusAboutTenPercent
+ rule: if FoodQuality is Bad and Service is Good then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ rule: if FoodQuality is Good and Service is Bad then Tip is AboutFifteenPercent and CheckPlusTip is PlusAboutFifteenPercent
+ rule: if FoodQuality is Good and Service is Good then Tip is AboutTwentyPercent and CheckPlusTip is PlusAboutTwentyPercent
diff --git a/examples/original/takagi-sugeno/SimpleDimmer.fis b/examples/original/takagi-sugeno/SimpleDimmer.fis
new file mode 100644
index 0000000..bb4e638
--- /dev/null
+++ b/examples/original/takagi-sugeno/SimpleDimmer.fis
@@ -0,0 +1,41 @@
+[System]
+Name='simple-dimmer'
+Type='sugeno'
+Version=4.0
+NumInputs=1
+NumOutputs=1
+NumRules=3
+AndMethod='min'
+OrMethod='max'
+ImpMethod='prod'
+AggMethod='sum'
+DefuzzMethod='wtaver'
+
+[Input1]
+Enabled=1
+Name='Ambient'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='DARK':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='BRIGHT':'trimf',[0.500 0.750 1.000]
+
+
+[Output1]
+Enabled=1
+Name='Power'
+Range=[0.000 1.000]
+Default=nan
+LockPrevious=0
+LockRange=0
+NumMFs=3
+MF1='LOW':'constant',[0.250]
+MF2='MEDIUM':'constant',[0.500]
+MF3='HIGH':'constant',[0.750]
+
+
+[Rules]
+1.000 , 3.000 (1) : 1
+2.000 , 2.000 (1) : 1
+3.000 , 1.000 (1) : 1
+
diff --git a/examples/original/takagi-sugeno/SimpleDimmer.fll b/examples/original/takagi-sugeno/SimpleDimmer.fll
new file mode 100644
index 0000000..dc46ec8
--- /dev/null
+++ b/examples/original/takagi-sugeno/SimpleDimmer.fll
@@ -0,0 +1,27 @@
+Engine: SimpleDimmer
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: LOW Constant 0.250
+ term: MEDIUM Constant 0.500
+ term: HIGH Constant 0.750
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW
diff --git a/examples/original/takagi-sugeno/approximation.fis b/examples/original/takagi-sugeno/approximation.fis
new file mode 100644
index 0000000..3627ccf
--- /dev/null
+++ b/examples/original/takagi-sugeno/approximation.fis
@@ -0,0 +1,80 @@
+[System]
+Name='approximation of sin(x)/x'
+Type='sugeno'
+Version=4.0
+NumInputs=1
+NumOutputs=3
+NumRules=10
+AndMethod=''
+OrMethod=''
+ImpMethod='prod'
+AggMethod='sum'
+DefuzzMethod='wtaver'
+
+[Input1]
+Enabled=1
+Name='inputX'
+Range=[0.000 10.000]
+NumMFs=9
+MF1='NEAR_1':'trimf',[0.000 1.000 2.000]
+MF2='NEAR_2':'trimf',[1.000 2.000 3.000]
+MF3='NEAR_3':'trimf',[2.000 3.000 4.000]
+MF4='NEAR_4':'trimf',[3.000 4.000 5.000]
+MF5='NEAR_5':'trimf',[4.000 5.000 6.000]
+MF6='NEAR_6':'trimf',[5.000 6.000 7.000]
+MF7='NEAR_7':'trimf',[6.000 7.000 8.000]
+MF8='NEAR_8':'trimf',[7.000 8.000 9.000]
+MF9='NEAR_9':'trimf',[8.000 9.000 10.000]
+
+
+[Output1]
+Enabled=1
+Name='outputFx'
+Range=[-1.000 1.000]
+Default=nan
+LockPrevious=1
+LockRange=0
+NumMFs=9
+MF1='f1':'constant',[0.840]
+MF2='f2':'constant',[0.450]
+MF3='f3':'constant',[0.040]
+MF4='f4':'constant',[-0.180]
+MF5='f5':'constant',[-0.190]
+MF6='f6':'constant',[-0.040]
+MF7='f7':'constant',[0.090]
+MF8='f8':'constant',[0.120]
+MF9='f9':'constant',[0.040]
+
+[Output2]
+Enabled=1
+Name='trueFx'
+Range=[-1.000 1.000]
+Default=nan
+LockPrevious=1
+LockRange=0
+NumMFs=1
+MF1='fx':'function',[sin ( inputX ) /inputX]
+
+[Output3]
+Enabled=1
+Name='diffFx'
+Range=[-1.000 1.000]
+Default=nan
+LockPrevious=0
+LockRange=0
+NumMFs=1
+MF1='diff':'function',[fabs ( outputFx-trueFx )]
+
+
+[Rules]
+1.000 , 1.000 0.000 0.000 (1.000) : 1
+2.000 , 2.000 0.000 0.000 (1.000) : 1
+3.000 , 3.000 0.000 0.000 (1.000) : 1
+4.000 , 4.000 0.000 0.000 (1.000) : 1
+5.000 , 5.000 0.000 0.000 (1.000) : 1
+6.000 , 6.000 0.000 0.000 (1.000) : 1
+7.000 , 7.000 0.000 0.000 (1.000) : 1
+8.000 , 8.000 0.000 0.000 (1.000) : 1
+9.000 , 9.000 0.000 0.000 (1.000) : 1
+0.990 , 0.000 1.000 1.000 (1.000) : 1
+
diff --git a/examples/original/takagi-sugeno/approximation.fll b/examples/original/takagi-sugeno/approximation.fll
new file mode 100644
index 0000000..63964dc
--- /dev/null
+++ b/examples/original/takagi-sugeno/approximation.fll
@@ -0,0 +1,64 @@
+Engine: approximation
+InputVariable: inputX
+ enabled: true
+ range: 0.000 10.000
+ term: NEAR_1 Triangle 0.000 1.000 2.000
+ term: NEAR_2 Triangle 1.000 2.000 3.000
+ term: NEAR_3 Triangle 2.000 3.000 4.000
+ term: NEAR_4 Triangle 3.000 4.000 5.000
+ term: NEAR_5 Triangle 4.000 5.000 6.000
+ term: NEAR_6 Triangle 5.000 6.000 7.000
+ term: NEAR_7 Triangle 6.000 7.000 8.000
+ term: NEAR_8 Triangle 7.000 8.000 9.000
+ term: NEAR_9 Triangle 8.000 9.000 10.000
+OutputVariable: outputFx
+ enabled: true
+ range: -1.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: true
+ lock-range: false
+ term: f1 Constant 0.840
+ term: f2 Constant 0.450
+ term: f3 Constant 0.040
+ term: f4 Constant -0.180
+ term: f5 Constant -0.190
+ term: f6 Constant -0.040
+ term: f7 Constant 0.090
+ term: f8 Constant 0.120
+ term: f9 Constant 0.040
+OutputVariable: trueFx
+ enabled: true
+ range: -1.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage
+ default: nan
+ lock-previous: true
+ lock-range: false
+ term: fx Function sin(inputX)/inputX
+OutputVariable: diffFx
+ enabled: true
+ range: -1.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: diff Function fabs(outputFx-trueFx)
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if inputX is NEAR_1 then outputFx is f1
+ rule: if inputX is NEAR_2 then outputFx is f2
+ rule: if inputX is NEAR_3 then outputFx is f3
+ rule: if inputX is NEAR_4 then outputFx is f4
+ rule: if inputX is NEAR_5 then outputFx is f5
+ rule: if inputX is NEAR_6 then outputFx is f6
+ rule: if inputX is NEAR_7 then outputFx is f7
+ rule: if inputX is NEAR_8 then outputFx is f8
+ rule: if inputX is NEAR_9 then outputFx is f9
+ rule: if inputX is any then trueFx is fx and diffFx is diff
diff --git a/examples/original/takagi-sugeno/octave/COPYING b/examples/original/takagi-sugeno/octave/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/examples/original/takagi-sugeno/octave/DESCRIPTION b/examples/original/takagi-sugeno/octave/DESCRIPTION
new file mode 100644
index 0000000..35df57d
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/DESCRIPTION
@@ -0,0 +1,12 @@
+Name: fuzzy-logic-toolkit
+Version: 0.4.2
+Date: 2012-10-02
+Author: L. Markowsky <lmarkov@users.sourceforge.net>
+Maintainer: L. Markowsky <lmarkov@users.sourceforge.net>
+Title: Octave Fuzzy Logic Toolkit
+Description: A mostly MATLAB-compatible fuzzy logic toolkit for Octave.
+Depends: octave (>= 3.2.4)
+Autoload: no
+License: GPLv3+
+Url: http://octave.sf.net
+ http://sf.net/projects/octave-fuzzy
diff --git a/examples/original/takagi-sugeno/octave/cubic_approximator.fis b/examples/original/takagi-sugeno/octave/cubic_approximator.fis
new file mode 100644
index 0000000..49bf5b1
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/cubic_approximator.fis
@@ -0,0 +1,81 @@
+## Copyright (C) 2011-2012 L. Markowsky <lmarkov@users.sourceforge.net>
+##
+## This file is part of the fuzzy-logic-toolkit.
+##
+## The fuzzy-logic-toolkit is free software; you can redistribute it
+## and/or modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 3 of
+## the License, or (at your option) any later version.
+##
+## The fuzzy-logic-toolkit is distributed in the hope that it will be
+## useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with the fuzzy-logic-toolkit; see the file COPYING. If not,
+## see <http://www.gnu.org/licenses/>.
+
+## Author: L. Markowsky
+## Keywords: fuzzy-logic-toolkit fis
+## Directory: fuzzy-logic-toolkit/inst/
+## Filename: cubic_approximator.fis
+## Last-Modified: 28 Aug 2012
+
+[System]
+Name='Cubic-Approximator'
+Type='sugeno'
+Version=2.0
+NumInputs=1
+NumOutputs=1
+NumRules=11
+AndMethod='min'
+OrMethod='max'
+ImpMethod='prod'
+AggMethod='sum'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='X'
+Range=[-5 5]
+NumMFs=11
+MF1 = 'About-Neg-Five':'trimf', [-6 -5 -4]
+MF2 = 'About-Neg-Four':'trimf', [-5 -4 -3]
+MF3 = 'About-Neg-Three':'trimf', [-4 -3 -2]
+MF4 = 'About-Neg-Two':'trimf', [-3 -2 -1]
+MF5 = 'About-Neg-One':'trimf', [-2 -1 0]
+MF6 = 'About-Zero':'trimf', [-1 0 1]
+MF7 = 'About-One':'trimf', [0 1 2]
+MF8 = 'About-Two':'trimf', [1 2 3]
+MF9 = 'About-Three':'trimf', [2 3 4]
+MF10 = 'About-Four':'trimf', [3 4 5]
+MF11 = 'About-Five':'trimf', [4 5 6]
+
+[Output1]
+Name='Approx-X-Cubed'
+Range=[-5 5]
+NumMFs=11
+MF1 = 'Tangent-at-Neg-Five':'linear', [75 250]
+MF2 = 'Tangent-at-Neg-Four':'linear', [48 128]
+MF3 = 'Tangent-at-Neg-Three':'linear', [27 54]
+MF4 = 'Tangent-at-Neg-Two':'linear', [12 16]
+MF5 = 'Tangent-at-Neg-One':'linear', [3 2]
+MF6 = 'Tangent-at-Zero':'linear', [0 0]
+MF7 = 'Tangent-at-One':'linear', [3 -2]
+MF8 = 'Tangent-at-Two':'linear', [12 -16]
+MF9 = 'Tangent-at-Three':'linear', [27 -54]
+MF10 = 'Tangent-at-Four':'linear', [48 -128]
+MF11 = 'Tangent-at-Five':'linear', [75 -250]
+
+[Rules]
+1, 1 (1) : 1
+2, 2 (1) : 1
+3, 3 (1) : 1
+4, 4 (1) : 1
+5, 5 (1) : 1
+6, 6 (1) : 1
+7, 7 (1) : 1
+8, 8 (1) : 1
+9, 9 (1) : 1
+10, 10 (1) : 1
+11, 11 (1) : 1
diff --git a/examples/original/takagi-sugeno/octave/cubic_approximator.fll b/examples/original/takagi-sugeno/octave/cubic_approximator.fll
new file mode 100644
index 0000000..7d2c157
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/cubic_approximator.fll
@@ -0,0 +1,51 @@
+Engine: cubic_approximator
+InputVariable: X
+ enabled: true
+ range: -5.000 5.000
+ term: AboutNegFive Triangle -6.000 -5.000 -4.000
+ term: AboutNegFour Triangle -5.000 -4.000 -3.000
+ term: AboutNegThree Triangle -4.000 -3.000 -2.000
+ term: AboutNegTwo Triangle -3.000 -2.000 -1.000
+ term: AboutNegOne Triangle -2.000 -1.000 0.000
+ term: AboutZero Triangle -1.000 0.000 1.000
+ term: AboutOne Triangle 0.000 1.000 2.000
+ term: AboutTwo Triangle 1.000 2.000 3.000
+ term: AboutThree Triangle 2.000 3.000 4.000
+ term: AboutFour Triangle 3.000 4.000 5.000
+ term: AboutFive Triangle 4.000 5.000 6.000
+OutputVariable: ApproxXCubed
+ enabled: true
+ range: -5.000 5.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: TangentatNegFive Linear 75.000 250.000
+ term: TangentatNegFour Linear 48.000 128.000
+ term: TangentatNegThree Linear 27.000 54.000
+ term: TangentatNegTwo Linear 12.000 16.000
+ term: TangentatNegOne Linear 3.000 2.000
+ term: TangentatZero Linear 0.000 0.000
+ term: TangentatOne Linear 3.000 -2.000
+ term: TangentatTwo Linear 12.000 -16.000
+ term: TangentatThree Linear 27.000 -54.000
+ term: TangentatFour Linear 48.000 -128.000
+ term: TangentatFive Linear 75.000 -250.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if X is AboutNegFive then ApproxXCubed is TangentatNegFive
+ rule: if X is AboutNegFour then ApproxXCubed is TangentatNegFour
+ rule: if X is AboutNegThree then ApproxXCubed is TangentatNegThree
+ rule: if X is AboutNegTwo then ApproxXCubed is TangentatNegTwo
+ rule: if X is AboutNegOne then ApproxXCubed is TangentatNegOne
+ rule: if X is AboutZero then ApproxXCubed is TangentatZero
+ rule: if X is AboutOne then ApproxXCubed is TangentatOne
+ rule: if X is AboutTwo then ApproxXCubed is TangentatTwo
+ rule: if X is AboutThree then ApproxXCubed is TangentatThree
+ rule: if X is AboutFour then ApproxXCubed is TangentatFour
+ rule: if X is AboutFive then ApproxXCubed is TangentatFive
diff --git a/examples/original/takagi-sugeno/octave/heart_disease_risk.fis b/examples/original/takagi-sugeno/octave/heart_disease_risk.fis
new file mode 100644
index 0000000..e0e18e0
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/heart_disease_risk.fis
@@ -0,0 +1,90 @@
+## Copyright (C) 2011-2012 L. Markowsky <lmarkov@users.sourceforge.net>
+##
+## This file is part of the fuzzy-logic-toolkit.
+##
+## The fuzzy-logic-toolkit is free software; you can redistribute it
+## and/or modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 3 of
+## the License, or (at your option) any later version.
+##
+## The fuzzy-logic-toolkit is distributed in the hope that it will be
+## useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with the fuzzy-logic-toolkit; see the file COPYING. If not,
+## see <http://www.gnu.org/licenses/>.
+
+## Author: L. Markowsky
+## Keywords: fuzzy-logic-toolkit fis
+## Directory: fuzzy-logic-toolkit/inst/
+## Filename: heart_disease_risk.fis
+## Last-Modified: 28 Aug 2012
+
+## Heart Disease Risk FIS
+
+[System]
+
+ Name = 'Heart-Disease-Risk'
+ Type = 'sugeno'
+ Version = 2.0
+ NumInputs = 2
+ NumOutputs = 1
+ NumRules = 15
+ AndMethod = 'min'
+ OrMethod = 'max'
+ ImpMethod = 'prod'
+ AggMethod = 'sum'
+ DefuzzMethod = 'wtaver'
+
+[Input1]
+
+ Name = 'LDL-Level'
+ Range = [0 300]
+ NumMFs = 5
+ MF1 = 'Low' : 'trapmf', [-1 0 90 110]
+ MF2 = 'Low-Borderline' : 'trapmf', [90 110 120 140]
+ MF3 = 'Borderline' : 'trapmf', [120 140 150 170]
+ MF4 = 'High-Borderline' : 'trapmf', [150 170 180 200]
+ MF5 = 'High' : 'trapmf', [180 200 300 301]
+
+[Input2]
+
+ Name = 'HDL-Level'
+ Range = [0 100]
+ NumMFs = 3
+
+ MF1 = 'Low-HDL' : 'trapmf', [-1 0 35 45]
+ MF2 = 'Moderate-HDL' : 'trapmf', [35 45 55 65]
+ MF3 = 'High-HDL' : 'trapmf', [55 65 100 101]
+
+[Output1]
+
+ Name = 'Heart-Disease-Risk'
+ Range = [0 10]
+ NumMFs = 5
+
+ MF1 = 'No-Risk' : 'constant', [0]
+ MF2 = 'Low-Risk' : 'constant', [2.5]
+ MF3 = 'Medium-Risk' : 'constant', [5]
+ MF4 = 'High-Risk' : 'constant', [7.5]
+ MF5 = 'Extreme-Risk' : 'constant', [10]
+
+[Rules]
+
+ 1 1, 3 (1) : 1
+ 1 2, 2 (1) : 1
+ 1 3, 1 (1) : 1
+ 2 1, 3 (1) : 1
+ 2 2, 2 (1) : 1
+ 2 3, 2 (1) : 1
+ 3 1, 4 (1) : 1
+ 3 2, 3 (1) : 1
+ 3 3, 2 (1) : 1
+ 4 1, 4 (1) : 1
+ 4 2, 4 (1) : 1
+ 4 3, 3 (1) : 1
+ 5 1, 5 (1) : 1
+ 5 2, 4 (1) : 1
+ 5 3, 3 (1) : 1
diff --git a/examples/original/takagi-sugeno/octave/heart_disease_risk.fll b/examples/original/takagi-sugeno/octave/heart_disease_risk.fll
new file mode 100644
index 0000000..4c60466
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/heart_disease_risk.fll
@@ -0,0 +1,49 @@
+Engine: heart_disease_risk
+InputVariable: LDLLevel
+ enabled: true
+ range: 0.000 300.000
+ term: Low Trapezoid -1.000 0.000 90.000 110.000
+ term: LowBorderline Trapezoid 90.000 110.000 120.000 140.000
+ term: Borderline Trapezoid 120.000 140.000 150.000 170.000
+ term: HighBorderline Trapezoid 150.000 170.000 180.000 200.000
+ term: High Trapezoid 180.000 200.000 300.000 301.000
+InputVariable: HDLLevel
+ enabled: true
+ range: 0.000 100.000
+ term: LowHDL Trapezoid -1.000 0.000 35.000 45.000
+ term: ModerateHDL Trapezoid 35.000 45.000 55.000 65.000
+ term: HighHDL Trapezoid 55.000 65.000 100.000 101.000
+OutputVariable: HeartDiseaseRisk
+ enabled: true
+ range: 0.000 10.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: NoRisk Constant 0.000
+ term: LowRisk Constant 2.500
+ term: MediumRisk Constant 5.000
+ term: HighRisk Constant 7.500
+ term: ExtremeRisk Constant 10.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if LDLLevel is Low and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is Low and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is Low and HDLLevel is HighHDL then HeartDiseaseRisk is NoRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is Borderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is Borderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is Borderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is High and HDLLevel is LowHDL then HeartDiseaseRisk is ExtremeRisk
+ rule: if LDLLevel is High and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is High and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk
diff --git a/examples/original/takagi-sugeno/octave/linear_tip_calculator.fis b/examples/original/takagi-sugeno/octave/linear_tip_calculator.fis
new file mode 100644
index 0000000..f387ce1
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/linear_tip_calculator.fis
@@ -0,0 +1,64 @@
+## Copyright (C) 2011-2012 L. Markowsky <lmarkov@users.sourceforge.net>
+##
+## This file is part of the fuzzy-logic-toolkit.
+##
+## The fuzzy-logic-toolkit is free software; you can redistribute it
+## and/or modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 3 of
+## the License, or (at your option) any later version.
+##
+## The fuzzy-logic-toolkit is distributed in the hope that it will be
+## useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with the fuzzy-logic-toolkit; see the file COPYING. If not,
+## see <http://www.gnu.org/licenses/>.
+
+## Author: L. Markowsky
+## Keywords: fuzzy-logic-toolkit fis
+## Directory: fuzzy-logic-toolkit/inst/
+## Filename: linear_tip_calculator.fis
+## Last-Modified: 28 Aug 2012
+
+[System]
+Name='Linear-Tip-Calculator'
+Type='sugeno'
+Version=2.0
+NumInputs=2
+NumOutputs=1
+NumRules=4
+AndMethod='min'
+OrMethod='max'
+ImpMethod='prod'
+AggMethod='sum'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='Food-Quality'
+Range=[1 10]
+NumMFs=2
+MF1='Bad':'trapmf',[0 1 3 7]
+MF2='Good':'trapmf',[3 7 10 11]
+
+[Input2]
+Name='Service'
+Range=[1 10]
+NumMFs=2
+MF1='Bad':'trapmf',[0 1 3 7]
+MF2='Good':'trapmf',[3 7 10 11]
+
+[Output1]
+Name='Tip'
+Range=[10 20]
+NumMFs=3
+MF1='Ten-Percent':'linear',[0 0 10]
+MF2='Fifteen-Percent':'linear',[0 0 15]
+MF3='Twenty-Percent':'linear',[0 0 20]
+
+[Rules]
+1 1, 1 (1) : 1
+1 2, 2 (1) : 1
+2 1, 2 (1) : 1
+2 2, 3 (1) : 1
diff --git a/examples/original/takagi-sugeno/octave/linear_tip_calculator.fll b/examples/original/takagi-sugeno/octave/linear_tip_calculator.fll
new file mode 100644
index 0000000..3b99fc9
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/linear_tip_calculator.fll
@@ -0,0 +1,32 @@
+Engine: linear_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: Tip
+ enabled: true
+ range: 10.000 20.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: TenPercent Linear 0.000 0.000 10.000
+ term: FifteenPercent Linear 0.000 0.000 15.000
+ term: TwentyPercent Linear 0.000 0.000 20.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is Bad and Service is Bad then Tip is TenPercent
+ rule: if FoodQuality is Bad and Service is Good then Tip is FifteenPercent
+ rule: if FoodQuality is Good and Service is Bad then Tip is FifteenPercent
+ rule: if FoodQuality is Good and Service is Good then Tip is TwentyPercent
diff --git a/examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fis b/examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fis
new file mode 100644
index 0000000..78786df
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fis
@@ -0,0 +1,98 @@
+## Copyright (C) 2011-2012 L. Markowsky <lmarkov@users.sourceforge.net>
+##
+## This file is part of the fuzzy-logic-toolkit.
+##
+## The fuzzy-logic-toolkit is free software; you can redistribute it
+## and/or modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 3 of
+## the License, or (at your option) any later version.
+##
+## The fuzzy-logic-toolkit is distributed in the hope that it will be
+## useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with the fuzzy-logic-toolkit; see the file COPYING. If not,
+## see <http://www.gnu.org/licenses/>.
+
+## Author: L. Markowsky
+## Keywords: fuzzy-logic-toolkit fis
+## Directory: fuzzy-logic-toolkit/inst/
+## Filename: sugeno_tip_calculator.fis
+## Last-Modified: 28 Aug 2012
+
+% Sugeno Tip Calculator
+
+% Computes cheap, average, and generous tips
+% given food quality and service ratings.
+
+[System]
+
+Name = 'Sugeno-Tip-Calculator'
+Type = 'sugeno'
+Version = 1.0
+NumInputs = 2
+NumOutputs = 3
+NumRules = 10
+AndMethod = 'einstein_product'
+OrMethod = 'einstein_sum'
+ImpMethod = 'prod'
+AggMethod = 'sum'
+DefuzzMethod = 'wtaver'
+
+[Input1]
+
+Name = 'Food-Quality'
+Range = [1 10]
+NumMFs = 2
+MF1 = 'Bad' : 'trapmf', [0 1 3 7]
+MF2 = 'Good' : 'trapmf', [3 7 10 11]
+
+[Input2]
+
+Name = 'Service'
+Range = [1 10]
+NumMFs = 2
+MF1 = 'Bad' : 'trapmf', [0 1 3 7]
+MF2 = 'Good' : 'trapmf', [3 7 10 11]
+
+[Output1]
+
+Name = 'Cheap-Tip'
+Range = [5 25]
+NumMFs = 3
+MF1 = 'Low' : 'constant', [10]
+MF2 = 'Medium' : 'constant', [15]
+MF3 = 'High' : 'constant', [20]
+
+[Output2]
+
+Name = 'Average-Tip'
+Range = [5 25]
+NumMFs = 3
+MF1 = 'Low' : 'constant', [10]
+MF2 = 'Medium' : 'constant', [15]
+MF3 = 'High' : 'constant', [20]
+
+[Output3]
+
+Name = 'Generous-Tip'
+Range = [5 25]
+NumMFs = 3
+MF1 = 'Low' : 'constant', [10]
+MF2 = 'Medium' : 'constant', [15]
+MF3 = 'High' : 'constant', [20]
+
+[Rules]
+
+ 1.30 1.30, 1.30 1.20 1.00 (1) : 1
+ 2.00 1.30, 1.00 1.00 2.00 (1) : 1
+ 2.20 1.20, 1.00 2.00 3.00 (1) : 1
+ 1.00 1.00, 1.00 1.00 2.00 (1) : 1
+ 2.00 1.00, 1.00 2.00 3.00 (1) : 1
+ 2.30 1.00, 1.00 2.00 3.20 (1) : 1
+ 1.00 2.00, 1.00 2.00 3.00 (1) : 1
+ 2.00 2.00, 2.00 2.00 3.20 (1) : 1
+ 1.20 2.20, 1.00 2.00 3.00 (1) : 1
+ 2.40 2.40, 3.00 3.20 3.30 (1) : 1
diff --git a/examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fll b/examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fll
new file mode 100644
index 0000000..19c5875
--- /dev/null
+++ b/examples/original/takagi-sugeno/octave/sugeno_tip_calculator.fll
@@ -0,0 +1,60 @@
+Engine: sugeno_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: CheapTip
+ enabled: true
+ range: 5.000 25.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: AverageTip
+ enabled: true
+ range: 5.000 25.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: GenerousTip
+ enabled: true
+ range: 5.000 25.000
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low
+ rule: if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High
diff --git a/examples/original/tsukamoto/tsukamoto.fis b/examples/original/tsukamoto/tsukamoto.fis
new file mode 100644
index 0000000..711e427
--- /dev/null
+++ b/examples/original/tsukamoto/tsukamoto.fis
@@ -0,0 +1,65 @@
+[System]
+Name=''
+Type='sugeno'
+Version=4.0
+NumInputs=1
+NumOutputs=3
+NumRules=3
+AndMethod=''
+OrMethod=''
+ImpMethod='prod'
+AggMethod='sum'
+DefuzzMethod='wtaver'
+
+[Input1]
+Enabled=1
+Name='X'
+Range=[-10.000 10.000]
+NumMFs=3
+MF1='small':'gbellmf',[5.000 3.000 -10.000]
+MF2='medium':'gbellmf',[5.000 3.000 0.000]
+MF3='large':'gbellmf',[5.000 3.000 10.000]
+
+
+[Output1]
+Enabled=1
+Name='A'
+Range=[0.000 1.000]
+Default=nan
+LockPrevious=0
+LockRange=0
+NumMFs=3
+MF1='a1':'rampmf',[0.000 0.250]
+MF2='a2':'rampmf',[0.600 0.400]
+MF3='a3':'rampmf',[0.700 1.000]
+
+[Output2]
+Enabled=1
+Name='B'
+Range=[0.000 1.000]
+Default=nan
+LockPrevious=0
+LockRange=0
+NumMFs=3
+MF1='b1':'sigmf',[30.000 0.130]
+MF2='b2':'sigmf',[-30.000 0.500]
+MF3='b3':'sigmf',[30.000 0.830]
+
+[Output3]
+Enabled=1
+Name='C'
+Range=[0.000 1.000]
+Default=nan
+LockPrevious=0
+LockRange=0
+NumMFs=3
+MF1='c1':'smf',[0.000 0.250]
+MF2='c2':'zmf',[0.300 0.600]
+MF3='c3':'smf',[0.700 1.000]
+
+
+[Rules]
+1.0 , 1.0 1.0 1.0 (1) : 1
+2.0 , 2.0 2.0 2.0 (1) : 1
+3.0 , 3.0 3.0 3.0 (1) : 1
+
diff --git a/examples/original/tsukamoto/tsukamoto.fll b/examples/original/tsukamoto/tsukamoto.fll
new file mode 100644
index 0000000..b8acf99
--- /dev/null
+++ b/examples/original/tsukamoto/tsukamoto.fll
@@ -0,0 +1,60 @@
+Engine: tsukamoto
+InputVariable: X
+ enabled: true
+ range: -10.000 10.000
+ term: small Bell -10.000 5.000 3.000
+ term: medium Bell 0.000 5.000 3.000
+ term: large Bell 10.000 5.000 3.000
+OutputVariable: Ramps
+ enabled: true
+ range: 0.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: b Ramp 0.600 0.400
+ term: a Ramp 0.000 0.250
+ term: c Ramp 0.700 1.000
+OutputVariable: Sigmoids
+ enabled: true
+ range: 0.020 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: b Sigmoid 0.500 -30.000
+ term: a Sigmoid 0.130 30.000
+ term: c Sigmoid 0.830 30.000
+OutputVariable: ZSShapes
+ enabled: true
+ range: 0.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: b ZShape 0.300 0.600
+ term: a SShape 0.000 0.250
+ term: c SShape 0.700 1.000
+OutputVariable: Concaves
+ enabled: true
+ range: 0.000 1.000
+ aggregation: none
+ defuzzifier: WeightedAverage
+ default: nan
+ lock-previous: false
+ lock-range: false
+ term: b Concave 0.500 0.400
+ term: a Concave 0.240 0.250
+ term: c Concave 0.900 1.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if X is small then Ramps is a and Sigmoids is a and ZSShapes is a and Concaves is a
+ rule: if X is medium then Ramps is b and Sigmoids is b and ZSShapes is b and Concaves is b
+ rule: if X is large then Ramps is c and Sigmoids is c and ZSShapes is c and Concaves is c
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.R b/examples/takagi-sugeno/ObstacleAvoidance.R
new file mode 100644
index 0000000..eb96813
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.R
@@ -0,0 +1,57 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "ObstacleAvoidance"
+engine.fll = "Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: tsSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: left Constant 0.333
+ term: right Constant 0.666
+RuleBlock: takagiSugeno
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if obstacle is left then tsSteer is right
+ rule: if obstacle is right then tsSteer is left"
+
+engine.fldFile = "ObstacleAvoidance.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(obstacle, tsSteer)) +
+ geom_line(aes(color=tsSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("obstacle vs tsSteer")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(obstacle, tsSteer)) +
+ geom_line(aes(color=tsSteer), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("tsSteer vs obstacle")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.cpp b/examples/takagi-sugeno/ObstacleAvoidance.cpp
new file mode 100644
index 0000000..32d6ba9
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.cpp
@@ -0,0 +1,49 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("ObstacleAvoidance");
+engine->setDescription("");
+
+InputVariable* obstacle = new InputVariable;
+obstacle->setName("obstacle");
+obstacle->setDescription("");
+obstacle->setEnabled(true);
+obstacle->setRange(0.000, 1.000);
+obstacle->setLockValueInRange(false);
+obstacle->addTerm(new Ramp("left", 1.000, 0.000));
+obstacle->addTerm(new Ramp("right", 0.000, 1.000));
+engine->addInputVariable(obstacle);
+
+OutputVariable* tsSteer = new OutputVariable;
+tsSteer->setName("tsSteer");
+tsSteer->setDescription("");
+tsSteer->setEnabled(true);
+tsSteer->setRange(0.000, 1.000);
+tsSteer->setLockValueInRange(false);
+tsSteer->setAggregation(new Maximum);
+tsSteer->setDefuzzifier(new WeightedAverage("Automatic"));
+tsSteer->setDefaultValue(fl::nan);
+tsSteer->setLockPreviousValue(false);
+tsSteer->addTerm(new Constant("left", 0.333));
+tsSteer->addTerm(new Constant("right", 0.666));
+engine->addOutputVariable(tsSteer);
+
+RuleBlock* takagiSugeno = new RuleBlock;
+takagiSugeno->setName("takagiSugeno");
+takagiSugeno->setDescription("");
+takagiSugeno->setEnabled(true);
+takagiSugeno->setConjunction(fl::null);
+takagiSugeno->setDisjunction(fl::null);
+takagiSugeno->setImplication(fl::null);
+takagiSugeno->setActivation(new General);
+takagiSugeno->addRule(Rule::parse("if obstacle is left then tsSteer is right", engine));
+takagiSugeno->addRule(Rule::parse("if obstacle is right then tsSteer is left", engine));
+engine->addRuleBlock(takagiSugeno);
+
+
+}
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.fcl b/examples/takagi-sugeno/ObstacleAvoidance.fcl
new file mode 100644
index 0000000..fc4348b
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.fcl
@@ -0,0 +1,33 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK ObstacleAvoidance
+
+VAR_INPUT
+ obstacle: REAL;
+END_VAR
+
+VAR_OUTPUT
+ tsSteer: REAL;
+END_VAR
+
+FUZZIFY obstacle
+ RANGE := (0.000 .. 1.000);
+ TERM left := Ramp 1.000 0.000;
+ TERM right := Ramp 0.000 1.000;
+END_FUZZIFY
+
+DEFUZZIFY tsSteer
+ RANGE := (0.000 .. 1.000);
+ TERM left := 0.333;
+ TERM right := 0.666;
+ METHOD : COGS;
+ ACCU : MAX;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK takagiSugeno
+ RULE 1 : if obstacle is left then tsSteer is right
+ RULE 2 : if obstacle is right then tsSteer is left
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.fis b/examples/takagi-sugeno/ObstacleAvoidance.fis
new file mode 100644
index 0000000..16c5791
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.fis
@@ -0,0 +1,32 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='ObstacleAvoidance'
+Type='sugeno'
+Version=6.0
+NumInputs=1
+NumOutputs=1
+NumRules=2
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='obstacle'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'rampmf',[1.000 0.000]
+MF2='right':'rampmf',[0.000 1.000]
+
+[Output1]
+Name='tsSteer'
+Range=[0.000 1.000]
+NumMFs=2
+MF1='left':'constant',[0.333]
+MF2='right':'constant',[0.666]
+
+[Rules]
+1.000 , 2.000 (1.000) : 1
+2.000 , 1.000 (1.000) : 1
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.fld b/examples/takagi-sugeno/ObstacleAvoidance.fld
new file mode 100644
index 0000000..00467f3
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.fld
@@ -0,0 +1,1025 @@
+obstacle tsSteer
+0.000000000 0.666000000
+0.000977517 0.665674487
+0.001955034 0.665348974
+0.002932551 0.665023460
+0.003910068 0.664697947
+0.004887586 0.664372434
+0.005865103 0.664046921
+0.006842620 0.663721408
+0.007820137 0.663395894
+0.008797654 0.663070381
+0.009775171 0.662744868
+0.010752688 0.662419355
+0.011730205 0.662093842
+0.012707722 0.661768328
+0.013685239 0.661442815
+0.014662757 0.661117302
+0.015640274 0.660791789
+0.016617791 0.660466276
+0.017595308 0.660140762
+0.018572825 0.659815249
+0.019550342 0.659489736
+0.020527859 0.659164223
+0.021505376 0.658838710
+0.022482893 0.658513196
+0.023460411 0.658187683
+0.024437928 0.657862170
+0.025415445 0.657536657
+0.026392962 0.657211144
+0.027370479 0.656885630
+0.028347996 0.656560117
+0.029325513 0.656234604
+0.030303030 0.655909091
+0.031280547 0.655583578
+0.032258065 0.655258065
+0.033235582 0.654932551
+0.034213099 0.654607038
+0.035190616 0.654281525
+0.036168133 0.653956012
+0.037145650 0.653630499
+0.038123167 0.653304985
+0.039100684 0.652979472
+0.040078201 0.652653959
+0.041055718 0.652328446
+0.042033236 0.652002933
+0.043010753 0.651677419
+0.043988270 0.651351906
+0.044965787 0.651026393
+0.045943304 0.650700880
+0.046920821 0.650375367
+0.047898338 0.650049853
+0.048875855 0.649724340
+0.049853372 0.649398827
+0.050830890 0.649073314
+0.051808407 0.648747801
+0.052785924 0.648422287
+0.053763441 0.648096774
+0.054740958 0.647771261
+0.055718475 0.647445748
+0.056695992 0.647120235
+0.057673509 0.646794721
+0.058651026 0.646469208
+0.059628543 0.646143695
+0.060606061 0.645818182
+0.061583578 0.645492669
+0.062561095 0.645167155
+0.063538612 0.644841642
+0.064516129 0.644516129
+0.065493646 0.644190616
+0.066471163 0.643865103
+0.067448680 0.643539589
+0.068426197 0.643214076
+0.069403715 0.642888563
+0.070381232 0.642563050
+0.071358749 0.642237537
+0.072336266 0.641912023
+0.073313783 0.641586510
+0.074291300 0.641260997
+0.075268817 0.640935484
+0.076246334 0.640609971
+0.077223851 0.640284457
+0.078201369 0.639958944
+0.079178886 0.639633431
+0.080156403 0.639307918
+0.081133920 0.638982405
+0.082111437 0.638656891
+0.083088954 0.638331378
+0.084066471 0.638005865
+0.085043988 0.637680352
+0.086021505 0.637354839
+0.086999022 0.637029326
+0.087976540 0.636703812
+0.088954057 0.636378299
+0.089931574 0.636052786
+0.090909091 0.635727273
+0.091886608 0.635401760
+0.092864125 0.635076246
+0.093841642 0.634750733
+0.094819159 0.634425220
+0.095796676 0.634099707
+0.096774194 0.633774194
+0.097751711 0.633448680
+0.098729228 0.633123167
+0.099706745 0.632797654
+0.100684262 0.632472141
+0.101661779 0.632146628
+0.102639296 0.631821114
+0.103616813 0.631495601
+0.104594330 0.631170088
+0.105571848 0.630844575
+0.106549365 0.630519062
+0.107526882 0.630193548
+0.108504399 0.629868035
+0.109481916 0.629542522
+0.110459433 0.629217009
+0.111436950 0.628891496
+0.112414467 0.628565982
+0.113391984 0.628240469
+0.114369501 0.627914956
+0.115347019 0.627589443
+0.116324536 0.627263930
+0.117302053 0.626938416
+0.118279570 0.626612903
+0.119257087 0.626287390
+0.120234604 0.625961877
+0.121212121 0.625636364
+0.122189638 0.625310850
+0.123167155 0.624985337
+0.124144673 0.624659824
+0.125122190 0.624334311
+0.126099707 0.624008798
+0.127077224 0.623683284
+0.128054741 0.623357771
+0.129032258 0.623032258
+0.130009775 0.622706745
+0.130987292 0.622381232
+0.131964809 0.622055718
+0.132942326 0.621730205
+0.133919844 0.621404692
+0.134897361 0.621079179
+0.135874878 0.620753666
+0.136852395 0.620428152
+0.137829912 0.620102639
+0.138807429 0.619777126
+0.139784946 0.619451613
+0.140762463 0.619126100
+0.141739980 0.618800587
+0.142717498 0.618475073
+0.143695015 0.618149560
+0.144672532 0.617824047
+0.145650049 0.617498534
+0.146627566 0.617173021
+0.147605083 0.616847507
+0.148582600 0.616521994
+0.149560117 0.616196481
+0.150537634 0.615870968
+0.151515152 0.615545455
+0.152492669 0.615219941
+0.153470186 0.614894428
+0.154447703 0.614568915
+0.155425220 0.614243402
+0.156402737 0.613917889
+0.157380254 0.613592375
+0.158357771 0.613266862
+0.159335288 0.612941349
+0.160312805 0.612615836
+0.161290323 0.612290323
+0.162267840 0.611964809
+0.163245357 0.611639296
+0.164222874 0.611313783
+0.165200391 0.610988270
+0.166177908 0.610662757
+0.167155425 0.610337243
+0.168132942 0.610011730
+0.169110459 0.609686217
+0.170087977 0.609360704
+0.171065494 0.609035191
+0.172043011 0.608709677
+0.173020528 0.608384164
+0.173998045 0.608058651
+0.174975562 0.607733138
+0.175953079 0.607407625
+0.176930596 0.607082111
+0.177908113 0.606756598
+0.178885630 0.606431085
+0.179863148 0.606105572
+0.180840665 0.605780059
+0.181818182 0.605454545
+0.182795699 0.605129032
+0.183773216 0.604803519
+0.184750733 0.604478006
+0.185728250 0.604152493
+0.186705767 0.603826979
+0.187683284 0.603501466
+0.188660802 0.603175953
+0.189638319 0.602850440
+0.190615836 0.602524927
+0.191593353 0.602199413
+0.192570870 0.601873900
+0.193548387 0.601548387
+0.194525904 0.601222874
+0.195503421 0.600897361
+0.196480938 0.600571848
+0.197458456 0.600246334
+0.198435973 0.599920821
+0.199413490 0.599595308
+0.200391007 0.599269795
+0.201368524 0.598944282
+0.202346041 0.598618768
+0.203323558 0.598293255
+0.204301075 0.597967742
+0.205278592 0.597642229
+0.206256109 0.597316716
+0.207233627 0.596991202
+0.208211144 0.596665689
+0.209188661 0.596340176
+0.210166178 0.596014663
+0.211143695 0.595689150
+0.212121212 0.595363636
+0.213098729 0.595038123
+0.214076246 0.594712610
+0.215053763 0.594387097
+0.216031281 0.594061584
+0.217008798 0.593736070
+0.217986315 0.593410557
+0.218963832 0.593085044
+0.219941349 0.592759531
+0.220918866 0.592434018
+0.221896383 0.592108504
+0.222873900 0.591782991
+0.223851417 0.591457478
+0.224828935 0.591131965
+0.225806452 0.590806452
+0.226783969 0.590480938
+0.227761486 0.590155425
+0.228739003 0.589829912
+0.229716520 0.589504399
+0.230694037 0.589178886
+0.231671554 0.588853372
+0.232649071 0.588527859
+0.233626588 0.588202346
+0.234604106 0.587876833
+0.235581623 0.587551320
+0.236559140 0.587225806
+0.237536657 0.586900293
+0.238514174 0.586574780
+0.239491691 0.586249267
+0.240469208 0.585923754
+0.241446725 0.585598240
+0.242424242 0.585272727
+0.243401760 0.584947214
+0.244379277 0.584621701
+0.245356794 0.584296188
+0.246334311 0.583970674
+0.247311828 0.583645161
+0.248289345 0.583319648
+0.249266862 0.582994135
+0.250244379 0.582668622
+0.251221896 0.582343109
+0.252199413 0.582017595
+0.253176931 0.581692082
+0.254154448 0.581366569
+0.255131965 0.581041056
+0.256109482 0.580715543
+0.257086999 0.580390029
+0.258064516 0.580064516
+0.259042033 0.579739003
+0.260019550 0.579413490
+0.260997067 0.579087977
+0.261974585 0.578762463
+0.262952102 0.578436950
+0.263929619 0.578111437
+0.264907136 0.577785924
+0.265884653 0.577460411
+0.266862170 0.577134897
+0.267839687 0.576809384
+0.268817204 0.576483871
+0.269794721 0.576158358
+0.270772239 0.575832845
+0.271749756 0.575507331
+0.272727273 0.575181818
+0.273704790 0.574856305
+0.274682307 0.574530792
+0.275659824 0.574205279
+0.276637341 0.573879765
+0.277614858 0.573554252
+0.278592375 0.573228739
+0.279569892 0.572903226
+0.280547410 0.572577713
+0.281524927 0.572252199
+0.282502444 0.571926686
+0.283479961 0.571601173
+0.284457478 0.571275660
+0.285434995 0.570950147
+0.286412512 0.570624633
+0.287390029 0.570299120
+0.288367546 0.569973607
+0.289345064 0.569648094
+0.290322581 0.569322581
+0.291300098 0.568997067
+0.292277615 0.568671554
+0.293255132 0.568346041
+0.294232649 0.568020528
+0.295210166 0.567695015
+0.296187683 0.567369501
+0.297165200 0.567043988
+0.298142717 0.566718475
+0.299120235 0.566392962
+0.300097752 0.566067449
+0.301075269 0.565741935
+0.302052786 0.565416422
+0.303030303 0.565090909
+0.304007820 0.564765396
+0.304985337 0.564439883
+0.305962854 0.564114370
+0.306940371 0.563788856
+0.307917889 0.563463343
+0.308895406 0.563137830
+0.309872923 0.562812317
+0.310850440 0.562486804
+0.311827957 0.562161290
+0.312805474 0.561835777
+0.313782991 0.561510264
+0.314760508 0.561184751
+0.315738025 0.560859238
+0.316715543 0.560533724
+0.317693060 0.560208211
+0.318670577 0.559882698
+0.319648094 0.559557185
+0.320625611 0.559231672
+0.321603128 0.558906158
+0.322580645 0.558580645
+0.323558162 0.558255132
+0.324535679 0.557929619
+0.325513196 0.557604106
+0.326490714 0.557278592
+0.327468231 0.556953079
+0.328445748 0.556627566
+0.329423265 0.556302053
+0.330400782 0.555976540
+0.331378299 0.555651026
+0.332355816 0.555325513
+0.333333333 0.555000000
+0.334310850 0.554674487
+0.335288368 0.554348974
+0.336265885 0.554023460
+0.337243402 0.553697947
+0.338220919 0.553372434
+0.339198436 0.553046921
+0.340175953 0.552721408
+0.341153470 0.552395894
+0.342130987 0.552070381
+0.343108504 0.551744868
+0.344086022 0.551419355
+0.345063539 0.551093842
+0.346041056 0.550768328
+0.347018573 0.550442815
+0.347996090 0.550117302
+0.348973607 0.549791789
+0.349951124 0.549466276
+0.350928641 0.549140762
+0.351906158 0.548815249
+0.352883675 0.548489736
+0.353861193 0.548164223
+0.354838710 0.547838710
+0.355816227 0.547513196
+0.356793744 0.547187683
+0.357771261 0.546862170
+0.358748778 0.546536657
+0.359726295 0.546211144
+0.360703812 0.545885630
+0.361681329 0.545560117
+0.362658847 0.545234604
+0.363636364 0.544909091
+0.364613881 0.544583578
+0.365591398 0.544258065
+0.366568915 0.543932551
+0.367546432 0.543607038
+0.368523949 0.543281525
+0.369501466 0.542956012
+0.370478983 0.542630499
+0.371456500 0.542304985
+0.372434018 0.541979472
+0.373411535 0.541653959
+0.374389052 0.541328446
+0.375366569 0.541002933
+0.376344086 0.540677419
+0.377321603 0.540351906
+0.378299120 0.540026393
+0.379276637 0.539700880
+0.380254154 0.539375367
+0.381231672 0.539049853
+0.382209189 0.538724340
+0.383186706 0.538398827
+0.384164223 0.538073314
+0.385141740 0.537747801
+0.386119257 0.537422287
+0.387096774 0.537096774
+0.388074291 0.536771261
+0.389051808 0.536445748
+0.390029326 0.536120235
+0.391006843 0.535794721
+0.391984360 0.535469208
+0.392961877 0.535143695
+0.393939394 0.534818182
+0.394916911 0.534492669
+0.395894428 0.534167155
+0.396871945 0.533841642
+0.397849462 0.533516129
+0.398826979 0.533190616
+0.399804497 0.532865103
+0.400782014 0.532539589
+0.401759531 0.532214076
+0.402737048 0.531888563
+0.403714565 0.531563050
+0.404692082 0.531237537
+0.405669599 0.530912023
+0.406647116 0.530586510
+0.407624633 0.530260997
+0.408602151 0.529935484
+0.409579668 0.529609971
+0.410557185 0.529284457
+0.411534702 0.528958944
+0.412512219 0.528633431
+0.413489736 0.528307918
+0.414467253 0.527982405
+0.415444770 0.527656891
+0.416422287 0.527331378
+0.417399804 0.527005865
+0.418377322 0.526680352
+0.419354839 0.526354839
+0.420332356 0.526029326
+0.421309873 0.525703812
+0.422287390 0.525378299
+0.423264907 0.525052786
+0.424242424 0.524727273
+0.425219941 0.524401760
+0.426197458 0.524076246
+0.427174976 0.523750733
+0.428152493 0.523425220
+0.429130010 0.523099707
+0.430107527 0.522774194
+0.431085044 0.522448680
+0.432062561 0.522123167
+0.433040078 0.521797654
+0.434017595 0.521472141
+0.434995112 0.521146628
+0.435972630 0.520821114
+0.436950147 0.520495601
+0.437927664 0.520170088
+0.438905181 0.519844575
+0.439882698 0.519519062
+0.440860215 0.519193548
+0.441837732 0.518868035
+0.442815249 0.518542522
+0.443792766 0.518217009
+0.444770283 0.517891496
+0.445747801 0.517565982
+0.446725318 0.517240469
+0.447702835 0.516914956
+0.448680352 0.516589443
+0.449657869 0.516263930
+0.450635386 0.515938416
+0.451612903 0.515612903
+0.452590420 0.515287390
+0.453567937 0.514961877
+0.454545455 0.514636364
+0.455522972 0.514310850
+0.456500489 0.513985337
+0.457478006 0.513659824
+0.458455523 0.513334311
+0.459433040 0.513008798
+0.460410557 0.512683284
+0.461388074 0.512357771
+0.462365591 0.512032258
+0.463343109 0.511706745
+0.464320626 0.511381232
+0.465298143 0.511055718
+0.466275660 0.510730205
+0.467253177 0.510404692
+0.468230694 0.510079179
+0.469208211 0.509753666
+0.470185728 0.509428152
+0.471163245 0.509102639
+0.472140762 0.508777126
+0.473118280 0.508451613
+0.474095797 0.508126100
+0.475073314 0.507800587
+0.476050831 0.507475073
+0.477028348 0.507149560
+0.478005865 0.506824047
+0.478983382 0.506498534
+0.479960899 0.506173021
+0.480938416 0.505847507
+0.481915934 0.505521994
+0.482893451 0.505196481
+0.483870968 0.504870968
+0.484848485 0.504545455
+0.485826002 0.504219941
+0.486803519 0.503894428
+0.487781036 0.503568915
+0.488758553 0.503243402
+0.489736070 0.502917889
+0.490713587 0.502592375
+0.491691105 0.502266862
+0.492668622 0.501941349
+0.493646139 0.501615836
+0.494623656 0.501290323
+0.495601173 0.500964809
+0.496578690 0.500639296
+0.497556207 0.500313783
+0.498533724 0.499988270
+0.499511241 0.499662757
+0.500488759 0.499337243
+0.501466276 0.499011730
+0.502443793 0.498686217
+0.503421310 0.498360704
+0.504398827 0.498035191
+0.505376344 0.497709677
+0.506353861 0.497384164
+0.507331378 0.497058651
+0.508308895 0.496733138
+0.509286413 0.496407625
+0.510263930 0.496082111
+0.511241447 0.495756598
+0.512218964 0.495431085
+0.513196481 0.495105572
+0.514173998 0.494780059
+0.515151515 0.494454545
+0.516129032 0.494129032
+0.517106549 0.493803519
+0.518084066 0.493478006
+0.519061584 0.493152493
+0.520039101 0.492826979
+0.521016618 0.492501466
+0.521994135 0.492175953
+0.522971652 0.491850440
+0.523949169 0.491524927
+0.524926686 0.491199413
+0.525904203 0.490873900
+0.526881720 0.490548387
+0.527859238 0.490222874
+0.528836755 0.489897361
+0.529814272 0.489571848
+0.530791789 0.489246334
+0.531769306 0.488920821
+0.532746823 0.488595308
+0.533724340 0.488269795
+0.534701857 0.487944282
+0.535679374 0.487618768
+0.536656891 0.487293255
+0.537634409 0.486967742
+0.538611926 0.486642229
+0.539589443 0.486316716
+0.540566960 0.485991202
+0.541544477 0.485665689
+0.542521994 0.485340176
+0.543499511 0.485014663
+0.544477028 0.484689150
+0.545454545 0.484363636
+0.546432063 0.484038123
+0.547409580 0.483712610
+0.548387097 0.483387097
+0.549364614 0.483061584
+0.550342131 0.482736070
+0.551319648 0.482410557
+0.552297165 0.482085044
+0.553274682 0.481759531
+0.554252199 0.481434018
+0.555229717 0.481108504
+0.556207234 0.480782991
+0.557184751 0.480457478
+0.558162268 0.480131965
+0.559139785 0.479806452
+0.560117302 0.479480938
+0.561094819 0.479155425
+0.562072336 0.478829912
+0.563049853 0.478504399
+0.564027370 0.478178886
+0.565004888 0.477853372
+0.565982405 0.477527859
+0.566959922 0.477202346
+0.567937439 0.476876833
+0.568914956 0.476551320
+0.569892473 0.476225806
+0.570869990 0.475900293
+0.571847507 0.475574780
+0.572825024 0.475249267
+0.573802542 0.474923754
+0.574780059 0.474598240
+0.575757576 0.474272727
+0.576735093 0.473947214
+0.577712610 0.473621701
+0.578690127 0.473296188
+0.579667644 0.472970674
+0.580645161 0.472645161
+0.581622678 0.472319648
+0.582600196 0.471994135
+0.583577713 0.471668622
+0.584555230 0.471343109
+0.585532747 0.471017595
+0.586510264 0.470692082
+0.587487781 0.470366569
+0.588465298 0.470041056
+0.589442815 0.469715543
+0.590420332 0.469390029
+0.591397849 0.469064516
+0.592375367 0.468739003
+0.593352884 0.468413490
+0.594330401 0.468087977
+0.595307918 0.467762463
+0.596285435 0.467436950
+0.597262952 0.467111437
+0.598240469 0.466785924
+0.599217986 0.466460411
+0.600195503 0.466134897
+0.601173021 0.465809384
+0.602150538 0.465483871
+0.603128055 0.465158358
+0.604105572 0.464832845
+0.605083089 0.464507331
+0.606060606 0.464181818
+0.607038123 0.463856305
+0.608015640 0.463530792
+0.608993157 0.463205279
+0.609970674 0.462879765
+0.610948192 0.462554252
+0.611925709 0.462228739
+0.612903226 0.461903226
+0.613880743 0.461577713
+0.614858260 0.461252199
+0.615835777 0.460926686
+0.616813294 0.460601173
+0.617790811 0.460275660
+0.618768328 0.459950147
+0.619745846 0.459624633
+0.620723363 0.459299120
+0.621700880 0.458973607
+0.622678397 0.458648094
+0.623655914 0.458322581
+0.624633431 0.457997067
+0.625610948 0.457671554
+0.626588465 0.457346041
+0.627565982 0.457020528
+0.628543500 0.456695015
+0.629521017 0.456369501
+0.630498534 0.456043988
+0.631476051 0.455718475
+0.632453568 0.455392962
+0.633431085 0.455067449
+0.634408602 0.454741935
+0.635386119 0.454416422
+0.636363636 0.454090909
+0.637341153 0.453765396
+0.638318671 0.453439883
+0.639296188 0.453114370
+0.640273705 0.452788856
+0.641251222 0.452463343
+0.642228739 0.452137830
+0.643206256 0.451812317
+0.644183773 0.451486804
+0.645161290 0.451161290
+0.646138807 0.450835777
+0.647116325 0.450510264
+0.648093842 0.450184751
+0.649071359 0.449859238
+0.650048876 0.449533724
+0.651026393 0.449208211
+0.652003910 0.448882698
+0.652981427 0.448557185
+0.653958944 0.448231672
+0.654936461 0.447906158
+0.655913978 0.447580645
+0.656891496 0.447255132
+0.657869013 0.446929619
+0.658846530 0.446604106
+0.659824047 0.446278592
+0.660801564 0.445953079
+0.661779081 0.445627566
+0.662756598 0.445302053
+0.663734115 0.444976540
+0.664711632 0.444651026
+0.665689150 0.444325513
+0.666666667 0.444000000
+0.667644184 0.443674487
+0.668621701 0.443348974
+0.669599218 0.443023460
+0.670576735 0.442697947
+0.671554252 0.442372434
+0.672531769 0.442046921
+0.673509286 0.441721408
+0.674486804 0.441395894
+0.675464321 0.441070381
+0.676441838 0.440744868
+0.677419355 0.440419355
+0.678396872 0.440093842
+0.679374389 0.439768328
+0.680351906 0.439442815
+0.681329423 0.439117302
+0.682306940 0.438791789
+0.683284457 0.438466276
+0.684261975 0.438140762
+0.685239492 0.437815249
+0.686217009 0.437489736
+0.687194526 0.437164223
+0.688172043 0.436838710
+0.689149560 0.436513196
+0.690127077 0.436187683
+0.691104594 0.435862170
+0.692082111 0.435536657
+0.693059629 0.435211144
+0.694037146 0.434885630
+0.695014663 0.434560117
+0.695992180 0.434234604
+0.696969697 0.433909091
+0.697947214 0.433583578
+0.698924731 0.433258065
+0.699902248 0.432932551
+0.700879765 0.432607038
+0.701857283 0.432281525
+0.702834800 0.431956012
+0.703812317 0.431630499
+0.704789834 0.431304985
+0.705767351 0.430979472
+0.706744868 0.430653959
+0.707722385 0.430328446
+0.708699902 0.430002933
+0.709677419 0.429677419
+0.710654936 0.429351906
+0.711632454 0.429026393
+0.712609971 0.428700880
+0.713587488 0.428375367
+0.714565005 0.428049853
+0.715542522 0.427724340
+0.716520039 0.427398827
+0.717497556 0.427073314
+0.718475073 0.426747801
+0.719452590 0.426422287
+0.720430108 0.426096774
+0.721407625 0.425771261
+0.722385142 0.425445748
+0.723362659 0.425120235
+0.724340176 0.424794721
+0.725317693 0.424469208
+0.726295210 0.424143695
+0.727272727 0.423818182
+0.728250244 0.423492669
+0.729227761 0.423167155
+0.730205279 0.422841642
+0.731182796 0.422516129
+0.732160313 0.422190616
+0.733137830 0.421865103
+0.734115347 0.421539589
+0.735092864 0.421214076
+0.736070381 0.420888563
+0.737047898 0.420563050
+0.738025415 0.420237537
+0.739002933 0.419912023
+0.739980450 0.419586510
+0.740957967 0.419260997
+0.741935484 0.418935484
+0.742913001 0.418609971
+0.743890518 0.418284457
+0.744868035 0.417958944
+0.745845552 0.417633431
+0.746823069 0.417307918
+0.747800587 0.416982405
+0.748778104 0.416656891
+0.749755621 0.416331378
+0.750733138 0.416005865
+0.751710655 0.415680352
+0.752688172 0.415354839
+0.753665689 0.415029326
+0.754643206 0.414703812
+0.755620723 0.414378299
+0.756598240 0.414052786
+0.757575758 0.413727273
+0.758553275 0.413401760
+0.759530792 0.413076246
+0.760508309 0.412750733
+0.761485826 0.412425220
+0.762463343 0.412099707
+0.763440860 0.411774194
+0.764418377 0.411448680
+0.765395894 0.411123167
+0.766373412 0.410797654
+0.767350929 0.410472141
+0.768328446 0.410146628
+0.769305963 0.409821114
+0.770283480 0.409495601
+0.771260997 0.409170088
+0.772238514 0.408844575
+0.773216031 0.408519062
+0.774193548 0.408193548
+0.775171065 0.407868035
+0.776148583 0.407542522
+0.777126100 0.407217009
+0.778103617 0.406891496
+0.779081134 0.406565982
+0.780058651 0.406240469
+0.781036168 0.405914956
+0.782013685 0.405589443
+0.782991202 0.405263930
+0.783968719 0.404938416
+0.784946237 0.404612903
+0.785923754 0.404287390
+0.786901271 0.403961877
+0.787878788 0.403636364
+0.788856305 0.403310850
+0.789833822 0.402985337
+0.790811339 0.402659824
+0.791788856 0.402334311
+0.792766373 0.402008798
+0.793743891 0.401683284
+0.794721408 0.401357771
+0.795698925 0.401032258
+0.796676442 0.400706745
+0.797653959 0.400381232
+0.798631476 0.400055718
+0.799608993 0.399730205
+0.800586510 0.399404692
+0.801564027 0.399079179
+0.802541544 0.398753666
+0.803519062 0.398428152
+0.804496579 0.398102639
+0.805474096 0.397777126
+0.806451613 0.397451613
+0.807429130 0.397126100
+0.808406647 0.396800587
+0.809384164 0.396475073
+0.810361681 0.396149560
+0.811339198 0.395824047
+0.812316716 0.395498534
+0.813294233 0.395173021
+0.814271750 0.394847507
+0.815249267 0.394521994
+0.816226784 0.394196481
+0.817204301 0.393870968
+0.818181818 0.393545455
+0.819159335 0.393219941
+0.820136852 0.392894428
+0.821114370 0.392568915
+0.822091887 0.392243402
+0.823069404 0.391917889
+0.824046921 0.391592375
+0.825024438 0.391266862
+0.826001955 0.390941349
+0.826979472 0.390615836
+0.827956989 0.390290323
+0.828934506 0.389964809
+0.829912023 0.389639296
+0.830889541 0.389313783
+0.831867058 0.388988270
+0.832844575 0.388662757
+0.833822092 0.388337243
+0.834799609 0.388011730
+0.835777126 0.387686217
+0.836754643 0.387360704
+0.837732160 0.387035191
+0.838709677 0.386709677
+0.839687195 0.386384164
+0.840664712 0.386058651
+0.841642229 0.385733138
+0.842619746 0.385407625
+0.843597263 0.385082111
+0.844574780 0.384756598
+0.845552297 0.384431085
+0.846529814 0.384105572
+0.847507331 0.383780059
+0.848484848 0.383454545
+0.849462366 0.383129032
+0.850439883 0.382803519
+0.851417400 0.382478006
+0.852394917 0.382152493
+0.853372434 0.381826979
+0.854349951 0.381501466
+0.855327468 0.381175953
+0.856304985 0.380850440
+0.857282502 0.380524927
+0.858260020 0.380199413
+0.859237537 0.379873900
+0.860215054 0.379548387
+0.861192571 0.379222874
+0.862170088 0.378897361
+0.863147605 0.378571848
+0.864125122 0.378246334
+0.865102639 0.377920821
+0.866080156 0.377595308
+0.867057674 0.377269795
+0.868035191 0.376944282
+0.869012708 0.376618768
+0.869990225 0.376293255
+0.870967742 0.375967742
+0.871945259 0.375642229
+0.872922776 0.375316716
+0.873900293 0.374991202
+0.874877810 0.374665689
+0.875855327 0.374340176
+0.876832845 0.374014663
+0.877810362 0.373689150
+0.878787879 0.373363636
+0.879765396 0.373038123
+0.880742913 0.372712610
+0.881720430 0.372387097
+0.882697947 0.372061584
+0.883675464 0.371736070
+0.884652981 0.371410557
+0.885630499 0.371085044
+0.886608016 0.370759531
+0.887585533 0.370434018
+0.888563050 0.370108504
+0.889540567 0.369782991
+0.890518084 0.369457478
+0.891495601 0.369131965
+0.892473118 0.368806452
+0.893450635 0.368480938
+0.894428152 0.368155425
+0.895405670 0.367829912
+0.896383187 0.367504399
+0.897360704 0.367178886
+0.898338221 0.366853372
+0.899315738 0.366527859
+0.900293255 0.366202346
+0.901270772 0.365876833
+0.902248289 0.365551320
+0.903225806 0.365225806
+0.904203324 0.364900293
+0.905180841 0.364574780
+0.906158358 0.364249267
+0.907135875 0.363923754
+0.908113392 0.363598240
+0.909090909 0.363272727
+0.910068426 0.362947214
+0.911045943 0.362621701
+0.912023460 0.362296188
+0.913000978 0.361970674
+0.913978495 0.361645161
+0.914956012 0.361319648
+0.915933529 0.360994135
+0.916911046 0.360668622
+0.917888563 0.360343109
+0.918866080 0.360017595
+0.919843597 0.359692082
+0.920821114 0.359366569
+0.921798631 0.359041056
+0.922776149 0.358715543
+0.923753666 0.358390029
+0.924731183 0.358064516
+0.925708700 0.357739003
+0.926686217 0.357413490
+0.927663734 0.357087977
+0.928641251 0.356762463
+0.929618768 0.356436950
+0.930596285 0.356111437
+0.931573803 0.355785924
+0.932551320 0.355460411
+0.933528837 0.355134897
+0.934506354 0.354809384
+0.935483871 0.354483871
+0.936461388 0.354158358
+0.937438905 0.353832845
+0.938416422 0.353507331
+0.939393939 0.353181818
+0.940371457 0.352856305
+0.941348974 0.352530792
+0.942326491 0.352205279
+0.943304008 0.351879765
+0.944281525 0.351554252
+0.945259042 0.351228739
+0.946236559 0.350903226
+0.947214076 0.350577713
+0.948191593 0.350252199
+0.949169110 0.349926686
+0.950146628 0.349601173
+0.951124145 0.349275660
+0.952101662 0.348950147
+0.953079179 0.348624633
+0.954056696 0.348299120
+0.955034213 0.347973607
+0.956011730 0.347648094
+0.956989247 0.347322581
+0.957966764 0.346997067
+0.958944282 0.346671554
+0.959921799 0.346346041
+0.960899316 0.346020528
+0.961876833 0.345695015
+0.962854350 0.345369501
+0.963831867 0.345043988
+0.964809384 0.344718475
+0.965786901 0.344392962
+0.966764418 0.344067449
+0.967741935 0.343741935
+0.968719453 0.343416422
+0.969696970 0.343090909
+0.970674487 0.342765396
+0.971652004 0.342439883
+0.972629521 0.342114370
+0.973607038 0.341788856
+0.974584555 0.341463343
+0.975562072 0.341137830
+0.976539589 0.340812317
+0.977517107 0.340486804
+0.978494624 0.340161290
+0.979472141 0.339835777
+0.980449658 0.339510264
+0.981427175 0.339184751
+0.982404692 0.338859238
+0.983382209 0.338533724
+0.984359726 0.338208211
+0.985337243 0.337882698
+0.986314761 0.337557185
+0.987292278 0.337231672
+0.988269795 0.336906158
+0.989247312 0.336580645
+0.990224829 0.336255132
+0.991202346 0.335929619
+0.992179863 0.335604106
+0.993157380 0.335278592
+0.994134897 0.334953079
+0.995112414 0.334627566
+0.996089932 0.334302053
+0.997067449 0.333976540
+0.998044966 0.333651026
+0.999022483 0.333325513
+1.000000000 0.333000000
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.fll b/examples/takagi-sugeno/ObstacleAvoidance.fll
new file mode 100644
index 0000000..10b53f4
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.fll
@@ -0,0 +1,25 @@
+Engine: ObstacleAvoidance
+InputVariable: obstacle
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: left Ramp 1.000 0.000
+ term: right Ramp 0.000 1.000
+OutputVariable: tsSteer
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: left Constant 0.333
+ term: right Constant 0.666
+RuleBlock: takagiSugeno
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if obstacle is left then tsSteer is right
+ rule: if obstacle is right then tsSteer is left \ No newline at end of file
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.java b/examples/takagi-sugeno/ObstacleAvoidance.java
new file mode 100644
index 0000000..c7c7f67
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.java
@@ -0,0 +1,60 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class ObstacleAvoidance{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("ObstacleAvoidance");
+engine.setDescription("");
+
+InputVariable obstacle = new InputVariable();
+obstacle.setName("obstacle");
+obstacle.setDescription("");
+obstacle.setEnabled(true);
+obstacle.setRange(0.000, 1.000);
+obstacle.setLockValueInRange(false);
+obstacle.addTerm(new Ramp("left", 1.000, 0.000));
+obstacle.addTerm(new Ramp("right", 0.000, 1.000));
+engine.addInputVariable(obstacle);
+
+OutputVariable tsSteer = new OutputVariable();
+tsSteer.setName("tsSteer");
+tsSteer.setDescription("");
+tsSteer.setEnabled(true);
+tsSteer.setRange(0.000, 1.000);
+tsSteer.setLockValueInRange(false);
+tsSteer.setAggregation(new Maximum());
+tsSteer.setDefuzzifier(new WeightedAverage("Automatic"));
+tsSteer.setDefaultValue(Double.NaN);
+tsSteer.setLockPreviousValue(false);
+tsSteer.addTerm(new Constant("left", 0.333));
+tsSteer.addTerm(new Constant("right", 0.666));
+engine.addOutputVariable(tsSteer);
+
+RuleBlock takagiSugeno = new RuleBlock();
+takagiSugeno.setName("takagiSugeno");
+takagiSugeno.setDescription("");
+takagiSugeno.setEnabled(true);
+takagiSugeno.setConjunction(null);
+takagiSugeno.setDisjunction(null);
+takagiSugeno.setImplication(null);
+takagiSugeno.setActivation(new General());
+takagiSugeno.addRule(Rule.parse("if obstacle is left then tsSteer is right", engine));
+takagiSugeno.addRule(Rule.parse("if obstacle is right then tsSteer is left", engine));
+engine.addRuleBlock(takagiSugeno);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/ObstacleAvoidance.pdf b/examples/takagi-sugeno/ObstacleAvoidance.pdf
new file mode 100644
index 0000000..28d0a7a
--- /dev/null
+++ b/examples/takagi-sugeno/ObstacleAvoidance.pdf
Binary files differ
diff --git a/examples/takagi-sugeno/SimpleDimmer.R b/examples/takagi-sugeno/SimpleDimmer.R
new file mode 100644
index 0000000..8502922
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.R
@@ -0,0 +1,60 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "SimpleDimmer"
+engine.fll = "Engine: SimpleDimmer
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: LOW Constant 0.250
+ term: MEDIUM Constant 0.500
+ term: HIGH Constant 0.750
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW"
+
+engine.fldFile = "SimpleDimmer.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("Ambient vs Power")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(Ambient, Power)) +
+ geom_line(aes(color=Power), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Power vs Ambient")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/SimpleDimmer.cpp b/examples/takagi-sugeno/SimpleDimmer.cpp
new file mode 100644
index 0000000..735096b
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.cpp
@@ -0,0 +1,52 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("SimpleDimmer");
+engine->setDescription("");
+
+InputVariable* Ambient = new InputVariable;
+Ambient->setName("Ambient");
+Ambient->setDescription("");
+Ambient->setEnabled(true);
+Ambient->setRange(0.000, 1.000);
+Ambient->setLockValueInRange(false);
+Ambient->addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient->addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine->addInputVariable(Ambient);
+
+OutputVariable* Power = new OutputVariable;
+Power->setName("Power");
+Power->setDescription("");
+Power->setEnabled(true);
+Power->setRange(0.000, 1.000);
+Power->setLockValueInRange(false);
+Power->setAggregation(fl::null);
+Power->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+Power->setDefaultValue(fl::nan);
+Power->setLockPreviousValue(false);
+Power->addTerm(new Constant("LOW", 0.250));
+Power->addTerm(new Constant("MEDIUM", 0.500));
+Power->addTerm(new Constant("HIGH", 0.750));
+engine->addOutputVariable(Power);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock->addRule(Rule::parse("if Ambient is BRIGHT then Power is LOW", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/takagi-sugeno/SimpleDimmer.fcl b/examples/takagi-sugeno/SimpleDimmer.fcl
new file mode 100644
index 0000000..a30f2c9
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.fcl
@@ -0,0 +1,35 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK SimpleDimmer
+
+VAR_INPUT
+ Ambient: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Power: REAL;
+END_VAR
+
+FUZZIFY Ambient
+ RANGE := (0.000 .. 1.000);
+ TERM DARK := Triangle 0.000 0.250 0.500;
+ TERM MEDIUM := Triangle 0.250 0.500 0.750;
+ TERM BRIGHT := Triangle 0.500 0.750 1.000;
+END_FUZZIFY
+
+DEFUZZIFY Power
+ RANGE := (0.000 .. 1.000);
+ TERM LOW := 0.250;
+ TERM MEDIUM := 0.500;
+ TERM HIGH := 0.750;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ RULE 1 : if Ambient is DARK then Power is HIGH
+ RULE 2 : if Ambient is MEDIUM then Power is MEDIUM
+ RULE 3 : if Ambient is BRIGHT then Power is LOW
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/SimpleDimmer.fis b/examples/takagi-sugeno/SimpleDimmer.fis
new file mode 100644
index 0000000..3988290
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.fis
@@ -0,0 +1,35 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='SimpleDimmer'
+Type='sugeno'
+Version=6.0
+NumInputs=1
+NumOutputs=1
+NumRules=3
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='Ambient'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='DARK':'trimf',[0.000 0.250 0.500]
+MF2='MEDIUM':'trimf',[0.250 0.500 0.750]
+MF3='BRIGHT':'trimf',[0.500 0.750 1.000]
+
+[Output1]
+Name='Power'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='LOW':'constant',[0.250]
+MF2='MEDIUM':'constant',[0.500]
+MF3='HIGH':'constant',[0.750]
+
+[Rules]
+1.000 , 3.000 (1.000) : 1
+2.000 , 2.000 (1.000) : 1
+3.000 , 1.000 (1.000) : 1
diff --git a/examples/takagi-sugeno/SimpleDimmer.fld b/examples/takagi-sugeno/SimpleDimmer.fld
new file mode 100644
index 0000000..9c2d25b
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.fld
@@ -0,0 +1,1025 @@
+Ambient Power
+0.000000000 nan
+0.000977517 0.750000000
+0.001955034 0.750000000
+0.002932551 0.750000000
+0.003910068 0.750000000
+0.004887586 0.750000000
+0.005865103 0.750000000
+0.006842620 0.750000000
+0.007820137 0.750000000
+0.008797654 0.750000000
+0.009775171 0.750000000
+0.010752688 0.750000000
+0.011730205 0.750000000
+0.012707722 0.750000000
+0.013685239 0.750000000
+0.014662757 0.750000000
+0.015640274 0.750000000
+0.016617791 0.750000000
+0.017595308 0.750000000
+0.018572825 0.750000000
+0.019550342 0.750000000
+0.020527859 0.750000000
+0.021505376 0.750000000
+0.022482893 0.750000000
+0.023460411 0.750000000
+0.024437928 0.750000000
+0.025415445 0.750000000
+0.026392962 0.750000000
+0.027370479 0.750000000
+0.028347996 0.750000000
+0.029325513 0.750000000
+0.030303030 0.750000000
+0.031280547 0.750000000
+0.032258065 0.750000000
+0.033235582 0.750000000
+0.034213099 0.750000000
+0.035190616 0.750000000
+0.036168133 0.750000000
+0.037145650 0.750000000
+0.038123167 0.750000000
+0.039100684 0.750000000
+0.040078201 0.750000000
+0.041055718 0.750000000
+0.042033236 0.750000000
+0.043010753 0.750000000
+0.043988270 0.750000000
+0.044965787 0.750000000
+0.045943304 0.750000000
+0.046920821 0.750000000
+0.047898338 0.750000000
+0.048875855 0.750000000
+0.049853372 0.750000000
+0.050830890 0.750000000
+0.051808407 0.750000000
+0.052785924 0.750000000
+0.053763441 0.750000000
+0.054740958 0.750000000
+0.055718475 0.750000000
+0.056695992 0.750000000
+0.057673509 0.750000000
+0.058651026 0.750000000
+0.059628543 0.750000000
+0.060606061 0.750000000
+0.061583578 0.750000000
+0.062561095 0.750000000
+0.063538612 0.750000000
+0.064516129 0.750000000
+0.065493646 0.750000000
+0.066471163 0.750000000
+0.067448680 0.750000000
+0.068426197 0.750000000
+0.069403715 0.750000000
+0.070381232 0.750000000
+0.071358749 0.750000000
+0.072336266 0.750000000
+0.073313783 0.750000000
+0.074291300 0.750000000
+0.075268817 0.750000000
+0.076246334 0.750000000
+0.077223851 0.750000000
+0.078201369 0.750000000
+0.079178886 0.750000000
+0.080156403 0.750000000
+0.081133920 0.750000000
+0.082111437 0.750000000
+0.083088954 0.750000000
+0.084066471 0.750000000
+0.085043988 0.750000000
+0.086021505 0.750000000
+0.086999022 0.750000000
+0.087976540 0.750000000
+0.088954057 0.750000000
+0.089931574 0.750000000
+0.090909091 0.750000000
+0.091886608 0.750000000
+0.092864125 0.750000000
+0.093841642 0.750000000
+0.094819159 0.750000000
+0.095796676 0.750000000
+0.096774194 0.750000000
+0.097751711 0.750000000
+0.098729228 0.750000000
+0.099706745 0.750000000
+0.100684262 0.750000000
+0.101661779 0.750000000
+0.102639296 0.750000000
+0.103616813 0.750000000
+0.104594330 0.750000000
+0.105571848 0.750000000
+0.106549365 0.750000000
+0.107526882 0.750000000
+0.108504399 0.750000000
+0.109481916 0.750000000
+0.110459433 0.750000000
+0.111436950 0.750000000
+0.112414467 0.750000000
+0.113391984 0.750000000
+0.114369501 0.750000000
+0.115347019 0.750000000
+0.116324536 0.750000000
+0.117302053 0.750000000
+0.118279570 0.750000000
+0.119257087 0.750000000
+0.120234604 0.750000000
+0.121212121 0.750000000
+0.122189638 0.750000000
+0.123167155 0.750000000
+0.124144673 0.750000000
+0.125122190 0.750000000
+0.126099707 0.750000000
+0.127077224 0.750000000
+0.128054741 0.750000000
+0.129032258 0.750000000
+0.130009775 0.750000000
+0.130987292 0.750000000
+0.131964809 0.750000000
+0.132942326 0.750000000
+0.133919844 0.750000000
+0.134897361 0.750000000
+0.135874878 0.750000000
+0.136852395 0.750000000
+0.137829912 0.750000000
+0.138807429 0.750000000
+0.139784946 0.750000000
+0.140762463 0.750000000
+0.141739980 0.750000000
+0.142717498 0.750000000
+0.143695015 0.750000000
+0.144672532 0.750000000
+0.145650049 0.750000000
+0.146627566 0.750000000
+0.147605083 0.750000000
+0.148582600 0.750000000
+0.149560117 0.750000000
+0.150537634 0.750000000
+0.151515152 0.750000000
+0.152492669 0.750000000
+0.153470186 0.750000000
+0.154447703 0.750000000
+0.155425220 0.750000000
+0.156402737 0.750000000
+0.157380254 0.750000000
+0.158357771 0.750000000
+0.159335288 0.750000000
+0.160312805 0.750000000
+0.161290323 0.750000000
+0.162267840 0.750000000
+0.163245357 0.750000000
+0.164222874 0.750000000
+0.165200391 0.750000000
+0.166177908 0.750000000
+0.167155425 0.750000000
+0.168132942 0.750000000
+0.169110459 0.750000000
+0.170087977 0.750000000
+0.171065494 0.750000000
+0.172043011 0.750000000
+0.173020528 0.750000000
+0.173998045 0.750000000
+0.174975562 0.750000000
+0.175953079 0.750000000
+0.176930596 0.750000000
+0.177908113 0.750000000
+0.178885630 0.750000000
+0.179863148 0.750000000
+0.180840665 0.750000000
+0.181818182 0.750000000
+0.182795699 0.750000000
+0.183773216 0.750000000
+0.184750733 0.750000000
+0.185728250 0.750000000
+0.186705767 0.750000000
+0.187683284 0.750000000
+0.188660802 0.750000000
+0.189638319 0.750000000
+0.190615836 0.750000000
+0.191593353 0.750000000
+0.192570870 0.750000000
+0.193548387 0.750000000
+0.194525904 0.750000000
+0.195503421 0.750000000
+0.196480938 0.750000000
+0.197458456 0.750000000
+0.198435973 0.750000000
+0.199413490 0.750000000
+0.200391007 0.750000000
+0.201368524 0.750000000
+0.202346041 0.750000000
+0.203323558 0.750000000
+0.204301075 0.750000000
+0.205278592 0.750000000
+0.206256109 0.750000000
+0.207233627 0.750000000
+0.208211144 0.750000000
+0.209188661 0.750000000
+0.210166178 0.750000000
+0.211143695 0.750000000
+0.212121212 0.750000000
+0.213098729 0.750000000
+0.214076246 0.750000000
+0.215053763 0.750000000
+0.216031281 0.750000000
+0.217008798 0.750000000
+0.217986315 0.750000000
+0.218963832 0.750000000
+0.219941349 0.750000000
+0.220918866 0.750000000
+0.221896383 0.750000000
+0.222873900 0.750000000
+0.223851417 0.750000000
+0.224828935 0.750000000
+0.225806452 0.750000000
+0.226783969 0.750000000
+0.227761486 0.750000000
+0.228739003 0.750000000
+0.229716520 0.750000000
+0.230694037 0.750000000
+0.231671554 0.750000000
+0.232649071 0.750000000
+0.233626588 0.750000000
+0.234604106 0.750000000
+0.235581623 0.750000000
+0.236559140 0.750000000
+0.237536657 0.750000000
+0.238514174 0.750000000
+0.239491691 0.750000000
+0.240469208 0.750000000
+0.241446725 0.750000000
+0.242424242 0.750000000
+0.243401760 0.750000000
+0.244379277 0.750000000
+0.245356794 0.750000000
+0.246334311 0.750000000
+0.247311828 0.750000000
+0.248289345 0.750000000
+0.249266862 0.750000000
+0.250244379 0.749755621
+0.251221896 0.748778104
+0.252199413 0.747800587
+0.253176931 0.746823069
+0.254154448 0.745845552
+0.255131965 0.744868035
+0.256109482 0.743890518
+0.257086999 0.742913001
+0.258064516 0.741935484
+0.259042033 0.740957967
+0.260019550 0.739980450
+0.260997067 0.739002933
+0.261974585 0.738025415
+0.262952102 0.737047898
+0.263929619 0.736070381
+0.264907136 0.735092864
+0.265884653 0.734115347
+0.266862170 0.733137830
+0.267839687 0.732160313
+0.268817204 0.731182796
+0.269794721 0.730205279
+0.270772239 0.729227761
+0.271749756 0.728250244
+0.272727273 0.727272727
+0.273704790 0.726295210
+0.274682307 0.725317693
+0.275659824 0.724340176
+0.276637341 0.723362659
+0.277614858 0.722385142
+0.278592375 0.721407625
+0.279569892 0.720430108
+0.280547410 0.719452590
+0.281524927 0.718475073
+0.282502444 0.717497556
+0.283479961 0.716520039
+0.284457478 0.715542522
+0.285434995 0.714565005
+0.286412512 0.713587488
+0.287390029 0.712609971
+0.288367546 0.711632454
+0.289345064 0.710654936
+0.290322581 0.709677419
+0.291300098 0.708699902
+0.292277615 0.707722385
+0.293255132 0.706744868
+0.294232649 0.705767351
+0.295210166 0.704789834
+0.296187683 0.703812317
+0.297165200 0.702834800
+0.298142717 0.701857283
+0.299120235 0.700879765
+0.300097752 0.699902248
+0.301075269 0.698924731
+0.302052786 0.697947214
+0.303030303 0.696969697
+0.304007820 0.695992180
+0.304985337 0.695014663
+0.305962854 0.694037146
+0.306940371 0.693059629
+0.307917889 0.692082111
+0.308895406 0.691104594
+0.309872923 0.690127077
+0.310850440 0.689149560
+0.311827957 0.688172043
+0.312805474 0.687194526
+0.313782991 0.686217009
+0.314760508 0.685239492
+0.315738025 0.684261975
+0.316715543 0.683284457
+0.317693060 0.682306940
+0.318670577 0.681329423
+0.319648094 0.680351906
+0.320625611 0.679374389
+0.321603128 0.678396872
+0.322580645 0.677419355
+0.323558162 0.676441838
+0.324535679 0.675464321
+0.325513196 0.674486804
+0.326490714 0.673509286
+0.327468231 0.672531769
+0.328445748 0.671554252
+0.329423265 0.670576735
+0.330400782 0.669599218
+0.331378299 0.668621701
+0.332355816 0.667644184
+0.333333333 0.666666667
+0.334310850 0.665689150
+0.335288368 0.664711632
+0.336265885 0.663734115
+0.337243402 0.662756598
+0.338220919 0.661779081
+0.339198436 0.660801564
+0.340175953 0.659824047
+0.341153470 0.658846530
+0.342130987 0.657869013
+0.343108504 0.656891496
+0.344086022 0.655913978
+0.345063539 0.654936461
+0.346041056 0.653958944
+0.347018573 0.652981427
+0.347996090 0.652003910
+0.348973607 0.651026393
+0.349951124 0.650048876
+0.350928641 0.649071359
+0.351906158 0.648093842
+0.352883675 0.647116325
+0.353861193 0.646138807
+0.354838710 0.645161290
+0.355816227 0.644183773
+0.356793744 0.643206256
+0.357771261 0.642228739
+0.358748778 0.641251222
+0.359726295 0.640273705
+0.360703812 0.639296188
+0.361681329 0.638318671
+0.362658847 0.637341153
+0.363636364 0.636363636
+0.364613881 0.635386119
+0.365591398 0.634408602
+0.366568915 0.633431085
+0.367546432 0.632453568
+0.368523949 0.631476051
+0.369501466 0.630498534
+0.370478983 0.629521017
+0.371456500 0.628543500
+0.372434018 0.627565982
+0.373411535 0.626588465
+0.374389052 0.625610948
+0.375366569 0.624633431
+0.376344086 0.623655914
+0.377321603 0.622678397
+0.378299120 0.621700880
+0.379276637 0.620723363
+0.380254154 0.619745846
+0.381231672 0.618768328
+0.382209189 0.617790811
+0.383186706 0.616813294
+0.384164223 0.615835777
+0.385141740 0.614858260
+0.386119257 0.613880743
+0.387096774 0.612903226
+0.388074291 0.611925709
+0.389051808 0.610948192
+0.390029326 0.609970674
+0.391006843 0.608993157
+0.391984360 0.608015640
+0.392961877 0.607038123
+0.393939394 0.606060606
+0.394916911 0.605083089
+0.395894428 0.604105572
+0.396871945 0.603128055
+0.397849462 0.602150538
+0.398826979 0.601173021
+0.399804497 0.600195503
+0.400782014 0.599217986
+0.401759531 0.598240469
+0.402737048 0.597262952
+0.403714565 0.596285435
+0.404692082 0.595307918
+0.405669599 0.594330401
+0.406647116 0.593352884
+0.407624633 0.592375367
+0.408602151 0.591397849
+0.409579668 0.590420332
+0.410557185 0.589442815
+0.411534702 0.588465298
+0.412512219 0.587487781
+0.413489736 0.586510264
+0.414467253 0.585532747
+0.415444770 0.584555230
+0.416422287 0.583577713
+0.417399804 0.582600196
+0.418377322 0.581622678
+0.419354839 0.580645161
+0.420332356 0.579667644
+0.421309873 0.578690127
+0.422287390 0.577712610
+0.423264907 0.576735093
+0.424242424 0.575757576
+0.425219941 0.574780059
+0.426197458 0.573802542
+0.427174976 0.572825024
+0.428152493 0.571847507
+0.429130010 0.570869990
+0.430107527 0.569892473
+0.431085044 0.568914956
+0.432062561 0.567937439
+0.433040078 0.566959922
+0.434017595 0.565982405
+0.434995112 0.565004888
+0.435972630 0.564027370
+0.436950147 0.563049853
+0.437927664 0.562072336
+0.438905181 0.561094819
+0.439882698 0.560117302
+0.440860215 0.559139785
+0.441837732 0.558162268
+0.442815249 0.557184751
+0.443792766 0.556207234
+0.444770283 0.555229717
+0.445747801 0.554252199
+0.446725318 0.553274682
+0.447702835 0.552297165
+0.448680352 0.551319648
+0.449657869 0.550342131
+0.450635386 0.549364614
+0.451612903 0.548387097
+0.452590420 0.547409580
+0.453567937 0.546432063
+0.454545455 0.545454545
+0.455522972 0.544477028
+0.456500489 0.543499511
+0.457478006 0.542521994
+0.458455523 0.541544477
+0.459433040 0.540566960
+0.460410557 0.539589443
+0.461388074 0.538611926
+0.462365591 0.537634409
+0.463343109 0.536656891
+0.464320626 0.535679374
+0.465298143 0.534701857
+0.466275660 0.533724340
+0.467253177 0.532746823
+0.468230694 0.531769306
+0.469208211 0.530791789
+0.470185728 0.529814272
+0.471163245 0.528836755
+0.472140762 0.527859238
+0.473118280 0.526881720
+0.474095797 0.525904203
+0.475073314 0.524926686
+0.476050831 0.523949169
+0.477028348 0.522971652
+0.478005865 0.521994135
+0.478983382 0.521016618
+0.479960899 0.520039101
+0.480938416 0.519061584
+0.481915934 0.518084066
+0.482893451 0.517106549
+0.483870968 0.516129032
+0.484848485 0.515151515
+0.485826002 0.514173998
+0.486803519 0.513196481
+0.487781036 0.512218964
+0.488758553 0.511241447
+0.489736070 0.510263930
+0.490713587 0.509286413
+0.491691105 0.508308895
+0.492668622 0.507331378
+0.493646139 0.506353861
+0.494623656 0.505376344
+0.495601173 0.504398827
+0.496578690 0.503421310
+0.497556207 0.502443793
+0.498533724 0.501466276
+0.499511241 0.500488759
+0.500488759 0.499511241
+0.501466276 0.498533724
+0.502443793 0.497556207
+0.503421310 0.496578690
+0.504398827 0.495601173
+0.505376344 0.494623656
+0.506353861 0.493646139
+0.507331378 0.492668622
+0.508308895 0.491691105
+0.509286413 0.490713587
+0.510263930 0.489736070
+0.511241447 0.488758553
+0.512218964 0.487781036
+0.513196481 0.486803519
+0.514173998 0.485826002
+0.515151515 0.484848485
+0.516129032 0.483870968
+0.517106549 0.482893451
+0.518084066 0.481915934
+0.519061584 0.480938416
+0.520039101 0.479960899
+0.521016618 0.478983382
+0.521994135 0.478005865
+0.522971652 0.477028348
+0.523949169 0.476050831
+0.524926686 0.475073314
+0.525904203 0.474095797
+0.526881720 0.473118280
+0.527859238 0.472140762
+0.528836755 0.471163245
+0.529814272 0.470185728
+0.530791789 0.469208211
+0.531769306 0.468230694
+0.532746823 0.467253177
+0.533724340 0.466275660
+0.534701857 0.465298143
+0.535679374 0.464320626
+0.536656891 0.463343109
+0.537634409 0.462365591
+0.538611926 0.461388074
+0.539589443 0.460410557
+0.540566960 0.459433040
+0.541544477 0.458455523
+0.542521994 0.457478006
+0.543499511 0.456500489
+0.544477028 0.455522972
+0.545454545 0.454545455
+0.546432063 0.453567937
+0.547409580 0.452590420
+0.548387097 0.451612903
+0.549364614 0.450635386
+0.550342131 0.449657869
+0.551319648 0.448680352
+0.552297165 0.447702835
+0.553274682 0.446725318
+0.554252199 0.445747801
+0.555229717 0.444770283
+0.556207234 0.443792766
+0.557184751 0.442815249
+0.558162268 0.441837732
+0.559139785 0.440860215
+0.560117302 0.439882698
+0.561094819 0.438905181
+0.562072336 0.437927664
+0.563049853 0.436950147
+0.564027370 0.435972630
+0.565004888 0.434995112
+0.565982405 0.434017595
+0.566959922 0.433040078
+0.567937439 0.432062561
+0.568914956 0.431085044
+0.569892473 0.430107527
+0.570869990 0.429130010
+0.571847507 0.428152493
+0.572825024 0.427174976
+0.573802542 0.426197458
+0.574780059 0.425219941
+0.575757576 0.424242424
+0.576735093 0.423264907
+0.577712610 0.422287390
+0.578690127 0.421309873
+0.579667644 0.420332356
+0.580645161 0.419354839
+0.581622678 0.418377322
+0.582600196 0.417399804
+0.583577713 0.416422287
+0.584555230 0.415444770
+0.585532747 0.414467253
+0.586510264 0.413489736
+0.587487781 0.412512219
+0.588465298 0.411534702
+0.589442815 0.410557185
+0.590420332 0.409579668
+0.591397849 0.408602151
+0.592375367 0.407624633
+0.593352884 0.406647116
+0.594330401 0.405669599
+0.595307918 0.404692082
+0.596285435 0.403714565
+0.597262952 0.402737048
+0.598240469 0.401759531
+0.599217986 0.400782014
+0.600195503 0.399804497
+0.601173021 0.398826979
+0.602150538 0.397849462
+0.603128055 0.396871945
+0.604105572 0.395894428
+0.605083089 0.394916911
+0.606060606 0.393939394
+0.607038123 0.392961877
+0.608015640 0.391984360
+0.608993157 0.391006843
+0.609970674 0.390029326
+0.610948192 0.389051808
+0.611925709 0.388074291
+0.612903226 0.387096774
+0.613880743 0.386119257
+0.614858260 0.385141740
+0.615835777 0.384164223
+0.616813294 0.383186706
+0.617790811 0.382209189
+0.618768328 0.381231672
+0.619745846 0.380254154
+0.620723363 0.379276637
+0.621700880 0.378299120
+0.622678397 0.377321603
+0.623655914 0.376344086
+0.624633431 0.375366569
+0.625610948 0.374389052
+0.626588465 0.373411535
+0.627565982 0.372434018
+0.628543500 0.371456500
+0.629521017 0.370478983
+0.630498534 0.369501466
+0.631476051 0.368523949
+0.632453568 0.367546432
+0.633431085 0.366568915
+0.634408602 0.365591398
+0.635386119 0.364613881
+0.636363636 0.363636364
+0.637341153 0.362658847
+0.638318671 0.361681329
+0.639296188 0.360703812
+0.640273705 0.359726295
+0.641251222 0.358748778
+0.642228739 0.357771261
+0.643206256 0.356793744
+0.644183773 0.355816227
+0.645161290 0.354838710
+0.646138807 0.353861193
+0.647116325 0.352883675
+0.648093842 0.351906158
+0.649071359 0.350928641
+0.650048876 0.349951124
+0.651026393 0.348973607
+0.652003910 0.347996090
+0.652981427 0.347018573
+0.653958944 0.346041056
+0.654936461 0.345063539
+0.655913978 0.344086022
+0.656891496 0.343108504
+0.657869013 0.342130987
+0.658846530 0.341153470
+0.659824047 0.340175953
+0.660801564 0.339198436
+0.661779081 0.338220919
+0.662756598 0.337243402
+0.663734115 0.336265885
+0.664711632 0.335288368
+0.665689150 0.334310850
+0.666666667 0.333333333
+0.667644184 0.332355816
+0.668621701 0.331378299
+0.669599218 0.330400782
+0.670576735 0.329423265
+0.671554252 0.328445748
+0.672531769 0.327468231
+0.673509286 0.326490714
+0.674486804 0.325513196
+0.675464321 0.324535679
+0.676441838 0.323558162
+0.677419355 0.322580645
+0.678396872 0.321603128
+0.679374389 0.320625611
+0.680351906 0.319648094
+0.681329423 0.318670577
+0.682306940 0.317693060
+0.683284457 0.316715543
+0.684261975 0.315738025
+0.685239492 0.314760508
+0.686217009 0.313782991
+0.687194526 0.312805474
+0.688172043 0.311827957
+0.689149560 0.310850440
+0.690127077 0.309872923
+0.691104594 0.308895406
+0.692082111 0.307917889
+0.693059629 0.306940371
+0.694037146 0.305962854
+0.695014663 0.304985337
+0.695992180 0.304007820
+0.696969697 0.303030303
+0.697947214 0.302052786
+0.698924731 0.301075269
+0.699902248 0.300097752
+0.700879765 0.299120235
+0.701857283 0.298142717
+0.702834800 0.297165200
+0.703812317 0.296187683
+0.704789834 0.295210166
+0.705767351 0.294232649
+0.706744868 0.293255132
+0.707722385 0.292277615
+0.708699902 0.291300098
+0.709677419 0.290322581
+0.710654936 0.289345064
+0.711632454 0.288367546
+0.712609971 0.287390029
+0.713587488 0.286412512
+0.714565005 0.285434995
+0.715542522 0.284457478
+0.716520039 0.283479961
+0.717497556 0.282502444
+0.718475073 0.281524927
+0.719452590 0.280547410
+0.720430108 0.279569892
+0.721407625 0.278592375
+0.722385142 0.277614858
+0.723362659 0.276637341
+0.724340176 0.275659824
+0.725317693 0.274682307
+0.726295210 0.273704790
+0.727272727 0.272727273
+0.728250244 0.271749756
+0.729227761 0.270772239
+0.730205279 0.269794721
+0.731182796 0.268817204
+0.732160313 0.267839687
+0.733137830 0.266862170
+0.734115347 0.265884653
+0.735092864 0.264907136
+0.736070381 0.263929619
+0.737047898 0.262952102
+0.738025415 0.261974585
+0.739002933 0.260997067
+0.739980450 0.260019550
+0.740957967 0.259042033
+0.741935484 0.258064516
+0.742913001 0.257086999
+0.743890518 0.256109482
+0.744868035 0.255131965
+0.745845552 0.254154448
+0.746823069 0.253176931
+0.747800587 0.252199413
+0.748778104 0.251221896
+0.749755621 0.250244379
+0.750733138 0.250000000
+0.751710655 0.250000000
+0.752688172 0.250000000
+0.753665689 0.250000000
+0.754643206 0.250000000
+0.755620723 0.250000000
+0.756598240 0.250000000
+0.757575758 0.250000000
+0.758553275 0.250000000
+0.759530792 0.250000000
+0.760508309 0.250000000
+0.761485826 0.250000000
+0.762463343 0.250000000
+0.763440860 0.250000000
+0.764418377 0.250000000
+0.765395894 0.250000000
+0.766373412 0.250000000
+0.767350929 0.250000000
+0.768328446 0.250000000
+0.769305963 0.250000000
+0.770283480 0.250000000
+0.771260997 0.250000000
+0.772238514 0.250000000
+0.773216031 0.250000000
+0.774193548 0.250000000
+0.775171065 0.250000000
+0.776148583 0.250000000
+0.777126100 0.250000000
+0.778103617 0.250000000
+0.779081134 0.250000000
+0.780058651 0.250000000
+0.781036168 0.250000000
+0.782013685 0.250000000
+0.782991202 0.250000000
+0.783968719 0.250000000
+0.784946237 0.250000000
+0.785923754 0.250000000
+0.786901271 0.250000000
+0.787878788 0.250000000
+0.788856305 0.250000000
+0.789833822 0.250000000
+0.790811339 0.250000000
+0.791788856 0.250000000
+0.792766373 0.250000000
+0.793743891 0.250000000
+0.794721408 0.250000000
+0.795698925 0.250000000
+0.796676442 0.250000000
+0.797653959 0.250000000
+0.798631476 0.250000000
+0.799608993 0.250000000
+0.800586510 0.250000000
+0.801564027 0.250000000
+0.802541544 0.250000000
+0.803519062 0.250000000
+0.804496579 0.250000000
+0.805474096 0.250000000
+0.806451613 0.250000000
+0.807429130 0.250000000
+0.808406647 0.250000000
+0.809384164 0.250000000
+0.810361681 0.250000000
+0.811339198 0.250000000
+0.812316716 0.250000000
+0.813294233 0.250000000
+0.814271750 0.250000000
+0.815249267 0.250000000
+0.816226784 0.250000000
+0.817204301 0.250000000
+0.818181818 0.250000000
+0.819159335 0.250000000
+0.820136852 0.250000000
+0.821114370 0.250000000
+0.822091887 0.250000000
+0.823069404 0.250000000
+0.824046921 0.250000000
+0.825024438 0.250000000
+0.826001955 0.250000000
+0.826979472 0.250000000
+0.827956989 0.250000000
+0.828934506 0.250000000
+0.829912023 0.250000000
+0.830889541 0.250000000
+0.831867058 0.250000000
+0.832844575 0.250000000
+0.833822092 0.250000000
+0.834799609 0.250000000
+0.835777126 0.250000000
+0.836754643 0.250000000
+0.837732160 0.250000000
+0.838709677 0.250000000
+0.839687195 0.250000000
+0.840664712 0.250000000
+0.841642229 0.250000000
+0.842619746 0.250000000
+0.843597263 0.250000000
+0.844574780 0.250000000
+0.845552297 0.250000000
+0.846529814 0.250000000
+0.847507331 0.250000000
+0.848484848 0.250000000
+0.849462366 0.250000000
+0.850439883 0.250000000
+0.851417400 0.250000000
+0.852394917 0.250000000
+0.853372434 0.250000000
+0.854349951 0.250000000
+0.855327468 0.250000000
+0.856304985 0.250000000
+0.857282502 0.250000000
+0.858260020 0.250000000
+0.859237537 0.250000000
+0.860215054 0.250000000
+0.861192571 0.250000000
+0.862170088 0.250000000
+0.863147605 0.250000000
+0.864125122 0.250000000
+0.865102639 0.250000000
+0.866080156 0.250000000
+0.867057674 0.250000000
+0.868035191 0.250000000
+0.869012708 0.250000000
+0.869990225 0.250000000
+0.870967742 0.250000000
+0.871945259 0.250000000
+0.872922776 0.250000000
+0.873900293 0.250000000
+0.874877810 0.250000000
+0.875855327 0.250000000
+0.876832845 0.250000000
+0.877810362 0.250000000
+0.878787879 0.250000000
+0.879765396 0.250000000
+0.880742913 0.250000000
+0.881720430 0.250000000
+0.882697947 0.250000000
+0.883675464 0.250000000
+0.884652981 0.250000000
+0.885630499 0.250000000
+0.886608016 0.250000000
+0.887585533 0.250000000
+0.888563050 0.250000000
+0.889540567 0.250000000
+0.890518084 0.250000000
+0.891495601 0.250000000
+0.892473118 0.250000000
+0.893450635 0.250000000
+0.894428152 0.250000000
+0.895405670 0.250000000
+0.896383187 0.250000000
+0.897360704 0.250000000
+0.898338221 0.250000000
+0.899315738 0.250000000
+0.900293255 0.250000000
+0.901270772 0.250000000
+0.902248289 0.250000000
+0.903225806 0.250000000
+0.904203324 0.250000000
+0.905180841 0.250000000
+0.906158358 0.250000000
+0.907135875 0.250000000
+0.908113392 0.250000000
+0.909090909 0.250000000
+0.910068426 0.250000000
+0.911045943 0.250000000
+0.912023460 0.250000000
+0.913000978 0.250000000
+0.913978495 0.250000000
+0.914956012 0.250000000
+0.915933529 0.250000000
+0.916911046 0.250000000
+0.917888563 0.250000000
+0.918866080 0.250000000
+0.919843597 0.250000000
+0.920821114 0.250000000
+0.921798631 0.250000000
+0.922776149 0.250000000
+0.923753666 0.250000000
+0.924731183 0.250000000
+0.925708700 0.250000000
+0.926686217 0.250000000
+0.927663734 0.250000000
+0.928641251 0.250000000
+0.929618768 0.250000000
+0.930596285 0.250000000
+0.931573803 0.250000000
+0.932551320 0.250000000
+0.933528837 0.250000000
+0.934506354 0.250000000
+0.935483871 0.250000000
+0.936461388 0.250000000
+0.937438905 0.250000000
+0.938416422 0.250000000
+0.939393939 0.250000000
+0.940371457 0.250000000
+0.941348974 0.250000000
+0.942326491 0.250000000
+0.943304008 0.250000000
+0.944281525 0.250000000
+0.945259042 0.250000000
+0.946236559 0.250000000
+0.947214076 0.250000000
+0.948191593 0.250000000
+0.949169110 0.250000000
+0.950146628 0.250000000
+0.951124145 0.250000000
+0.952101662 0.250000000
+0.953079179 0.250000000
+0.954056696 0.250000000
+0.955034213 0.250000000
+0.956011730 0.250000000
+0.956989247 0.250000000
+0.957966764 0.250000000
+0.958944282 0.250000000
+0.959921799 0.250000000
+0.960899316 0.250000000
+0.961876833 0.250000000
+0.962854350 0.250000000
+0.963831867 0.250000000
+0.964809384 0.250000000
+0.965786901 0.250000000
+0.966764418 0.250000000
+0.967741935 0.250000000
+0.968719453 0.250000000
+0.969696970 0.250000000
+0.970674487 0.250000000
+0.971652004 0.250000000
+0.972629521 0.250000000
+0.973607038 0.250000000
+0.974584555 0.250000000
+0.975562072 0.250000000
+0.976539589 0.250000000
+0.977517107 0.250000000
+0.978494624 0.250000000
+0.979472141 0.250000000
+0.980449658 0.250000000
+0.981427175 0.250000000
+0.982404692 0.250000000
+0.983382209 0.250000000
+0.984359726 0.250000000
+0.985337243 0.250000000
+0.986314761 0.250000000
+0.987292278 0.250000000
+0.988269795 0.250000000
+0.989247312 0.250000000
+0.990224829 0.250000000
+0.991202346 0.250000000
+0.992179863 0.250000000
+0.993157380 0.250000000
+0.994134897 0.250000000
+0.995112414 0.250000000
+0.996089932 0.250000000
+0.997067449 0.250000000
+0.998044966 0.250000000
+0.999022483 0.250000000
+1.000000000 nan
diff --git a/examples/takagi-sugeno/SimpleDimmer.fll b/examples/takagi-sugeno/SimpleDimmer.fll
new file mode 100644
index 0000000..f08e563
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.fll
@@ -0,0 +1,28 @@
+Engine: SimpleDimmer
+InputVariable: Ambient
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ term: DARK Triangle 0.000 0.250 0.500
+ term: MEDIUM Triangle 0.250 0.500 0.750
+ term: BRIGHT Triangle 0.500 0.750 1.000
+OutputVariable: Power
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: LOW Constant 0.250
+ term: MEDIUM Constant 0.500
+ term: HIGH Constant 0.750
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if Ambient is DARK then Power is HIGH
+ rule: if Ambient is MEDIUM then Power is MEDIUM
+ rule: if Ambient is BRIGHT then Power is LOW \ No newline at end of file
diff --git a/examples/takagi-sugeno/SimpleDimmer.java b/examples/takagi-sugeno/SimpleDimmer.java
new file mode 100644
index 0000000..c3c53e9
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.java
@@ -0,0 +1,63 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class SimpleDimmer{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("SimpleDimmer");
+engine.setDescription("");
+
+InputVariable Ambient = new InputVariable();
+Ambient.setName("Ambient");
+Ambient.setDescription("");
+Ambient.setEnabled(true);
+Ambient.setRange(0.000, 1.000);
+Ambient.setLockValueInRange(false);
+Ambient.addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+Ambient.addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+Ambient.addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+engine.addInputVariable(Ambient);
+
+OutputVariable Power = new OutputVariable();
+Power.setName("Power");
+Power.setDescription("");
+Power.setEnabled(true);
+Power.setRange(0.000, 1.000);
+Power.setLockValueInRange(false);
+Power.setAggregation(null);
+Power.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+Power.setDefaultValue(Double.NaN);
+Power.setLockPreviousValue(false);
+Power.addTerm(new Constant("LOW", 0.250));
+Power.addTerm(new Constant("MEDIUM", 0.500));
+Power.addTerm(new Constant("HIGH", 0.750));
+engine.addOutputVariable(Power);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if Ambient is DARK then Power is HIGH", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
+ruleBlock.addRule(Rule.parse("if Ambient is BRIGHT then Power is LOW", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/SimpleDimmer.pdf b/examples/takagi-sugeno/SimpleDimmer.pdf
new file mode 100644
index 0000000..f35dec9
--- /dev/null
+++ b/examples/takagi-sugeno/SimpleDimmer.pdf
Binary files differ
diff --git a/examples/takagi-sugeno/approximation.R b/examples/takagi-sugeno/approximation.R
new file mode 100644
index 0000000..89c0654
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.R
@@ -0,0 +1,119 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "approximation"
+engine.fll = "Engine: approximation
+InputVariable: inputX
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ term: NEAR_1 Triangle 0.000 1.000 2.000
+ term: NEAR_2 Triangle 1.000 2.000 3.000
+ term: NEAR_3 Triangle 2.000 3.000 4.000
+ term: NEAR_4 Triangle 3.000 4.000 5.000
+ term: NEAR_5 Triangle 4.000 5.000 6.000
+ term: NEAR_6 Triangle 5.000 6.000 7.000
+ term: NEAR_7 Triangle 6.000 7.000 8.000
+ term: NEAR_8 Triangle 7.000 8.000 9.000
+ term: NEAR_9 Triangle 8.000 9.000 10.000
+OutputVariable: outputFx
+ enabled: true
+ range: -1.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: true
+ term: f1 Constant 0.840
+ term: f2 Constant 0.450
+ term: f3 Constant 0.040
+ term: f4 Constant -0.180
+ term: f5 Constant -0.190
+ term: f6 Constant -0.040
+ term: f7 Constant 0.090
+ term: f8 Constant 0.120
+ term: f9 Constant 0.040
+OutputVariable: trueFx
+ enabled: true
+ range: -1.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: true
+ term: fx Function sin(inputX)/inputX
+OutputVariable: diffFx
+ enabled: true
+ range: -1.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: diff Function fabs(outputFx-trueFx)
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if inputX is NEAR_1 then outputFx is f1
+ rule: if inputX is NEAR_2 then outputFx is f2
+ rule: if inputX is NEAR_3 then outputFx is f3
+ rule: if inputX is NEAR_4 then outputFx is f4
+ rule: if inputX is NEAR_5 then outputFx is f5
+ rule: if inputX is NEAR_6 then outputFx is f6
+ rule: if inputX is NEAR_7 then outputFx is f7
+ rule: if inputX is NEAR_8 then outputFx is f8
+ rule: if inputX is NEAR_9 then outputFx is f9
+ rule: if inputX is any then trueFx is fx and diffFx is diff"
+
+engine.fldFile = "approximation.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(inputX, outputFx)) +
+ geom_line(aes(color=outputFx), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("inputX vs outputFx")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(inputX, outputFx)) +
+ geom_line(aes(color=outputFx), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("outputFx vs inputX")
+
+engine.plot.i1_o2 = ggplot(engine.df, aes(inputX, trueFx)) +
+ geom_line(aes(color=trueFx), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("inputX vs trueFx")
+
+engine.plot.o2_i1 = ggplot(engine.df, aes(inputX, trueFx)) +
+ geom_line(aes(color=trueFx), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("trueFx vs inputX")
+
+engine.plot.i1_o3 = ggplot(engine.df, aes(inputX, diffFx)) +
+ geom_line(aes(color=diffFx), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("inputX vs diffFx")
+
+engine.plot.o3_i1 = ggplot(engine.df, aes(inputX, diffFx)) +
+ geom_line(aes(color=diffFx), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("diffFx vs inputX")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, engine.plot.i1_o2, engine.plot.o2_i1, engine.plot.i1_o3, engine.plot.o3_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/approximation.cpp b/examples/takagi-sugeno/approximation.cpp
new file mode 100644
index 0000000..da0a307
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.cpp
@@ -0,0 +1,97 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("approximation");
+engine->setDescription("");
+
+InputVariable* inputX = new InputVariable;
+inputX->setName("inputX");
+inputX->setDescription("");
+inputX->setEnabled(true);
+inputX->setRange(0.000, 10.000);
+inputX->setLockValueInRange(false);
+inputX->addTerm(new Triangle("NEAR_1", 0.000, 1.000, 2.000));
+inputX->addTerm(new Triangle("NEAR_2", 1.000, 2.000, 3.000));
+inputX->addTerm(new Triangle("NEAR_3", 2.000, 3.000, 4.000));
+inputX->addTerm(new Triangle("NEAR_4", 3.000, 4.000, 5.000));
+inputX->addTerm(new Triangle("NEAR_5", 4.000, 5.000, 6.000));
+inputX->addTerm(new Triangle("NEAR_6", 5.000, 6.000, 7.000));
+inputX->addTerm(new Triangle("NEAR_7", 6.000, 7.000, 8.000));
+inputX->addTerm(new Triangle("NEAR_8", 7.000, 8.000, 9.000));
+inputX->addTerm(new Triangle("NEAR_9", 8.000, 9.000, 10.000));
+engine->addInputVariable(inputX);
+
+OutputVariable* outputFx = new OutputVariable;
+outputFx->setName("outputFx");
+outputFx->setDescription("");
+outputFx->setEnabled(true);
+outputFx->setRange(-1.000, 1.000);
+outputFx->setLockValueInRange(false);
+outputFx->setAggregation(fl::null);
+outputFx->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+outputFx->setDefaultValue(fl::nan);
+outputFx->setLockPreviousValue(true);
+outputFx->addTerm(new Constant("f1", 0.840));
+outputFx->addTerm(new Constant("f2", 0.450));
+outputFx->addTerm(new Constant("f3", 0.040));
+outputFx->addTerm(new Constant("f4", -0.180));
+outputFx->addTerm(new Constant("f5", -0.190));
+outputFx->addTerm(new Constant("f6", -0.040));
+outputFx->addTerm(new Constant("f7", 0.090));
+outputFx->addTerm(new Constant("f8", 0.120));
+outputFx->addTerm(new Constant("f9", 0.040));
+engine->addOutputVariable(outputFx);
+
+OutputVariable* trueFx = new OutputVariable;
+trueFx->setName("trueFx");
+trueFx->setDescription("");
+trueFx->setEnabled(true);
+trueFx->setRange(-1.000, 1.000);
+trueFx->setLockValueInRange(false);
+trueFx->setAggregation(fl::null);
+trueFx->setDefuzzifier(new WeightedAverage("Automatic"));
+trueFx->setDefaultValue(fl::nan);
+trueFx->setLockPreviousValue(true);
+trueFx->addTerm(Function::create("fx", "sin(inputX)/inputX", engine));
+engine->addOutputVariable(trueFx);
+
+OutputVariable* diffFx = new OutputVariable;
+diffFx->setName("diffFx");
+diffFx->setDescription("");
+diffFx->setEnabled(true);
+diffFx->setRange(-1.000, 1.000);
+diffFx->setLockValueInRange(false);
+diffFx->setAggregation(fl::null);
+diffFx->setDefuzzifier(new WeightedAverage("Automatic"));
+diffFx->setDefaultValue(fl::nan);
+diffFx->setLockPreviousValue(false);
+diffFx->addTerm(Function::create("diff", "fabs(outputFx-trueFx)", engine));
+engine->addOutputVariable(diffFx);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_1 then outputFx is f1", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_2 then outputFx is f2", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_3 then outputFx is f3", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_4 then outputFx is f4", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_5 then outputFx is f5", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_6 then outputFx is f6", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_7 then outputFx is f7", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_8 then outputFx is f8", engine));
+ruleBlock->addRule(Rule::parse("if inputX is NEAR_9 then outputFx is f9", engine));
+ruleBlock->addRule(Rule::parse("if inputX is any then trueFx is fx and diffFx is diff", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/takagi-sugeno/approximation.fcl b/examples/takagi-sugeno/approximation.fcl
new file mode 100644
index 0000000..6bf285d
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.fcl
@@ -0,0 +1,70 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK approximation
+
+VAR_INPUT
+ inputX: REAL;
+END_VAR
+
+VAR_OUTPUT
+ outputFx: REAL;
+ trueFx: REAL;
+ diffFx: REAL;
+END_VAR
+
+FUZZIFY inputX
+ RANGE := (0.000 .. 10.000);
+ TERM NEAR_1 := Triangle 0.000 1.000 2.000;
+ TERM NEAR_2 := Triangle 1.000 2.000 3.000;
+ TERM NEAR_3 := Triangle 2.000 3.000 4.000;
+ TERM NEAR_4 := Triangle 3.000 4.000 5.000;
+ TERM NEAR_5 := Triangle 4.000 5.000 6.000;
+ TERM NEAR_6 := Triangle 5.000 6.000 7.000;
+ TERM NEAR_7 := Triangle 6.000 7.000 8.000;
+ TERM NEAR_8 := Triangle 7.000 8.000 9.000;
+ TERM NEAR_9 := Triangle 8.000 9.000 10.000;
+END_FUZZIFY
+
+DEFUZZIFY outputFx
+ RANGE := (-1.000 .. 1.000);
+ TERM f1 := 0.840;
+ TERM f2 := 0.450;
+ TERM f3 := 0.040;
+ TERM f4 := -0.180;
+ TERM f5 := -0.190;
+ TERM f6 := -0.040;
+ TERM f7 := 0.090;
+ TERM f8 := 0.120;
+ TERM f9 := 0.040;
+ METHOD : COGS;
+ DEFAULT := nan | NC;
+END_DEFUZZIFY
+
+DEFUZZIFY trueFx
+ RANGE := (-1.000 .. 1.000);
+ TERM fx := Function sin(inputX)/inputX;
+ METHOD : COGS;
+ DEFAULT := nan | NC;
+END_DEFUZZIFY
+
+DEFUZZIFY diffFx
+ RANGE := (-1.000 .. 1.000);
+ TERM diff := Function fabs(outputFx-trueFx);
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ RULE 1 : if inputX is NEAR_1 then outputFx is f1
+ RULE 2 : if inputX is NEAR_2 then outputFx is f2
+ RULE 3 : if inputX is NEAR_3 then outputFx is f3
+ RULE 4 : if inputX is NEAR_4 then outputFx is f4
+ RULE 5 : if inputX is NEAR_5 then outputFx is f5
+ RULE 6 : if inputX is NEAR_6 then outputFx is f6
+ RULE 7 : if inputX is NEAR_7 then outputFx is f7
+ RULE 8 : if inputX is NEAR_8 then outputFx is f8
+ RULE 9 : if inputX is NEAR_9 then outputFx is f9
+ RULE 10 : if inputX is any then trueFx is fx and diffFx is diff
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/approximation.fis b/examples/takagi-sugeno/approximation.fis
new file mode 100644
index 0000000..2fcbc8d
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.fis
@@ -0,0 +1,66 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='approximation'
+Type='sugeno'
+Version=6.0
+NumInputs=1
+NumOutputs=3
+NumRules=10
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='inputX'
+Range=[0.000 10.000]
+NumMFs=9
+MF1='NEAR_1':'trimf',[0.000 1.000 2.000]
+MF2='NEAR_2':'trimf',[1.000 2.000 3.000]
+MF3='NEAR_3':'trimf',[2.000 3.000 4.000]
+MF4='NEAR_4':'trimf',[3.000 4.000 5.000]
+MF5='NEAR_5':'trimf',[4.000 5.000 6.000]
+MF6='NEAR_6':'trimf',[5.000 6.000 7.000]
+MF7='NEAR_7':'trimf',[6.000 7.000 8.000]
+MF8='NEAR_8':'trimf',[7.000 8.000 9.000]
+MF9='NEAR_9':'trimf',[8.000 9.000 10.000]
+
+[Output1]
+Name='outputFx'
+Range=[-1.000 1.000]
+NumMFs=9
+MF1='f1':'constant',[0.840]
+MF2='f2':'constant',[0.450]
+MF3='f3':'constant',[0.040]
+MF4='f4':'constant',[-0.180]
+MF5='f5':'constant',[-0.190]
+MF6='f6':'constant',[-0.040]
+MF7='f7':'constant',[0.090]
+MF8='f8':'constant',[0.120]
+MF9='f9':'constant',[0.040]
+
+[Output2]
+Name='trueFx'
+Range=[-1.000 1.000]
+NumMFs=1
+MF1='fx':'function',[sin(inputX)/inputX]
+
+[Output3]
+Name='diffFx'
+Range=[-1.000 1.000]
+NumMFs=1
+MF1='diff':'function',[fabs(outputFx-trueFx)]
+
+[Rules]
+1.000 , 1.000 0.000 0.000 (1.000) : 1
+2.000 , 2.000 0.000 0.000 (1.000) : 1
+3.000 , 3.000 0.000 0.000 (1.000) : 1
+4.000 , 4.000 0.000 0.000 (1.000) : 1
+5.000 , 5.000 0.000 0.000 (1.000) : 1
+6.000 , 6.000 0.000 0.000 (1.000) : 1
+7.000 , 7.000 0.000 0.000 (1.000) : 1
+8.000 , 8.000 0.000 0.000 (1.000) : 1
+9.000 , 9.000 0.000 0.000 (1.000) : 1
+0.990 , 0.000 1.000 1.000 (1.000) : 1
diff --git a/examples/takagi-sugeno/approximation.fld b/examples/takagi-sugeno/approximation.fld
new file mode 100644
index 0000000..1f3ba00
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.fld
@@ -0,0 +1,1025 @@
+inputX outputFx trueFx diffFx
+0.000000000 nan nan nan
+0.009775171 0.840000000 0.999984074 0.159984074
+0.019550342 0.840000000 0.999936299 0.159936299
+0.029325513 0.840000000 0.999856675 0.159856675
+0.039100684 0.840000000 0.999745209 0.159745209
+0.048875855 0.840000000 0.999601906 0.159601906
+0.058651026 0.840000000 0.999426775 0.159426775
+0.068426197 0.840000000 0.999219825 0.159219825
+0.078201369 0.840000000 0.998981069 0.158981069
+0.087976540 0.840000000 0.998710521 0.158710521
+0.097751711 0.840000000 0.998408195 0.158408195
+0.107526882 0.840000000 0.998074109 0.158074109
+0.117302053 0.840000000 0.997708282 0.157708282
+0.127077224 0.840000000 0.997310736 0.157310736
+0.136852395 0.840000000 0.996881492 0.156881492
+0.146627566 0.840000000 0.996420576 0.156420576
+0.156402737 0.840000000 0.995928014 0.155928014
+0.166177908 0.840000000 0.995403835 0.155403835
+0.175953079 0.840000000 0.994848067 0.154848067
+0.185728250 0.840000000 0.994260744 0.154260744
+0.195503421 0.840000000 0.993641898 0.153641898
+0.205278592 0.840000000 0.992991566 0.152991566
+0.215053763 0.840000000 0.992309784 0.152309784
+0.224828935 0.840000000 0.991596592 0.151596592
+0.234604106 0.840000000 0.990852030 0.150852030
+0.244379277 0.840000000 0.990076141 0.150076141
+0.254154448 0.840000000 0.989268970 0.149268970
+0.263929619 0.840000000 0.988430562 0.148430562
+0.273704790 0.840000000 0.987560966 0.147560966
+0.283479961 0.840000000 0.986660231 0.146660231
+0.293255132 0.840000000 0.985728410 0.145728410
+0.303030303 0.840000000 0.984765555 0.144765555
+0.312805474 0.840000000 0.983771721 0.143771721
+0.322580645 0.840000000 0.982746966 0.142746966
+0.332355816 0.840000000 0.981691347 0.141691347
+0.342130987 0.840000000 0.980604926 0.140604926
+0.351906158 0.840000000 0.979487765 0.139487765
+0.361681329 0.840000000 0.978339927 0.138339927
+0.371456500 0.840000000 0.977161478 0.137161478
+0.381231672 0.840000000 0.975952486 0.135952486
+0.391006843 0.840000000 0.974713019 0.134713019
+0.400782014 0.840000000 0.973443149 0.133443149
+0.410557185 0.840000000 0.972142948 0.132142948
+0.420332356 0.840000000 0.970812490 0.130812490
+0.430107527 0.840000000 0.969451851 0.129451851
+0.439882698 0.840000000 0.968061110 0.128061110
+0.449657869 0.840000000 0.966640345 0.126640345
+0.459433040 0.840000000 0.965189638 0.125189638
+0.469208211 0.840000000 0.963709072 0.123709072
+0.478983382 0.840000000 0.962198730 0.122198730
+0.488758553 0.840000000 0.960658700 0.120658700
+0.498533724 0.840000000 0.959089069 0.119089069
+0.508308895 0.840000000 0.957489927 0.117489927
+0.518084066 0.840000000 0.955861365 0.115861365
+0.527859238 0.840000000 0.954203476 0.114203476
+0.537634409 0.840000000 0.952516354 0.112516354
+0.547409580 0.840000000 0.950800096 0.110800096
+0.557184751 0.840000000 0.949054799 0.109054799
+0.566959922 0.840000000 0.947280564 0.107280564
+0.576735093 0.840000000 0.945477490 0.105477490
+0.586510264 0.840000000 0.943645681 0.103645681
+0.596285435 0.840000000 0.941785241 0.101785241
+0.606060606 0.840000000 0.939896276 0.099896276
+0.615835777 0.840000000 0.937978894 0.097978894
+0.625610948 0.840000000 0.936033204 0.096033204
+0.635386119 0.840000000 0.934059316 0.094059316
+0.645161290 0.840000000 0.932057343 0.092057343
+0.654936461 0.840000000 0.930027398 0.090027398
+0.664711632 0.840000000 0.927969597 0.087969597
+0.674486804 0.840000000 0.925884058 0.085884058
+0.684261975 0.840000000 0.923770897 0.083770897
+0.694037146 0.840000000 0.921630237 0.081630237
+0.703812317 0.840000000 0.919462198 0.079462198
+0.713587488 0.840000000 0.917266903 0.077266903
+0.723362659 0.840000000 0.915044476 0.075044476
+0.733137830 0.840000000 0.912795045 0.072795045
+0.742913001 0.840000000 0.910518737 0.070518737
+0.752688172 0.840000000 0.908215680 0.068215680
+0.762463343 0.840000000 0.905886006 0.065886006
+0.772238514 0.840000000 0.903529847 0.063529847
+0.782013685 0.840000000 0.901147335 0.061147335
+0.791788856 0.840000000 0.898738606 0.058738606
+0.801564027 0.840000000 0.896303797 0.056303797
+0.811339198 0.840000000 0.893843045 0.053843045
+0.821114370 0.840000000 0.891356490 0.051356490
+0.830889541 0.840000000 0.888844272 0.048844272
+0.840664712 0.840000000 0.886306533 0.046306533
+0.850439883 0.840000000 0.883743417 0.043743417
+0.860215054 0.840000000 0.881155068 0.041155068
+0.869990225 0.840000000 0.878541634 0.038541634
+0.879765396 0.840000000 0.875903261 0.035903261
+0.889540567 0.840000000 0.873240099 0.033240099
+0.899315738 0.840000000 0.870552298 0.030552298
+0.909090909 0.840000000 0.867840009 0.027840009
+0.918866080 0.840000000 0.865103386 0.025103386
+0.928641251 0.840000000 0.862342583 0.022342583
+0.938416422 0.840000000 0.859557755 0.019557755
+0.948191593 0.840000000 0.856749059 0.016749059
+0.957966764 0.840000000 0.853916654 0.013916654
+0.967741935 0.840000000 0.851060700 0.011060700
+0.977517107 0.840000000 0.848181355 0.008181355
+0.987292278 0.840000000 0.845278784 0.005278784
+0.997067449 0.840000000 0.842353148 0.002353148
+1.006842620 0.837331378 0.839404613 0.002073235
+1.016617791 0.833519062 0.836433344 0.002914283
+1.026392962 0.829706745 0.833439508 0.003732763
+1.036168133 0.825894428 0.830423273 0.004528844
+1.045943304 0.822082111 0.827384807 0.005302696
+1.055718475 0.818269795 0.824324283 0.006054488
+1.065493646 0.814457478 0.821241871 0.006784393
+1.075268817 0.810645161 0.818137743 0.007492582
+1.085043988 0.806832845 0.815012075 0.008179230
+1.094819159 0.803020528 0.811865040 0.008844512
+1.104594330 0.799208211 0.808696816 0.009488604
+1.114369501 0.795395894 0.805507578 0.010111684
+1.124144673 0.791583578 0.802297506 0.010713928
+1.133919844 0.787771261 0.799066779 0.011295518
+1.143695015 0.783958944 0.795815577 0.011856632
+1.153470186 0.780146628 0.792544081 0.012397454
+1.163245357 0.776334311 0.789252476 0.012918165
+1.173020528 0.772521994 0.785940943 0.013418949
+1.182795699 0.768709677 0.782609668 0.013899990
+1.192570870 0.764897361 0.779258836 0.014361475
+1.202346041 0.761085044 0.775888633 0.014803589
+1.212121212 0.757272727 0.772499248 0.015226521
+1.221896383 0.753460411 0.769090869 0.015630459
+1.231671554 0.749648094 0.765663685 0.016015592
+1.241446725 0.745835777 0.762217888 0.016382110
+1.251221896 0.742023460 0.758753667 0.016730207
+1.260997067 0.738211144 0.755271216 0.017060072
+1.270772239 0.734398827 0.751770728 0.017371901
+1.280547410 0.730586510 0.748252396 0.017665886
+1.290322581 0.726774194 0.744716416 0.017942223
+1.300097752 0.722961877 0.741162984 0.018201107
+1.309872923 0.719149560 0.737592296 0.018442736
+1.319648094 0.715337243 0.734004550 0.018667307
+1.329423265 0.711524927 0.730399945 0.018875018
+1.339198436 0.707712610 0.726778678 0.019066068
+1.348973607 0.703900293 0.723140951 0.019240658
+1.358748778 0.700087977 0.719486964 0.019398987
+1.368523949 0.696275660 0.715816918 0.019541259
+1.378299120 0.692463343 0.712131017 0.019667674
+1.388074291 0.688651026 0.708429462 0.019778436
+1.397849462 0.684838710 0.704712458 0.019873748
+1.407624633 0.681026393 0.700980209 0.019953816
+1.417399804 0.677214076 0.697232921 0.020018845
+1.427174976 0.673401760 0.693470798 0.020069039
+1.436950147 0.669589443 0.689694049 0.020104606
+1.446725318 0.665777126 0.685902879 0.020125753
+1.456500489 0.661964809 0.682097497 0.020132688
+1.466275660 0.658152493 0.678278112 0.020125619
+1.476050831 0.654340176 0.674444932 0.020104756
+1.485826002 0.650527859 0.670598167 0.020070308
+1.495601173 0.646715543 0.666738028 0.020022485
+1.505376344 0.642903226 0.662864725 0.019961499
+1.515151515 0.639090909 0.658978470 0.019887561
+1.524926686 0.635278592 0.655079475 0.019800882
+1.534701857 0.631466276 0.651167952 0.019701676
+1.544477028 0.627653959 0.647244115 0.019590156
+1.554252199 0.623841642 0.643308177 0.019466535
+1.564027370 0.620029326 0.639360352 0.019331027
+1.573802542 0.616217009 0.635400856 0.019183847
+1.583577713 0.612404692 0.631429902 0.019025209
+1.593352884 0.608592375 0.627447706 0.018855331
+1.603128055 0.604780059 0.623454485 0.018674426
+1.612903226 0.600967742 0.619450454 0.018482712
+1.622678397 0.597155425 0.615435831 0.018280406
+1.632453568 0.593343109 0.611410832 0.018067724
+1.642228739 0.589530792 0.607375676 0.017844884
+1.652003910 0.585718475 0.603330579 0.017612104
+1.661779081 0.581906158 0.599275761 0.017369603
+1.671554252 0.578093842 0.595211440 0.017117598
+1.681329423 0.574281525 0.591137834 0.016856310
+1.691104594 0.570469208 0.587055164 0.016585956
+1.700879765 0.566656891 0.582963649 0.016306757
+1.710654936 0.562844575 0.578863507 0.016018933
+1.720430108 0.559032258 0.574754961 0.015722703
+1.730205279 0.555219941 0.570638229 0.015418287
+1.739980450 0.551407625 0.566513532 0.015105908
+1.749755621 0.547595308 0.562381092 0.014785784
+1.759530792 0.543782991 0.558241129 0.014458138
+1.769305963 0.539970674 0.554093865 0.014123190
+1.779081134 0.536158358 0.549939520 0.013781162
+1.788856305 0.532346041 0.545778317 0.013432276
+1.798631476 0.528533724 0.541610476 0.013076752
+1.808406647 0.524721408 0.537436221 0.012714813
+1.818181818 0.520909091 0.533255772 0.012346681
+1.827956989 0.517096774 0.529069352 0.011972578
+1.837732160 0.513284457 0.524877183 0.011592726
+1.847507331 0.509472141 0.520679488 0.011207347
+1.857282502 0.505659824 0.516476488 0.010816664
+1.867057674 0.501847507 0.512268406 0.010420898
+1.876832845 0.498035191 0.508055464 0.010020273
+1.886608016 0.494222874 0.503837884 0.009615010
+1.896383187 0.490410557 0.499615890 0.009205333
+1.906158358 0.486598240 0.495389703 0.008791463
+1.915933529 0.482785924 0.491159546 0.008373622
+1.925708700 0.478973607 0.486925641 0.007952034
+1.935483871 0.475161290 0.482688211 0.007526920
+1.945259042 0.471348974 0.478447477 0.007098503
+1.955034213 0.467536657 0.474203662 0.006667005
+1.964809384 0.463724340 0.469956987 0.006232647
+1.974584555 0.459912023 0.465707675 0.005795652
+1.984359726 0.456099707 0.461455948 0.005356241
+1.994134897 0.452287390 0.457202027 0.004914637
+2.003910068 0.448396872 0.452946134 0.004549262
+2.013685239 0.444389052 0.448688489 0.004299437
+2.023460411 0.440381232 0.444429315 0.004048083
+2.033235582 0.436373412 0.440168832 0.003795420
+2.043010753 0.432365591 0.435907260 0.003541669
+2.052785924 0.428357771 0.431644821 0.003287050
+2.062561095 0.424349951 0.427381735 0.003031784
+2.072336266 0.420342131 0.423118222 0.002776091
+2.082111437 0.416334311 0.418854501 0.002520190
+2.091886608 0.412326491 0.414590792 0.002264301
+2.101661779 0.408318671 0.410327314 0.002008643
+2.111436950 0.404310850 0.406064286 0.001753436
+2.121212121 0.400303030 0.401801927 0.001498897
+2.130987292 0.396295210 0.397540455 0.001245245
+2.140762463 0.392287390 0.393280087 0.000992697
+2.150537634 0.388279570 0.389021042 0.000741472
+2.160312805 0.384271750 0.384763536 0.000491786
+2.170087977 0.380263930 0.380507786 0.000243857
+2.179863148 0.376256109 0.376254009 0.000002100
+2.189638319 0.372248289 0.372002420 0.000245869
+2.199413490 0.368240469 0.367753235 0.000487234
+2.209188661 0.364232649 0.363506669 0.000725980
+2.218963832 0.360224829 0.359262937 0.000961892
+2.228739003 0.356217009 0.355022251 0.001194757
+2.238514174 0.352209189 0.350784828 0.001424361
+2.248289345 0.348201369 0.346550878 0.001650491
+2.258064516 0.344193548 0.342320615 0.001872933
+2.267839687 0.340185728 0.338094251 0.002091477
+2.277614858 0.336177908 0.333871998 0.002305910
+2.287390029 0.332170088 0.329654066 0.002516022
+2.297165200 0.328162268 0.325440666 0.002721602
+2.306940371 0.324154448 0.321232007 0.002922440
+2.316715543 0.320146628 0.317028300 0.003118328
+2.326490714 0.316138807 0.312829752 0.003309056
+2.336265885 0.312130987 0.308636571 0.003494416
+2.346041056 0.308123167 0.304448965 0.003674202
+2.355816227 0.304115347 0.300267141 0.003848206
+2.365591398 0.300107527 0.296091304 0.004016222
+2.375366569 0.296099707 0.291921661 0.004178046
+2.385141740 0.292091887 0.287758415 0.004333472
+2.394916911 0.288084066 0.283601770 0.004482296
+2.404692082 0.284076246 0.279451931 0.004624315
+2.414467253 0.280068426 0.275309099 0.004759327
+2.424242424 0.276060606 0.271173477 0.004887129
+2.434017595 0.272052786 0.267045265 0.005007521
+2.443792766 0.268044966 0.262924663 0.005120302
+2.453567937 0.264037146 0.258811872 0.005225273
+2.463343109 0.260029326 0.254707090 0.005322235
+2.473118280 0.256021505 0.250610515 0.005410990
+2.482893451 0.252013685 0.246522344 0.005491341
+2.492668622 0.248005865 0.242442774 0.005563091
+2.502443793 0.243998045 0.238371999 0.005626046
+2.512218964 0.239990225 0.234310215 0.005680009
+2.521994135 0.235982405 0.230257616 0.005724789
+2.531769306 0.231974585 0.226214394 0.005760191
+2.541544477 0.227966764 0.222180741 0.005786024
+2.551319648 0.223958944 0.218156848 0.005802096
+2.561094819 0.219951124 0.214142907 0.005808217
+2.570869990 0.215943304 0.210139105 0.005804199
+2.580645161 0.211935484 0.206145632 0.005789852
+2.590420332 0.207927664 0.202162674 0.005764989
+2.600195503 0.203919844 0.198190419 0.005729424
+2.609970674 0.199912023 0.194229052 0.005682971
+2.619745846 0.195904203 0.190278758 0.005625446
+2.629521017 0.191896383 0.186339719 0.005556664
+2.639296188 0.187888563 0.182412119 0.005476444
+2.649071359 0.183880743 0.178496140 0.005384603
+2.658846530 0.179872923 0.174591961 0.005280962
+2.668621701 0.175865103 0.170699762 0.005165340
+2.678396872 0.171857283 0.166819723 0.005037560
+2.688172043 0.167849462 0.162952019 0.004897443
+2.697947214 0.163841642 0.159096828 0.004744814
+2.707722385 0.159833822 0.155254326 0.004579496
+2.717497556 0.155826002 0.151424685 0.004401317
+2.727272727 0.151818182 0.147608080 0.004210102
+2.737047898 0.147810362 0.143804682 0.004005680
+2.746823069 0.143802542 0.140014663 0.003787879
+2.756598240 0.139794721 0.136238191 0.003556530
+2.766373412 0.135786901 0.132475437 0.003311464
+2.776148583 0.131779081 0.128726567 0.003052514
+2.785923754 0.127771261 0.124991748 0.002779513
+2.795698925 0.123763441 0.121271145 0.002492296
+2.805474096 0.119755621 0.117564921 0.002190699
+2.815249267 0.115747801 0.113873241 0.001874559
+2.825024438 0.111739980 0.110196266 0.001543715
+2.834799609 0.107732160 0.106534155 0.001198005
+2.844574780 0.103724340 0.102887069 0.000837271
+2.854349951 0.099716520 0.099255166 0.000461354
+2.864125122 0.095708700 0.095638602 0.000070098
+2.873900293 0.091700880 0.092037533 0.000336653
+2.883675464 0.087693060 0.088452113 0.000759053
+2.893450635 0.083685239 0.084882496 0.001197256
+2.903225806 0.079677419 0.081328833 0.001651414
+2.913000978 0.075669599 0.077791275 0.002121676
+2.922776149 0.071661779 0.074269971 0.002608192
+2.932551320 0.067653959 0.070765070 0.003111111
+2.942326491 0.063646139 0.067276718 0.003630579
+2.952101662 0.059638319 0.063805060 0.004166741
+2.961876833 0.055630499 0.060350240 0.004719742
+2.971652004 0.051622678 0.056912402 0.005289724
+2.981427175 0.047614858 0.053491687 0.005876829
+2.991202346 0.043607038 0.050088235 0.006481197
+3.000977517 0.039784946 0.046702185 0.006917238
+3.010752688 0.037634409 0.043333674 0.005699265
+3.020527859 0.035483871 0.039982838 0.004498967
+3.030303030 0.033333333 0.036649813 0.003316479
+3.040078201 0.031182796 0.033334731 0.002151935
+3.049853372 0.029032258 0.030037724 0.001005466
+3.059628543 0.026881720 0.026758924 0.000122797
+3.069403715 0.024731183 0.023498459 0.001232724
+3.079178886 0.022580645 0.020256457 0.002324188
+3.088954057 0.020430108 0.017033044 0.003397063
+3.098729228 0.018279570 0.013828347 0.004451223
+3.108504399 0.016129032 0.010642487 0.005486545
+3.118279570 0.013978495 0.007475588 0.006502907
+3.128054741 0.011827957 0.004327769 0.007500188
+3.137829912 0.009677419 0.001199151 0.008478268
+3.147605083 0.007526882 -0.001910149 0.009437030
+3.157380254 0.005376344 -0.005000014 0.010376358
+3.167155425 0.003225806 -0.008070329 0.011296136
+3.176930596 0.001075269 -0.011120982 0.012196251
+3.186705767 -0.001075269 -0.014151860 0.013076591
+3.196480938 -0.003225806 -0.017162852 0.013937045
+3.206256109 -0.005376344 -0.020153849 0.014777505
+3.216031281 -0.007526882 -0.023124744 0.015597862
+3.225806452 -0.009677419 -0.026075431 0.016398012
+3.235581623 -0.011827957 -0.029005805 0.017177848
+3.245356794 -0.013978495 -0.031915762 0.017937268
+3.255131965 -0.016129032 -0.034805202 0.018676170
+3.264907136 -0.018279570 -0.037674024 0.019394454
+3.274682307 -0.020430108 -0.040522130 0.020092022
+3.284457478 -0.022580645 -0.043349422 0.020768777
+3.294232649 -0.024731183 -0.046155805 0.021424622
+3.304007820 -0.026881720 -0.048941185 0.022059465
+3.313782991 -0.029032258 -0.051705469 0.022673211
+3.323558162 -0.031182796 -0.054448567 0.023265771
+3.333333333 -0.033333333 -0.057170389 0.023837056
+3.343108504 -0.035483871 -0.059870847 0.024386976
+3.352883675 -0.037634409 -0.062549854 0.024915446
+3.362658847 -0.039784946 -0.065207327 0.025422380
+3.372434018 -0.041935484 -0.067843181 0.025907697
+3.382209189 -0.044086022 -0.070457335 0.026371313
+3.391984360 -0.046236559 -0.073049709 0.026813150
+3.401759531 -0.048387097 -0.075620224 0.027233127
+3.411534702 -0.050537634 -0.078168803 0.027631169
+3.421309873 -0.052688172 -0.080695371 0.028007199
+3.431085044 -0.054838710 -0.083199854 0.028361144
+3.440860215 -0.056989247 -0.085682179 0.028692932
+3.450635386 -0.059139785 -0.088142277 0.029002492
+3.460410557 -0.061290323 -0.090580077 0.029289754
+3.470185728 -0.063440860 -0.092995512 0.029554651
+3.479960899 -0.065591398 -0.095388516 0.029797118
+3.489736070 -0.067741935 -0.097759024 0.030017089
+3.499511241 -0.069892473 -0.100106975 0.030214502
+3.509286413 -0.072043011 -0.102432306 0.030389296
+3.519061584 -0.074193548 -0.104734958 0.030541410
+3.528836755 -0.076344086 -0.107014873 0.030670787
+3.538611926 -0.078494624 -0.109271995 0.030777371
+3.548387097 -0.080645161 -0.111506268 0.030861107
+3.558162268 -0.082795699 -0.113717639 0.030921940
+3.567937439 -0.084946237 -0.115906057 0.030959820
+3.577712610 -0.087096774 -0.118071471 0.030974697
+3.587487781 -0.089247312 -0.120213834 0.030966522
+3.597262952 -0.091397849 -0.122333097 0.030935248
+3.607038123 -0.093548387 -0.124429216 0.030880829
+3.616813294 -0.095698925 -0.126502148 0.030803223
+3.626588465 -0.097849462 -0.128551849 0.030702387
+3.636363636 -0.100000000 -0.130578280 0.030578280
+3.646138807 -0.102150538 -0.132581402 0.030430865
+3.655913978 -0.104301075 -0.134561177 0.030260102
+3.665689150 -0.106451613 -0.136517570 0.030065957
+3.675464321 -0.108602151 -0.138450547 0.029848396
+3.685239492 -0.110752688 -0.140360075 0.029607387
+3.695014663 -0.112903226 -0.142246123 0.029342897
+3.704789834 -0.115053763 -0.144108662 0.029054898
+3.714565005 -0.117204301 -0.145947664 0.028743363
+3.724340176 -0.119354839 -0.147763104 0.028408265
+3.734115347 -0.121505376 -0.149554957 0.028049580
+3.743890518 -0.123655914 -0.151323199 0.027667285
+3.753665689 -0.125806452 -0.153067810 0.027261359
+3.763440860 -0.127956989 -0.154788770 0.026831781
+3.773216031 -0.130107527 -0.156486061 0.026378534
+3.782991202 -0.132258065 -0.158159667 0.025901602
+3.792766373 -0.134408602 -0.159809571 0.025400969
+3.802541544 -0.136559140 -0.161435762 0.024876622
+3.812316716 -0.138709677 -0.163038227 0.024328550
+3.822091887 -0.140860215 -0.164616957 0.023756742
+3.831867058 -0.143010753 -0.166171942 0.023161190
+3.841642229 -0.145161290 -0.167703176 0.022541886
+3.851417400 -0.147311828 -0.169210654 0.021898826
+3.861192571 -0.149462366 -0.170694370 0.021232005
+3.870967742 -0.151612903 -0.172154324 0.020541421
+3.880742913 -0.153763441 -0.173590515 0.019827074
+3.890518084 -0.155913978 -0.175002943 0.019088965
+3.900293255 -0.158064516 -0.176391612 0.018327095
+3.910068426 -0.160215054 -0.177756524 0.017541470
+3.919843597 -0.162365591 -0.179097686 0.016732094
+3.929618768 -0.164516129 -0.180415104 0.015898975
+3.939393939 -0.166666667 -0.181708788 0.015042122
+3.949169110 -0.168817204 -0.182978748 0.014161544
+3.958944282 -0.170967742 -0.184224995 0.013257253
+3.968719453 -0.173118280 -0.185447544 0.012329264
+3.978494624 -0.175268817 -0.186646408 0.011377591
+3.988269795 -0.177419355 -0.187821604 0.010402249
+3.998044966 -0.179569892 -0.188973151 0.009403258
+4.007820137 -0.180078201 -0.190101067 0.010022866
+4.017595308 -0.180175953 -0.191205374 0.011029421
+4.027370479 -0.180273705 -0.192286095 0.012012390
+4.037145650 -0.180371457 -0.193343253 0.012971796
+4.046920821 -0.180469208 -0.194376874 0.013907665
+4.056695992 -0.180566960 -0.195386985 0.014820025
+4.066471163 -0.180664712 -0.196373614 0.015708903
+4.076246334 -0.180762463 -0.197336793 0.016574330
+4.086021505 -0.180860215 -0.198276552 0.017416337
+4.095796676 -0.180957967 -0.199192925 0.018234958
+4.105571848 -0.181055718 -0.200085945 0.019030227
+4.115347019 -0.181153470 -0.200955650 0.019802180
+4.125122190 -0.181251222 -0.201802077 0.020550855
+4.134897361 -0.181348974 -0.202625264 0.021276290
+4.144672532 -0.181446725 -0.203425253 0.021978527
+4.154447703 -0.181544477 -0.204202084 0.022657607
+4.164222874 -0.181642229 -0.204955802 0.023313574
+4.173998045 -0.181739980 -0.205686452 0.023946472
+4.183773216 -0.181837732 -0.206394079 0.024556347
+4.193548387 -0.181935484 -0.207078732 0.025143248
+4.203323558 -0.182033236 -0.207740459 0.025707224
+4.213098729 -0.182130987 -0.208379312 0.026248324
+4.222873900 -0.182228739 -0.208995341 0.026766602
+4.232649071 -0.182326491 -0.209588601 0.027262110
+4.242424242 -0.182424242 -0.210159146 0.027734904
+4.252199413 -0.182521994 -0.210707033 0.028185039
+4.261974585 -0.182619746 -0.211232319 0.028612574
+4.271749756 -0.182717498 -0.211735064 0.029017566
+4.281524927 -0.182815249 -0.212215327 0.029400078
+4.291300098 -0.182913001 -0.212673170 0.029760169
+4.301075269 -0.183010753 -0.213108657 0.030097904
+4.310850440 -0.183108504 -0.213521852 0.030413347
+4.320625611 -0.183206256 -0.213912820 0.030706564
+4.330400782 -0.183304008 -0.214281630 0.030977622
+4.340175953 -0.183401760 -0.214628349 0.031226589
+4.349951124 -0.183499511 -0.214953047 0.031453536
+4.359726295 -0.183597263 -0.215255796 0.031658533
+4.369501466 -0.183695015 -0.215536668 0.031841654
+4.379276637 -0.183792766 -0.215795737 0.032002971
+4.389051808 -0.183890518 -0.216033078 0.032142560
+4.398826979 -0.183988270 -0.216248767 0.032260497
+4.408602151 -0.184086022 -0.216442883 0.032356861
+4.418377322 -0.184183773 -0.216615503 0.032431730
+4.428152493 -0.184281525 -0.216766708 0.032485183
+4.437927664 -0.184379277 -0.216896581 0.032517304
+4.447702835 -0.184477028 -0.217005203 0.032528174
+4.457478006 -0.184574780 -0.217092658 0.032517878
+4.467253177 -0.184672532 -0.217159032 0.032486500
+4.477028348 -0.184770283 -0.217204411 0.032434128
+4.486803519 -0.184868035 -0.217228884 0.032360849
+4.496578690 -0.184965787 -0.217232538 0.032266751
+4.506353861 -0.185063539 -0.217215464 0.032151925
+4.516129032 -0.185161290 -0.217177753 0.032016463
+4.525904203 -0.185259042 -0.217119498 0.031860456
+4.535679374 -0.185356794 -0.217040792 0.031683998
+4.545454545 -0.185454545 -0.216941730 0.031487185
+4.555229717 -0.185552297 -0.216822409 0.031270112
+4.565004888 -0.185650049 -0.216682925 0.031032876
+4.574780059 -0.185747801 -0.216523376 0.030775576
+4.584555230 -0.185845552 -0.216343863 0.030498310
+4.594330401 -0.185943304 -0.216144485 0.030201181
+4.604105572 -0.186041056 -0.215925344 0.029884288
+4.613880743 -0.186138807 -0.215686543 0.029547735
+4.623655914 -0.186236559 -0.215428185 0.029191626
+4.633431085 -0.186334311 -0.215150377 0.028816066
+4.643206256 -0.186432063 -0.214853223 0.028421161
+4.652981427 -0.186529814 -0.214536831 0.028007017
+4.662756598 -0.186627566 -0.214201309 0.027573743
+4.672531769 -0.186725318 -0.213846766 0.027121448
+4.682306940 -0.186823069 -0.213473312 0.026650242
+4.692082111 -0.186920821 -0.213081058 0.026160237
+4.701857283 -0.187018573 -0.212670118 0.025651545
+4.711632454 -0.187116325 -0.212240603 0.025124279
+4.721407625 -0.187214076 -0.211792629 0.024578553
+4.731182796 -0.187311828 -0.211326310 0.024014482
+4.740957967 -0.187409580 -0.210841763 0.023432183
+4.750733138 -0.187507331 -0.210339104 0.022831773
+4.760508309 -0.187605083 -0.209818453 0.022213370
+4.770283480 -0.187702835 -0.209279928 0.021577093
+4.780058651 -0.187800587 -0.208723648 0.020923062
+4.789833822 -0.187898338 -0.208149736 0.020251398
+4.799608993 -0.187996090 -0.207558313 0.019562223
+4.809384164 -0.188093842 -0.206949501 0.018855660
+4.819159335 -0.188191593 -0.206323425 0.018131831
+4.828934506 -0.188289345 -0.205680208 0.017390863
+4.838709677 -0.188387097 -0.205019977 0.016632880
+4.848484848 -0.188484848 -0.204342856 0.015858008
+4.858260020 -0.188582600 -0.203648975 0.015066375
+4.868035191 -0.188680352 -0.202938460 0.014258108
+4.877810362 -0.188778104 -0.202211440 0.013433336
+4.887585533 -0.188875855 -0.201468044 0.012592189
+4.897360704 -0.188973607 -0.200708404 0.011734797
+4.907135875 -0.189071359 -0.199932650 0.010861292
+4.916911046 -0.189169110 -0.199140915 0.009971804
+4.926686217 -0.189266862 -0.198333330 0.009066468
+4.936461388 -0.189364614 -0.197510031 0.008145417
+4.946236559 -0.189462366 -0.196671149 0.007208784
+4.956011730 -0.189560117 -0.195816822 0.006256704
+4.965786901 -0.189657869 -0.194947184 0.005289315
+4.975562072 -0.189755621 -0.194062371 0.004306751
+4.985337243 -0.189853372 -0.193162522 0.003309149
+4.995112414 -0.189951124 -0.192247773 0.002296649
+5.004887586 -0.189266862 -0.191318264 0.002051402
+5.014662757 -0.187800587 -0.190374133 0.002573546
+5.024437928 -0.186334311 -0.189415520 0.003081209
+5.034213099 -0.184868035 -0.188442566 0.003574530
+5.043988270 -0.183401760 -0.187455411 0.004053652
+5.053763441 -0.181935484 -0.186454198 0.004518714
+5.063538612 -0.180469208 -0.185439069 0.004969861
+5.073313783 -0.179002933 -0.184410166 0.005407234
+5.083088954 -0.177536657 -0.183367634 0.005830977
+5.092864125 -0.176070381 -0.182311616 0.006241235
+5.102639296 -0.174604106 -0.181242257 0.006638152
+5.112414467 -0.173137830 -0.180159702 0.007021872
+5.122189638 -0.171671554 -0.179064097 0.007392543
+5.131964809 -0.170205279 -0.177955589 0.007750310
+5.141739980 -0.168739003 -0.176834323 0.008095320
+5.151515152 -0.167272727 -0.175700447 0.008427720
+5.161290323 -0.165806452 -0.174554110 0.008747658
+5.171065494 -0.164340176 -0.173395458 0.009055283
+5.180840665 -0.162873900 -0.172224642 0.009350742
+5.190615836 -0.161407625 -0.171041810 0.009634186
+5.200391007 -0.159941349 -0.169847112 0.009905763
+5.210166178 -0.158475073 -0.168640698 0.010165625
+5.219941349 -0.157008798 -0.167422718 0.010413921
+5.229716520 -0.155542522 -0.166193324 0.010650802
+5.239491691 -0.154076246 -0.164952666 0.010876420
+5.249266862 -0.152609971 -0.163700897 0.011090926
+5.259042033 -0.151143695 -0.162438167 0.011294472
+5.268817204 -0.149677419 -0.161164631 0.011487212
+5.278592375 -0.148211144 -0.159880440 0.011669296
+5.288367546 -0.146744868 -0.158585748 0.011840880
+5.298142717 -0.145278592 -0.157280708 0.012002115
+5.307917889 -0.143812317 -0.155965473 0.012153157
+5.317693060 -0.142346041 -0.154640199 0.012294158
+5.327468231 -0.140879765 -0.153305038 0.012425273
+5.337243402 -0.139413490 -0.151960146 0.012546657
+5.347018573 -0.137947214 -0.150605678 0.012658464
+5.356793744 -0.136480938 -0.149241789 0.012760850
+5.366568915 -0.135014663 -0.147868633 0.012853971
+5.376344086 -0.133548387 -0.146486368 0.012937981
+5.386119257 -0.132082111 -0.145095148 0.013013036
+5.395894428 -0.130615836 -0.143695129 0.013079293
+5.405669599 -0.129149560 -0.142286468 0.013136908
+5.415444770 -0.127683284 -0.140869321 0.013186036
+5.425219941 -0.126217009 -0.139443844 0.013226835
+5.434995112 -0.124750733 -0.138010195 0.013259462
+5.444770283 -0.123284457 -0.136568530 0.013284072
+5.454545455 -0.121818182 -0.135119006 0.013300824
+5.464320626 -0.120351906 -0.133661780 0.013309874
+5.474095797 -0.118885630 -0.132197009 0.013311379
+5.483870968 -0.117419355 -0.130724852 0.013305497
+5.493646139 -0.115953079 -0.129245464 0.013292385
+5.503421310 -0.114486804 -0.127759003 0.013272200
+5.513196481 -0.113020528 -0.126265628 0.013245100
+5.522971652 -0.111554252 -0.124765495 0.013211243
+5.532746823 -0.110087977 -0.123258763 0.013170786
+5.542521994 -0.108621701 -0.121745588 0.013123887
+5.552297165 -0.107155425 -0.120226129 0.013070703
+5.562072336 -0.105689150 -0.118700542 0.013011393
+5.571847507 -0.104222874 -0.117168986 0.012946112
+5.581622678 -0.102756598 -0.115631619 0.012875020
+5.591397849 -0.101290323 -0.114088597 0.012798274
+5.601173021 -0.099824047 -0.112540078 0.012716031
+5.610948192 -0.098357771 -0.110986220 0.012628449
+5.620723363 -0.096891496 -0.109427180 0.012535685
+5.630498534 -0.095425220 -0.107863116 0.012437896
+5.640273705 -0.093958944 -0.106294184 0.012335240
+5.650048876 -0.092492669 -0.104720542 0.012227873
+5.659824047 -0.091026393 -0.103142346 0.012115953
+5.669599218 -0.089560117 -0.101559754 0.011999637
+5.679374389 -0.088093842 -0.099972922 0.011879080
+5.689149560 -0.086627566 -0.098382007 0.011754441
+5.698924731 -0.085161290 -0.096787164 0.011625874
+5.708699902 -0.083695015 -0.095188551 0.011493537
+5.718475073 -0.082228739 -0.093586324 0.011357585
+5.728250244 -0.080762463 -0.091980637 0.011218174
+5.738025415 -0.079296188 -0.090371648 0.011075460
+5.747800587 -0.077829912 -0.088759510 0.010929598
+5.757575758 -0.076363636 -0.087144380 0.010780744
+5.767350929 -0.074897361 -0.085526412 0.010629051
+5.777126100 -0.073431085 -0.083905761 0.010474676
+5.786901271 -0.071964809 -0.082282581 0.010317771
+5.796676442 -0.070498534 -0.080657026 0.010158492
+5.806451613 -0.069032258 -0.079029251 0.009996993
+5.816226784 -0.067565982 -0.077399408 0.009833426
+5.826001955 -0.066099707 -0.075767651 0.009667945
+5.835777126 -0.064633431 -0.074134133 0.009500702
+5.845552297 -0.063167155 -0.072499007 0.009331851
+5.855327468 -0.061700880 -0.070862424 0.009161544
+5.865102639 -0.060234604 -0.069224536 0.008989932
+5.874877810 -0.058768328 -0.067585496 0.008817167
+5.884652981 -0.057302053 -0.065945453 0.008643400
+5.894428152 -0.055835777 -0.064304559 0.008468782
+5.904203324 -0.054369501 -0.062662964 0.008293463
+5.913978495 -0.052903226 -0.061020818 0.008117593
+5.923753666 -0.051436950 -0.059378271 0.007941321
+5.933528837 -0.049970674 -0.057735471 0.007764797
+5.943304008 -0.048504399 -0.056092568 0.007588169
+5.953079179 -0.047038123 -0.054449709 0.007411586
+5.962854350 -0.045571848 -0.052807042 0.007235194
+5.972629521 -0.044105572 -0.051164714 0.007059142
+5.982404692 -0.042639296 -0.049522873 0.006883577
+5.992179863 -0.041173021 -0.047881664 0.006708643
+6.001955034 -0.039745846 -0.046241233 0.006495387
+6.011730205 -0.038475073 -0.044601725 0.006126652
+6.021505376 -0.037204301 -0.042963286 0.005758985
+6.031280547 -0.035933529 -0.041326059 0.005392530
+6.041055718 -0.034662757 -0.039690188 0.005027431
+6.050830890 -0.033391984 -0.038055816 0.004663832
+6.060606061 -0.032121212 -0.036423086 0.004301874
+6.070381232 -0.030850440 -0.034792139 0.003941699
+6.080156403 -0.029579668 -0.033163118 0.003583450
+6.089931574 -0.028308895 -0.031536162 0.003227267
+6.099706745 -0.027038123 -0.029911413 0.002873289
+6.109481916 -0.025767351 -0.028289009 0.002521658
+6.119257087 -0.024496579 -0.026669089 0.002172511
+6.129032258 -0.023225806 -0.025051793 0.001825986
+6.138807429 -0.021955034 -0.023437257 0.001482223
+6.148582600 -0.020684262 -0.021825619 0.001141357
+6.158357771 -0.019413490 -0.020217015 0.000803526
+6.168132942 -0.018142717 -0.018611581 0.000468864
+6.177908113 -0.016871945 -0.017009452 0.000137507
+6.187683284 -0.015601173 -0.015410762 0.000190411
+6.197458456 -0.014330401 -0.013815645 0.000514755
+6.207233627 -0.013059629 -0.012224234 0.000835394
+6.217008798 -0.011788856 -0.010636662 0.001152195
+6.226783969 -0.010518084 -0.009053059 0.001465025
+6.236559140 -0.009247312 -0.007473556 0.001773756
+6.246334311 -0.007976540 -0.005898284 0.002078255
+6.256109482 -0.006705767 -0.004327373 0.002378395
+6.265884653 -0.005434995 -0.002760950 0.002674046
+6.275659824 -0.004164223 -0.001199143 0.002965080
+6.285434995 -0.002893451 0.000357920 0.003251371
+6.295210166 -0.001622678 0.001910114 0.003532792
+6.304985337 -0.000351906 0.003457312 0.003809218
+6.314760508 0.000918866 0.004999391 0.004080525
+6.324535679 0.002189638 0.006536225 0.004346587
+6.334310850 0.003460411 0.008067693 0.004607282
+6.344086022 0.004731183 0.009593671 0.004862488
+6.353861193 0.006001955 0.011114039 0.005112084
+6.363636364 0.007272727 0.012628676 0.005355948
+6.373411535 0.008543500 0.014137461 0.005593962
+6.383186706 0.009814272 0.015640277 0.005826005
+6.392961877 0.011085044 0.017137005 0.006051961
+6.402737048 0.012355816 0.018627527 0.006271711
+6.412512219 0.013626588 0.020111728 0.006485140
+6.422287390 0.014897361 0.021589493 0.006692132
+6.432062561 0.016168133 0.023060705 0.006892572
+6.441837732 0.017438905 0.024525253 0.007086348
+6.451612903 0.018709677 0.025983022 0.007273345
+6.461388074 0.019980450 0.027433902 0.007453453
+6.471163245 0.021251222 0.028877781 0.007626559
+6.480938416 0.022521994 0.030314550 0.007792555
+6.490713587 0.023792766 0.031744098 0.007951331
+6.500488759 0.025063539 0.033166318 0.008102779
+6.510263930 0.026334311 0.034581103 0.008246792
+6.520039101 0.027605083 0.035988346 0.008383263
+6.529814272 0.028875855 0.037387943 0.008512087
+6.539589443 0.030146628 0.038779788 0.008633160
+6.549364614 0.031417400 0.040163778 0.008746378
+6.559139785 0.032688172 0.041539811 0.008851639
+6.568914956 0.033958944 0.042907785 0.008948841
+6.578690127 0.035229717 0.044267600 0.009037884
+6.588465298 0.036500489 0.045619157 0.009118668
+6.598240469 0.037771261 0.046962356 0.009191095
+6.608015640 0.039042033 0.048297101 0.009255067
+6.617790811 0.040312805 0.049623294 0.009310488
+6.627565982 0.041583578 0.050940840 0.009357263
+6.637341153 0.042854350 0.052249646 0.009395296
+6.647116325 0.044125122 0.053549616 0.009424494
+6.656891496 0.045395894 0.054840660 0.009444765
+6.666666667 0.046666667 0.056122685 0.009456018
+6.676441838 0.047937439 0.057395600 0.009458162
+6.686217009 0.049208211 0.058659318 0.009451107
+6.695992180 0.050478983 0.059913749 0.009434766
+6.705767351 0.051749756 0.061158806 0.009409051
+6.715542522 0.053020528 0.062394403 0.009373876
+6.725317693 0.054291300 0.063620455 0.009329155
+6.735092864 0.055562072 0.064836878 0.009274806
+6.744868035 0.056832845 0.066043589 0.009210744
+6.754643206 0.058103617 0.067240505 0.009136888
+6.764418377 0.059374389 0.068427546 0.009053157
+6.774193548 0.060645161 0.069604633 0.008959471
+6.783968719 0.061915934 0.070771685 0.008855752
+6.793743891 0.063186706 0.071928627 0.008741921
+6.803519062 0.064457478 0.073075381 0.008617903
+6.813294233 0.065728250 0.074211872 0.008483622
+6.823069404 0.066999022 0.075338026 0.008339003
+6.832844575 0.068269795 0.076453768 0.008183974
+6.842619746 0.069540567 0.077559028 0.008018461
+6.852394917 0.070811339 0.078653734 0.007842395
+6.862170088 0.072082111 0.079737817 0.007655705
+6.871945259 0.073352884 0.080811207 0.007458323
+6.881720430 0.074623656 0.081873836 0.007250181
+6.891495601 0.075894428 0.082925639 0.007031211
+6.901270772 0.077165200 0.083966550 0.006801350
+6.911045943 0.078435973 0.084996504 0.006560532
+6.920821114 0.079706745 0.086015439 0.006308694
+6.930596285 0.080977517 0.087023292 0.006045774
+6.940371457 0.082248289 0.088020002 0.005771712
+6.950146628 0.083519062 0.089005509 0.005486448
+6.959921799 0.084789834 0.089979756 0.005189922
+6.969696970 0.086060606 0.090942684 0.004882078
+6.979472141 0.087331378 0.091894237 0.004562859
+6.989247312 0.088602151 0.092834360 0.004232209
+6.999022483 0.089872923 0.093762998 0.003890075
+7.008797654 0.090263930 0.094680100 0.004416170
+7.018572825 0.090557185 0.095585612 0.005028427
+7.028347996 0.090850440 0.096479485 0.005629045
+7.038123167 0.091143695 0.097361668 0.006217973
+7.047898338 0.091436950 0.098232114 0.006795164
+7.057673509 0.091730205 0.099090776 0.007360571
+7.067448680 0.092023460 0.099937607 0.007914147
+7.077223851 0.092316716 0.100772562 0.008455847
+7.086999022 0.092609971 0.101595599 0.008985628
+7.096774194 0.092903226 0.102406673 0.009503447
+7.106549365 0.093196481 0.103205745 0.010009264
+7.116324536 0.093489736 0.103992773 0.010503037
+7.126099707 0.093782991 0.104767719 0.010984727
+7.135874878 0.094076246 0.105530544 0.011454298
+7.145650049 0.094369501 0.106281212 0.011911711
+7.155425220 0.094662757 0.107019688 0.012356931
+7.165200391 0.094956012 0.107745936 0.012789925
+7.174975562 0.095249267 0.108459925 0.013210658
+7.184750733 0.095542522 0.109161621 0.013619099
+7.194525904 0.095835777 0.109850993 0.014015216
+7.204301075 0.096129032 0.110528013 0.014398980
+7.214076246 0.096422287 0.111192650 0.014770363
+7.223851417 0.096715543 0.111844879 0.015129336
+7.233626588 0.097008798 0.112484672 0.015475874
+7.243401760 0.097302053 0.113112004 0.015809951
+7.253176931 0.097595308 0.113726852 0.016131544
+7.262952102 0.097888563 0.114329192 0.016440629
+7.272727273 0.098181818 0.114919004 0.016737185
+7.282502444 0.098475073 0.115496266 0.017021192
+7.292277615 0.098768328 0.116060959 0.017292630
+7.302052786 0.099061584 0.116613065 0.017551481
+7.311827957 0.099354839 0.117152566 0.017797728
+7.321603128 0.099648094 0.117679448 0.018031354
+7.331378299 0.099941349 0.118193696 0.018252347
+7.341153470 0.100234604 0.118695295 0.018460691
+7.350928641 0.100527859 0.119184233 0.018656374
+7.360703812 0.100821114 0.119660499 0.018839385
+7.370478983 0.101114370 0.120124084 0.019009714
+7.380254154 0.101407625 0.120574977 0.019167352
+7.390029326 0.101700880 0.121013171 0.019312291
+7.399804497 0.101994135 0.121438660 0.019444525
+7.409579668 0.102287390 0.121851437 0.019564047
+7.419354839 0.102580645 0.122251499 0.019670854
+7.429130010 0.102873900 0.122638842 0.019764942
+7.438905181 0.103167155 0.123013464 0.019846308
+7.448680352 0.103460411 0.123375363 0.019914953
+7.458455523 0.103753666 0.123724541 0.019970875
+7.468230694 0.104046921 0.124060997 0.020014077
+7.478005865 0.104340176 0.124384736 0.020044560
+7.487781036 0.104633431 0.124695758 0.020062327
+7.497556207 0.104926686 0.124994071 0.020067385
+7.507331378 0.105219941 0.125279678 0.020059737
+7.517106549 0.105513196 0.125552588 0.020039391
+7.526881720 0.105806452 0.125812807 0.020006355
+7.536656891 0.106099707 0.126060345 0.019960638
+7.546432063 0.106392962 0.126295212 0.019902250
+7.556207234 0.106686217 0.126517418 0.019831201
+7.565982405 0.106979472 0.126726978 0.019747505
+7.575757576 0.107272727 0.126923902 0.019651175
+7.585532747 0.107565982 0.127108207 0.019542225
+7.595307918 0.107859238 0.127279908 0.019420670
+7.605083089 0.108152493 0.127439020 0.019286528
+7.614858260 0.108445748 0.127585563 0.019139815
+7.624633431 0.108739003 0.127719554 0.018980551
+7.634408602 0.109032258 0.127841014 0.018808756
+7.644183773 0.109325513 0.127949963 0.018624450
+7.653958944 0.109618768 0.128046424 0.018427655
+7.663734115 0.109912023 0.128130418 0.018218395
+7.673509286 0.110205279 0.128201972 0.017996693
+7.683284457 0.110498534 0.128261108 0.017762574
+7.693059629 0.110791789 0.128307854 0.017516065
+7.702834800 0.111085044 0.128342237 0.017257193
+7.712609971 0.111378299 0.128364284 0.016985985
+7.722385142 0.111671554 0.128374026 0.016702472
+7.732160313 0.111964809 0.128371492 0.016406683
+7.741935484 0.112258065 0.128356713 0.016098649
+7.751710655 0.112551320 0.128329723 0.015778403
+7.761485826 0.112844575 0.128290553 0.015445979
+7.771260997 0.113137830 0.128239239 0.015101409
+7.781036168 0.113431085 0.128175816 0.014744731
+7.790811339 0.113724340 0.128100319 0.014375979
+7.800586510 0.114017595 0.128012787 0.013995192
+7.810361681 0.114310850 0.127913257 0.013602407
+7.820136852 0.114604106 0.127801769 0.013197663
+7.829912023 0.114897361 0.127678362 0.012781001
+7.839687195 0.115190616 0.127543078 0.012352462
+7.849462366 0.115483871 0.127395959 0.011912088
+7.859237537 0.115777126 0.127237049 0.011459922
+7.869012708 0.116070381 0.127066390 0.010996009
+7.878787879 0.116363636 0.126884028 0.010520392
+7.888563050 0.116656891 0.126690009 0.010033117
+7.898338221 0.116950147 0.126484379 0.009534233
+7.908113392 0.117243402 0.126267187 0.009023785
+7.917888563 0.117536657 0.126038481 0.008501824
+7.927663734 0.117829912 0.125798310 0.007968398
+7.937438905 0.118123167 0.125546725 0.007423558
+7.947214076 0.118416422 0.125283778 0.006867356
+7.956989247 0.118709677 0.125009520 0.006299842
+7.966764418 0.119002933 0.124724004 0.005721072
+7.976539589 0.119296188 0.124427286 0.005131098
+7.986314761 0.119589443 0.124119418 0.004529975
+7.996089932 0.119882698 0.123800458 0.003917760
+8.005865103 0.119530792 0.123470462 0.003939670
+8.015640274 0.118748778 0.123129487 0.004380709
+8.025415445 0.117966764 0.122777591 0.004810827
+8.035190616 0.117184751 0.122414835 0.005230084
+8.044965787 0.116402737 0.122041276 0.005638539
+8.054740958 0.115620723 0.121656978 0.006036254
+8.064516129 0.114838710 0.121262000 0.006423290
+8.074291300 0.114056696 0.120856406 0.006799710
+8.084066471 0.113274682 0.120440258 0.007165576
+8.093841642 0.112492669 0.120013621 0.007520952
+8.103616813 0.111710655 0.119576559 0.007865904
+8.113391984 0.110928641 0.119129139 0.008200497
+8.123167155 0.110146628 0.118671425 0.008524798
+8.132942326 0.109364614 0.118203486 0.008838873
+8.142717498 0.108582600 0.117725390 0.009142790
+8.152492669 0.107800587 0.117237204 0.009436618
+8.162267840 0.107018573 0.116738999 0.009720426
+8.172043011 0.106236559 0.116230844 0.009994285
+8.181818182 0.105454545 0.115712811 0.010258266
+8.191593353 0.104672532 0.115184970 0.010512439
+8.201368524 0.103890518 0.114647395 0.010756877
+8.211143695 0.103108504 0.114100157 0.010991653
+8.220918866 0.102326491 0.113543331 0.011216841
+8.230694037 0.101544477 0.112976992 0.011432515
+8.240469208 0.100762463 0.112401213 0.011638750
+8.250244379 0.099980450 0.111816071 0.011835622
+8.260019550 0.099198436 0.111221643 0.012023207
+8.269794721 0.098416422 0.110618004 0.012201582
+8.279569892 0.097634409 0.110005234 0.012370825
+8.289345064 0.096852395 0.109383410 0.012531015
+8.299120235 0.096070381 0.108752611 0.012682230
+8.308895406 0.095288368 0.108112917 0.012824549
+8.318670577 0.094506354 0.107464408 0.012958054
+8.328445748 0.093724340 0.106807165 0.013082824
+8.338220919 0.092942326 0.106141268 0.013198942
+8.347996090 0.092160313 0.105466802 0.013306489
+8.357771261 0.091378299 0.104783846 0.013405547
+8.367546432 0.090596285 0.104092486 0.013496201
+8.377321603 0.089814272 0.103392805 0.013578533
+8.387096774 0.089032258 0.102684886 0.013652628
+8.396871945 0.088250244 0.101968816 0.013718571
+8.406647116 0.087468231 0.101244678 0.013776447
+8.416422287 0.086686217 0.100512560 0.013826343
+8.426197458 0.085904203 0.099772547 0.013868343
+8.435972630 0.085122190 0.099024726 0.013902537
+8.445747801 0.084340176 0.098269186 0.013929010
+8.455522972 0.083558162 0.097506013 0.013947850
+8.465298143 0.082776149 0.096735296 0.013959148
+8.475073314 0.081994135 0.095957125 0.013962990
+8.484848485 0.081212121 0.095171588 0.013959467
+8.494623656 0.080430108 0.094378776 0.013948668
+8.504398827 0.079648094 0.093578778 0.013930684
+8.514173998 0.078866080 0.092771686 0.013905606
+8.523949169 0.078084066 0.091957590 0.013873524
+8.533724340 0.077302053 0.091136583 0.013834530
+8.543499511 0.076520039 0.090308756 0.013788717
+8.553274682 0.075738025 0.089474202 0.013736177
+8.563049853 0.074956012 0.088633013 0.013677002
+8.572825024 0.074173998 0.087785284 0.013611286
+8.582600196 0.073391984 0.086931106 0.013539122
+8.592375367 0.072609971 0.086070575 0.013460605
+8.602150538 0.071827957 0.085203785 0.013375828
+8.611925709 0.071045943 0.084330831 0.013284887
+8.621700880 0.070263930 0.083451807 0.013187877
+8.631476051 0.069481916 0.082566808 0.013084893
+8.641251222 0.068699902 0.081675932 0.012976030
+8.651026393 0.067917889 0.080779273 0.012861385
+8.660801564 0.067135875 0.079876928 0.012741054
+8.670576735 0.066353861 0.078968994 0.012615133
+8.680351906 0.065571848 0.078055568 0.012483720
+8.690127077 0.064789834 0.077136747 0.012346913
+8.699902248 0.064007820 0.076212627 0.012204807
+8.709677419 0.063225806 0.075283308 0.012057502
+8.719452590 0.062443793 0.074348888 0.011905095
+8.729227761 0.061661779 0.073409463 0.011747684
+8.739002933 0.060879765 0.072465134 0.011585369
+8.748778104 0.060097752 0.071515998 0.011418247
+8.758553275 0.059315738 0.070562155 0.011246417
+8.768328446 0.058533724 0.069603704 0.011069980
+8.778103617 0.057751711 0.068640744 0.010889033
+8.787878788 0.056969697 0.067673375 0.010703678
+8.797653959 0.056187683 0.066701696 0.010514013
+8.807429130 0.055405670 0.065725808 0.010320138
+8.817204301 0.054623656 0.064745810 0.010122154
+8.826979472 0.053841642 0.063761802 0.009920160
+8.836754643 0.053059629 0.062773886 0.009714258
+8.846529814 0.052277615 0.061782162 0.009504547
+8.856304985 0.051495601 0.060786730 0.009291128
+8.866080156 0.050713587 0.059787690 0.009074103
+8.875855327 0.049931574 0.058785145 0.008853571
+8.885630499 0.049149560 0.057779195 0.008629635
+8.895405670 0.048367546 0.056769940 0.008402394
+8.905180841 0.047585533 0.055757483 0.008171950
+8.914956012 0.046803519 0.054741924 0.007938405
+8.924731183 0.046021505 0.053723365 0.007701859
+8.934506354 0.045239492 0.052701907 0.007462415
+8.944281525 0.044457478 0.051677651 0.007220173
+8.954056696 0.043675464 0.050650698 0.006975234
+8.963831867 0.042893451 0.049621151 0.006727701
+8.973607038 0.042111437 0.048589111 0.006477674
+8.983382209 0.041329423 0.047554679 0.006225256
+8.993157380 0.040547410 0.046517957 0.005970547
+9.002932551 0.040000000 0.045479046 0.005479046
+9.012707722 0.040000000 0.044438047 0.004438047
+9.022482893 0.040000000 0.043395063 0.003395063
+9.032258065 0.040000000 0.042350194 0.002350194
+9.042033236 0.040000000 0.041303542 0.001303542
+9.051808407 0.040000000 0.040255208 0.000255208
+9.061583578 0.040000000 0.039205294 0.000794706
+9.071358749 0.040000000 0.038153900 0.001846100
+9.081133920 0.040000000 0.037101127 0.002898873
+9.090909091 0.040000000 0.036047078 0.003952922
+9.100684262 0.040000000 0.034991852 0.005008148
+9.110459433 0.040000000 0.033935551 0.006064449
+9.120234604 0.040000000 0.032878274 0.007121726
+9.130009775 0.040000000 0.031820124 0.008179876
+9.139784946 0.040000000 0.030761199 0.009238801
+9.149560117 0.040000000 0.029701602 0.010298398
+9.159335288 0.040000000 0.028641430 0.011358570
+9.169110459 0.040000000 0.027580786 0.012419214
+9.178885630 0.040000000 0.026519767 0.013480233
+9.188660802 0.040000000 0.025458475 0.014541525
+9.198435973 0.040000000 0.024397009 0.015602991
+9.208211144 0.040000000 0.023335467 0.016664533
+9.217986315 0.040000000 0.022273950 0.017726050
+9.227761486 0.040000000 0.021212555 0.018787445
+9.237536657 0.040000000 0.020151382 0.019848618
+9.247311828 0.040000000 0.019090529 0.020909471
+9.257086999 0.040000000 0.018030094 0.021969906
+9.266862170 0.040000000 0.016970175 0.023029825
+9.276637341 0.040000000 0.015910870 0.024089130
+9.286412512 0.040000000 0.014852277 0.025147723
+9.296187683 0.040000000 0.013794492 0.026205508
+9.305962854 0.040000000 0.012737613 0.027262387
+9.315738025 0.040000000 0.011681736 0.028318264
+9.325513196 0.040000000 0.010626957 0.029373043
+9.335288368 0.040000000 0.009573373 0.030426627
+9.345063539 0.040000000 0.008521079 0.031478921
+9.354838710 0.040000000 0.007470171 0.032529829
+9.364613881 0.040000000 0.006420744 0.033579256
+9.374389052 0.040000000 0.005372893 0.034627107
+9.384164223 0.040000000 0.004326712 0.035673288
+9.393939394 0.040000000 0.003282295 0.036717705
+9.403714565 0.040000000 0.002239736 0.037760264
+9.413489736 0.040000000 0.001199129 0.038800871
+9.423264907 0.040000000 0.000160566 0.039839434
+9.433040078 0.040000000 -0.000875860 0.040875860
+9.442815249 0.040000000 -0.001910056 0.041910056
+9.452590420 0.040000000 -0.002941932 0.042941932
+9.462365591 0.040000000 -0.003971394 0.043971394
+9.472140762 0.040000000 -0.004998352 0.044998352
+9.481915934 0.040000000 -0.006022716 0.046022716
+9.491691105 0.040000000 -0.007044395 0.047044395
+9.501466276 0.040000000 -0.008063300 0.048063300
+9.511241447 0.040000000 -0.009079340 0.049079340
+9.521016618 0.040000000 -0.010092427 0.050092427
+9.530791789 0.040000000 -0.011102473 0.051102473
+9.540566960 0.040000000 -0.012109389 0.052109389
+9.550342131 0.040000000 -0.013113089 0.053113089
+9.560117302 0.040000000 -0.014113483 0.054113483
+9.569892473 0.040000000 -0.015110487 0.055110487
+9.579667644 0.040000000 -0.016104014 0.056104014
+9.589442815 0.040000000 -0.017093978 0.057093978
+9.599217986 0.040000000 -0.018080295 0.058080295
+9.608993157 0.040000000 -0.019062878 0.059062878
+9.618768328 0.040000000 -0.020041645 0.060041645
+9.628543500 0.040000000 -0.021016511 0.061016511
+9.638318671 0.040000000 -0.021987394 0.061987394
+9.648093842 0.040000000 -0.022954211 0.062954211
+9.657869013 0.040000000 -0.023916879 0.063916879
+9.667644184 0.040000000 -0.024875317 0.064875317
+9.677419355 0.040000000 -0.025829445 0.065829445
+9.687194526 0.040000000 -0.026779182 0.066779182
+9.696969697 0.040000000 -0.027724447 0.067724447
+9.706744868 0.040000000 -0.028665163 0.068665163
+9.716520039 0.040000000 -0.029601249 0.069601249
+9.726295210 0.040000000 -0.030532628 0.070532628
+9.736070381 0.040000000 -0.031459222 0.071459222
+9.745845552 0.040000000 -0.032380954 0.072380954
+9.755620723 0.040000000 -0.033297748 0.073297748
+9.765395894 0.040000000 -0.034209528 0.074209528
+9.775171065 0.040000000 -0.035116220 0.075116220
+9.784946237 0.040000000 -0.036017747 0.076017747
+9.794721408 0.040000000 -0.036914037 0.076914037
+9.804496579 0.040000000 -0.037805016 0.077805016
+9.814271750 0.040000000 -0.038690611 0.078690611
+9.824046921 0.040000000 -0.039570750 0.079570750
+9.833822092 0.040000000 -0.040445362 0.080445362
+9.843597263 0.040000000 -0.041314377 0.081314377
+9.853372434 0.040000000 -0.042177723 0.082177723
+9.863147605 0.040000000 -0.043035332 0.083035332
+9.872922776 0.040000000 -0.043887135 0.083887135
+9.882697947 0.040000000 -0.044733063 0.084733063
+9.892473118 0.040000000 -0.045573049 0.085573049
+9.902248289 0.040000000 -0.046407026 0.086407026
+9.912023460 0.040000000 -0.047234929 0.087234929
+9.921798631 0.040000000 -0.048056691 0.088056691
+9.931573803 0.040000000 -0.048872248 0.088872248
+9.941348974 0.040000000 -0.049681535 0.089681535
+9.951124145 0.040000000 -0.050484491 0.090484491
+9.960899316 0.040000000 -0.051281051 0.091281051
+9.970674487 0.040000000 -0.052071154 0.092071154
+9.980449658 0.040000000 -0.052854739 0.092854739
+9.990224829 0.040000000 -0.053631744 0.093631744
+10.000000000 0.040000000 -0.054402111 0.094402111
diff --git a/examples/takagi-sugeno/approximation.fll b/examples/takagi-sugeno/approximation.fll
new file mode 100644
index 0000000..4461299
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.fll
@@ -0,0 +1,65 @@
+Engine: approximation
+InputVariable: inputX
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ term: NEAR_1 Triangle 0.000 1.000 2.000
+ term: NEAR_2 Triangle 1.000 2.000 3.000
+ term: NEAR_3 Triangle 2.000 3.000 4.000
+ term: NEAR_4 Triangle 3.000 4.000 5.000
+ term: NEAR_5 Triangle 4.000 5.000 6.000
+ term: NEAR_6 Triangle 5.000 6.000 7.000
+ term: NEAR_7 Triangle 6.000 7.000 8.000
+ term: NEAR_8 Triangle 7.000 8.000 9.000
+ term: NEAR_9 Triangle 8.000 9.000 10.000
+OutputVariable: outputFx
+ enabled: true
+ range: -1.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: true
+ term: f1 Constant 0.840
+ term: f2 Constant 0.450
+ term: f3 Constant 0.040
+ term: f4 Constant -0.180
+ term: f5 Constant -0.190
+ term: f6 Constant -0.040
+ term: f7 Constant 0.090
+ term: f8 Constant 0.120
+ term: f9 Constant 0.040
+OutputVariable: trueFx
+ enabled: true
+ range: -1.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: true
+ term: fx Function sin(inputX)/inputX
+OutputVariable: diffFx
+ enabled: true
+ range: -1.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: diff Function fabs(outputFx-trueFx)
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if inputX is NEAR_1 then outputFx is f1
+ rule: if inputX is NEAR_2 then outputFx is f2
+ rule: if inputX is NEAR_3 then outputFx is f3
+ rule: if inputX is NEAR_4 then outputFx is f4
+ rule: if inputX is NEAR_5 then outputFx is f5
+ rule: if inputX is NEAR_6 then outputFx is f6
+ rule: if inputX is NEAR_7 then outputFx is f7
+ rule: if inputX is NEAR_8 then outputFx is f8
+ rule: if inputX is NEAR_9 then outputFx is f9
+ rule: if inputX is any then trueFx is fx and diffFx is diff \ No newline at end of file
diff --git a/examples/takagi-sugeno/approximation.java b/examples/takagi-sugeno/approximation.java
new file mode 100644
index 0000000..c2f9d00
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.java
@@ -0,0 +1,108 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class approximation{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("approximation");
+engine.setDescription("");
+
+InputVariable inputX = new InputVariable();
+inputX.setName("inputX");
+inputX.setDescription("");
+inputX.setEnabled(true);
+inputX.setRange(0.000, 10.000);
+inputX.setLockValueInRange(false);
+inputX.addTerm(new Triangle("NEAR_1", 0.000, 1.000, 2.000));
+inputX.addTerm(new Triangle("NEAR_2", 1.000, 2.000, 3.000));
+inputX.addTerm(new Triangle("NEAR_3", 2.000, 3.000, 4.000));
+inputX.addTerm(new Triangle("NEAR_4", 3.000, 4.000, 5.000));
+inputX.addTerm(new Triangle("NEAR_5", 4.000, 5.000, 6.000));
+inputX.addTerm(new Triangle("NEAR_6", 5.000, 6.000, 7.000));
+inputX.addTerm(new Triangle("NEAR_7", 6.000, 7.000, 8.000));
+inputX.addTerm(new Triangle("NEAR_8", 7.000, 8.000, 9.000));
+inputX.addTerm(new Triangle("NEAR_9", 8.000, 9.000, 10.000));
+engine.addInputVariable(inputX);
+
+OutputVariable outputFx = new OutputVariable();
+outputFx.setName("outputFx");
+outputFx.setDescription("");
+outputFx.setEnabled(true);
+outputFx.setRange(-1.000, 1.000);
+outputFx.setLockValueInRange(false);
+outputFx.setAggregation(null);
+outputFx.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+outputFx.setDefaultValue(Double.NaN);
+outputFx.setLockPreviousValue(true);
+outputFx.addTerm(new Constant("f1", 0.840));
+outputFx.addTerm(new Constant("f2", 0.450));
+outputFx.addTerm(new Constant("f3", 0.040));
+outputFx.addTerm(new Constant("f4", -0.180));
+outputFx.addTerm(new Constant("f5", -0.190));
+outputFx.addTerm(new Constant("f6", -0.040));
+outputFx.addTerm(new Constant("f7", 0.090));
+outputFx.addTerm(new Constant("f8", 0.120));
+outputFx.addTerm(new Constant("f9", 0.040));
+engine.addOutputVariable(outputFx);
+
+OutputVariable trueFx = new OutputVariable();
+trueFx.setName("trueFx");
+trueFx.setDescription("");
+trueFx.setEnabled(true);
+trueFx.setRange(-1.000, 1.000);
+trueFx.setLockValueInRange(false);
+trueFx.setAggregation(null);
+trueFx.setDefuzzifier(new WeightedAverage("Automatic"));
+trueFx.setDefaultValue(Double.NaN);
+trueFx.setLockPreviousValue(true);
+trueFx.addTerm(Function.create("fx", "sin(inputX)/inputX", engine));
+engine.addOutputVariable(trueFx);
+
+OutputVariable diffFx = new OutputVariable();
+diffFx.setName("diffFx");
+diffFx.setDescription("");
+diffFx.setEnabled(true);
+diffFx.setRange(-1.000, 1.000);
+diffFx.setLockValueInRange(false);
+diffFx.setAggregation(null);
+diffFx.setDefuzzifier(new WeightedAverage("Automatic"));
+diffFx.setDefaultValue(Double.NaN);
+diffFx.setLockPreviousValue(false);
+diffFx.addTerm(Function.create("diff", "fabs(outputFx-trueFx)", engine));
+engine.addOutputVariable(diffFx);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_1 then outputFx is f1", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_2 then outputFx is f2", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_3 then outputFx is f3", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_4 then outputFx is f4", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_5 then outputFx is f5", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_6 then outputFx is f6", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_7 then outputFx is f7", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_8 then outputFx is f8", engine));
+ruleBlock.addRule(Rule.parse("if inputX is NEAR_9 then outputFx is f9", engine));
+ruleBlock.addRule(Rule.parse("if inputX is any then trueFx is fx and diffFx is diff", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/approximation.pdf b/examples/takagi-sugeno/approximation.pdf
new file mode 100644
index 0000000..6af8fef
--- /dev/null
+++ b/examples/takagi-sugeno/approximation.pdf
Binary files differ
diff --git a/examples/takagi-sugeno/octave/COPYING b/examples/takagi-sugeno/octave/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/examples/takagi-sugeno/octave/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/examples/takagi-sugeno/octave/DESCRIPTION b/examples/takagi-sugeno/octave/DESCRIPTION
new file mode 100644
index 0000000..35df57d
--- /dev/null
+++ b/examples/takagi-sugeno/octave/DESCRIPTION
@@ -0,0 +1,12 @@
+Name: fuzzy-logic-toolkit
+Version: 0.4.2
+Date: 2012-10-02
+Author: L. Markowsky <lmarkov@users.sourceforge.net>
+Maintainer: L. Markowsky <lmarkov@users.sourceforge.net>
+Title: Octave Fuzzy Logic Toolkit
+Description: A mostly MATLAB-compatible fuzzy logic toolkit for Octave.
+Depends: octave (>= 3.2.4)
+Autoload: no
+License: GPLv3+
+Url: http://octave.sf.net
+ http://sf.net/projects/octave-fuzzy
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.R b/examples/takagi-sugeno/octave/cubic_approximator.R
new file mode 100644
index 0000000..d3d3fbf
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.R
@@ -0,0 +1,84 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "cubic_approximator"
+engine.fll = "Engine: cubic_approximator
+InputVariable: X
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ term: AboutNegFive Triangle -6.000 -5.000 -4.000
+ term: AboutNegFour Triangle -5.000 -4.000 -3.000
+ term: AboutNegThree Triangle -4.000 -3.000 -2.000
+ term: AboutNegTwo Triangle -3.000 -2.000 -1.000
+ term: AboutNegOne Triangle -2.000 -1.000 0.000
+ term: AboutZero Triangle -1.000 0.000 1.000
+ term: AboutOne Triangle 0.000 1.000 2.000
+ term: AboutTwo Triangle 1.000 2.000 3.000
+ term: AboutThree Triangle 2.000 3.000 4.000
+ term: AboutFour Triangle 3.000 4.000 5.000
+ term: AboutFive Triangle 4.000 5.000 6.000
+OutputVariable: ApproxXCubed
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: TangentatNegFive Linear 75.000 250.000
+ term: TangentatNegFour Linear 48.000 128.000
+ term: TangentatNegThree Linear 27.000 54.000
+ term: TangentatNegTwo Linear 12.000 16.000
+ term: TangentatNegOne Linear 3.000 2.000
+ term: TangentatZero Linear 0.000 0.000
+ term: TangentatOne Linear 3.000 -2.000
+ term: TangentatTwo Linear 12.000 -16.000
+ term: TangentatThree Linear 27.000 -54.000
+ term: TangentatFour Linear 48.000 -128.000
+ term: TangentatFive Linear 75.000 -250.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if X is AboutNegFive then ApproxXCubed is TangentatNegFive
+ rule: if X is AboutNegFour then ApproxXCubed is TangentatNegFour
+ rule: if X is AboutNegThree then ApproxXCubed is TangentatNegThree
+ rule: if X is AboutNegTwo then ApproxXCubed is TangentatNegTwo
+ rule: if X is AboutNegOne then ApproxXCubed is TangentatNegOne
+ rule: if X is AboutZero then ApproxXCubed is TangentatZero
+ rule: if X is AboutOne then ApproxXCubed is TangentatOne
+ rule: if X is AboutTwo then ApproxXCubed is TangentatTwo
+ rule: if X is AboutThree then ApproxXCubed is TangentatThree
+ rule: if X is AboutFour then ApproxXCubed is TangentatFour
+ rule: if X is AboutFive then ApproxXCubed is TangentatFive"
+
+engine.fldFile = "cubic_approximator.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(X, ApproxXCubed)) +
+ geom_line(aes(color=ApproxXCubed), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("X vs ApproxXCubed")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(X, ApproxXCubed)) +
+ geom_line(aes(color=ApproxXCubed), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("ApproxXCubed vs X")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.cpp b/examples/takagi-sugeno/octave/cubic_approximator.cpp
new file mode 100644
index 0000000..2b9df3f
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.cpp
@@ -0,0 +1,76 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("cubic_approximator");
+engine->setDescription("");
+
+InputVariable* X = new InputVariable;
+X->setName("X");
+X->setDescription("");
+X->setEnabled(true);
+X->setRange(-5.000, 5.000);
+X->setLockValueInRange(false);
+X->addTerm(new Triangle("AboutNegFive", -6.000, -5.000, -4.000));
+X->addTerm(new Triangle("AboutNegFour", -5.000, -4.000, -3.000));
+X->addTerm(new Triangle("AboutNegThree", -4.000, -3.000, -2.000));
+X->addTerm(new Triangle("AboutNegTwo", -3.000, -2.000, -1.000));
+X->addTerm(new Triangle("AboutNegOne", -2.000, -1.000, 0.000));
+X->addTerm(new Triangle("AboutZero", -1.000, 0.000, 1.000));
+X->addTerm(new Triangle("AboutOne", 0.000, 1.000, 2.000));
+X->addTerm(new Triangle("AboutTwo", 1.000, 2.000, 3.000));
+X->addTerm(new Triangle("AboutThree", 2.000, 3.000, 4.000));
+X->addTerm(new Triangle("AboutFour", 3.000, 4.000, 5.000));
+X->addTerm(new Triangle("AboutFive", 4.000, 5.000, 6.000));
+engine->addInputVariable(X);
+
+OutputVariable* ApproxXCubed = new OutputVariable;
+ApproxXCubed->setName("ApproxXCubed");
+ApproxXCubed->setDescription("");
+ApproxXCubed->setEnabled(true);
+ApproxXCubed->setRange(-5.000, 5.000);
+ApproxXCubed->setLockValueInRange(false);
+ApproxXCubed->setAggregation(fl::null);
+ApproxXCubed->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+ApproxXCubed->setDefaultValue(fl::nan);
+ApproxXCubed->setLockPreviousValue(false);
+ApproxXCubed->addTerm(Linear::create("TangentatNegFive", engine, 75.000, 250.000));
+ApproxXCubed->addTerm(Linear::create("TangentatNegFour", engine, 48.000, 128.000));
+ApproxXCubed->addTerm(Linear::create("TangentatNegThree", engine, 27.000, 54.000));
+ApproxXCubed->addTerm(Linear::create("TangentatNegTwo", engine, 12.000, 16.000));
+ApproxXCubed->addTerm(Linear::create("TangentatNegOne", engine, 3.000, 2.000));
+ApproxXCubed->addTerm(Linear::create("TangentatZero", engine, 0.000, 0.000));
+ApproxXCubed->addTerm(Linear::create("TangentatOne", engine, 3.000, -2.000));
+ApproxXCubed->addTerm(Linear::create("TangentatTwo", engine, 12.000, -16.000));
+ApproxXCubed->addTerm(Linear::create("TangentatThree", engine, 27.000, -54.000));
+ApproxXCubed->addTerm(Linear::create("TangentatFour", engine, 48.000, -128.000));
+ApproxXCubed->addTerm(Linear::create("TangentatFive", engine, 75.000, -250.000));
+engine->addOutputVariable(ApproxXCubed);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if X is AboutNegFive then ApproxXCubed is TangentatNegFive", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutNegFour then ApproxXCubed is TangentatNegFour", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutNegThree then ApproxXCubed is TangentatNegThree", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutNegTwo then ApproxXCubed is TangentatNegTwo", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutNegOne then ApproxXCubed is TangentatNegOne", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutZero then ApproxXCubed is TangentatZero", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutOne then ApproxXCubed is TangentatOne", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutTwo then ApproxXCubed is TangentatTwo", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutThree then ApproxXCubed is TangentatThree", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutFour then ApproxXCubed is TangentatFour", engine));
+ruleBlock->addRule(Rule::parse("if X is AboutFive then ApproxXCubed is TangentatFive", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.fcl b/examples/takagi-sugeno/octave/cubic_approximator.fcl
new file mode 100644
index 0000000..df4e8be
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.fcl
@@ -0,0 +1,59 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK cubic_approximator
+
+VAR_INPUT
+ X: REAL;
+END_VAR
+
+VAR_OUTPUT
+ ApproxXCubed: REAL;
+END_VAR
+
+FUZZIFY X
+ RANGE := (-5.000 .. 5.000);
+ TERM AboutNegFive := Triangle -6.000 -5.000 -4.000;
+ TERM AboutNegFour := Triangle -5.000 -4.000 -3.000;
+ TERM AboutNegThree := Triangle -4.000 -3.000 -2.000;
+ TERM AboutNegTwo := Triangle -3.000 -2.000 -1.000;
+ TERM AboutNegOne := Triangle -2.000 -1.000 0.000;
+ TERM AboutZero := Triangle -1.000 0.000 1.000;
+ TERM AboutOne := Triangle 0.000 1.000 2.000;
+ TERM AboutTwo := Triangle 1.000 2.000 3.000;
+ TERM AboutThree := Triangle 2.000 3.000 4.000;
+ TERM AboutFour := Triangle 3.000 4.000 5.000;
+ TERM AboutFive := Triangle 4.000 5.000 6.000;
+END_FUZZIFY
+
+DEFUZZIFY ApproxXCubed
+ RANGE := (-5.000 .. 5.000);
+ TERM TangentatNegFive := Linear 75.000 250.000;
+ TERM TangentatNegFour := Linear 48.000 128.000;
+ TERM TangentatNegThree := Linear 27.000 54.000;
+ TERM TangentatNegTwo := Linear 12.000 16.000;
+ TERM TangentatNegOne := Linear 3.000 2.000;
+ TERM TangentatZero := Linear 0.000 0.000;
+ TERM TangentatOne := Linear 3.000 -2.000;
+ TERM TangentatTwo := Linear 12.000 -16.000;
+ TERM TangentatThree := Linear 27.000 -54.000;
+ TERM TangentatFour := Linear 48.000 -128.000;
+ TERM TangentatFive := Linear 75.000 -250.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ RULE 1 : if X is AboutNegFive then ApproxXCubed is TangentatNegFive
+ RULE 2 : if X is AboutNegFour then ApproxXCubed is TangentatNegFour
+ RULE 3 : if X is AboutNegThree then ApproxXCubed is TangentatNegThree
+ RULE 4 : if X is AboutNegTwo then ApproxXCubed is TangentatNegTwo
+ RULE 5 : if X is AboutNegOne then ApproxXCubed is TangentatNegOne
+ RULE 6 : if X is AboutZero then ApproxXCubed is TangentatZero
+ RULE 7 : if X is AboutOne then ApproxXCubed is TangentatOne
+ RULE 8 : if X is AboutTwo then ApproxXCubed is TangentatTwo
+ RULE 9 : if X is AboutThree then ApproxXCubed is TangentatThree
+ RULE 10 : if X is AboutFour then ApproxXCubed is TangentatFour
+ RULE 11 : if X is AboutFive then ApproxXCubed is TangentatFive
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.fis b/examples/takagi-sugeno/octave/cubic_approximator.fis
new file mode 100644
index 0000000..e0af36f
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.fis
@@ -0,0 +1,59 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='cubic_approximator'
+Type='sugeno'
+Version=6.0
+NumInputs=1
+NumOutputs=1
+NumRules=11
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='X'
+Range=[-5.000 5.000]
+NumMFs=11
+MF1='AboutNegFive':'trimf',[-6.000 -5.000 -4.000]
+MF2='AboutNegFour':'trimf',[-5.000 -4.000 -3.000]
+MF3='AboutNegThree':'trimf',[-4.000 -3.000 -2.000]
+MF4='AboutNegTwo':'trimf',[-3.000 -2.000 -1.000]
+MF5='AboutNegOne':'trimf',[-2.000 -1.000 0.000]
+MF6='AboutZero':'trimf',[-1.000 0.000 1.000]
+MF7='AboutOne':'trimf',[0.000 1.000 2.000]
+MF8='AboutTwo':'trimf',[1.000 2.000 3.000]
+MF9='AboutThree':'trimf',[2.000 3.000 4.000]
+MF10='AboutFour':'trimf',[3.000 4.000 5.000]
+MF11='AboutFive':'trimf',[4.000 5.000 6.000]
+
+[Output1]
+Name='ApproxXCubed'
+Range=[-5.000 5.000]
+NumMFs=11
+MF1='TangentatNegFive':'linear',[75.000 250.000]
+MF2='TangentatNegFour':'linear',[48.000 128.000]
+MF3='TangentatNegThree':'linear',[27.000 54.000]
+MF4='TangentatNegTwo':'linear',[12.000 16.000]
+MF5='TangentatNegOne':'linear',[3.000 2.000]
+MF6='TangentatZero':'linear',[0.000 0.000]
+MF7='TangentatOne':'linear',[3.000 -2.000]
+MF8='TangentatTwo':'linear',[12.000 -16.000]
+MF9='TangentatThree':'linear',[27.000 -54.000]
+MF10='TangentatFour':'linear',[48.000 -128.000]
+MF11='TangentatFive':'linear',[75.000 -250.000]
+
+[Rules]
+1.000 , 1.000 (1.000) : 1
+2.000 , 2.000 (1.000) : 1
+3.000 , 3.000 (1.000) : 1
+4.000 , 4.000 (1.000) : 1
+5.000 , 5.000 (1.000) : 1
+6.000 , 6.000 (1.000) : 1
+7.000 , 7.000 (1.000) : 1
+8.000 , 8.000 (1.000) : 1
+9.000 , 9.000 (1.000) : 1
+10.000 , 10.000 (1.000) : 1
+11.000 , 11.000 (1.000) : 1
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.fld b/examples/takagi-sugeno/octave/cubic_approximator.fld
new file mode 100644
index 0000000..4f6ddeb
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.fld
@@ -0,0 +1,1025 @@
+X ApproxXCubed
+-5.000000000 -125.000000000
+-4.990224829 -124.142364903
+-4.980449658 -123.289889721
+-4.970674487 -122.442574453
+-4.960899316 -121.600419100
+-4.951124145 -120.763423661
+-4.941348974 -119.931588136
+-4.931573803 -119.104912525
+-4.921798631 -118.283396829
+-4.912023460 -117.467041047
+-4.902248289 -116.655845180
+-4.892473118 -115.849809227
+-4.882697947 -115.048933188
+-4.872922776 -114.253217063
+-4.863147605 -113.462660853
+-4.853372434 -112.677264557
+-4.843597263 -111.897028176
+-4.833822092 -111.121951709
+-4.824046921 -110.352035156
+-4.814271750 -109.587278518
+-4.804496579 -108.827681794
+-4.794721408 -108.073244984
+-4.784946237 -107.323968089
+-4.775171065 -106.579851108
+-4.765395894 -105.840894041
+-4.755620723 -105.107096889
+-4.745845552 -104.378459651
+-4.736070381 -103.654982327
+-4.726295210 -102.936664918
+-4.716520039 -102.223507423
+-4.706744868 -101.515509843
+-4.696969697 -100.812672176
+-4.687194526 -100.114994424
+-4.677419355 -99.422476587
+-4.667644184 -98.735118664
+-4.657869013 -98.052920655
+-4.648093842 -97.375882560
+-4.638318671 -96.704004380
+-4.628543500 -96.037286114
+-4.618768328 -95.375727763
+-4.608993157 -94.719329326
+-4.599217986 -94.068090803
+-4.589442815 -93.422012195
+-4.579667644 -92.781093501
+-4.569892473 -92.145334721
+-4.560117302 -91.514735855
+-4.550342131 -90.889296904
+-4.540566960 -90.269017868
+-4.530791789 -89.653898745
+-4.521016618 -89.043939537
+-4.511241447 -88.439140244
+-4.501466276 -87.839500864
+-4.491691105 -87.245021399
+-4.481915934 -86.655701849
+-4.472140762 -86.071542212
+-4.462365591 -85.492542490
+-4.452590420 -84.918702683
+-4.442815249 -84.350022790
+-4.433040078 -83.786502811
+-4.423264907 -83.228142746
+-4.413489736 -82.674942596
+-4.403714565 -82.126902360
+-4.393939394 -81.584022039
+-4.384164223 -81.046301631
+-4.374389052 -80.513741139
+-4.364613881 -79.986340560
+-4.354838710 -79.464099896
+-4.345063539 -78.947019146
+-4.335288368 -78.435098311
+-4.325513196 -77.928337390
+-4.315738025 -77.426736383
+-4.305962854 -76.930295290
+-4.296187683 -76.439014112
+-4.286412512 -75.952892849
+-4.276637341 -75.471931499
+-4.266862170 -74.996130064
+-4.257086999 -74.525488544
+-4.247311828 -74.060006937
+-4.237536657 -73.599685245
+-4.227761486 -73.144523468
+-4.217986315 -72.694521604
+-4.208211144 -72.249679655
+-4.198435973 -71.809997621
+-4.188660802 -71.375475500
+-4.178885630 -70.946113295
+-4.169110459 -70.521911003
+-4.159335288 -70.102868626
+-4.149560117 -69.688986163
+-4.139784946 -69.280263614
+-4.130009775 -68.876700980
+-4.120234604 -68.478298260
+-4.110459433 -68.085055455
+-4.100684262 -67.696972564
+-4.090909091 -67.314049587
+-4.081133920 -66.936286524
+-4.071358749 -66.563683376
+-4.061583578 -66.196240142
+-4.051808407 -65.833956823
+-4.042033236 -65.476833418
+-4.032258065 -65.124869927
+-4.022482893 -64.778066351
+-4.012707722 -64.436422689
+-4.002932551 -64.099938941
+-3.993157380 -63.604111305
+-3.983382209 -63.041967303
+-3.973607038 -62.483836568
+-3.963831867 -61.929719100
+-3.954056696 -61.379614898
+-3.944281525 -60.833523964
+-3.934506354 -60.291446295
+-3.924731183 -59.753381894
+-3.914956012 -59.219330759
+-3.905180841 -58.689292891
+-3.895405670 -58.163268290
+-3.885630499 -57.641256955
+-3.875855327 -57.123258887
+-3.866080156 -56.609274086
+-3.856304985 -56.099302552
+-3.846529814 -55.593344284
+-3.836754643 -55.091399283
+-3.826979472 -54.593467548
+-3.817204301 -54.099549081
+-3.807429130 -53.609643880
+-3.797653959 -53.123751946
+-3.787878788 -52.641873278
+-3.778103617 -52.164007877
+-3.768328446 -51.690155743
+-3.758553275 -51.220316876
+-3.748778104 -50.754491275
+-3.739002933 -50.292678942
+-3.729227761 -49.834879874
+-3.719452590 -49.381094074
+-3.709677419 -48.931321540
+-3.699902248 -48.485562273
+-3.690127077 -48.043816273
+-3.680351906 -47.606083539
+-3.670576735 -47.172364072
+-3.660801564 -46.742657872
+-3.651026393 -46.316964938
+-3.641251222 -45.895285272
+-3.631476051 -45.477618872
+-3.621700880 -45.063965738
+-3.611925709 -44.654325872
+-3.602150538 -44.248699272
+-3.592375367 -43.847085938
+-3.582600196 -43.449485872
+-3.572825024 -43.055899072
+-3.563049853 -42.666325539
+-3.553274682 -42.280765273
+-3.543499511 -41.899218273
+-3.533724340 -41.521684540
+-3.523949169 -41.148164074
+-3.514173998 -40.778656874
+-3.504398827 -40.413162941
+-3.494623656 -40.051682275
+-3.484848485 -39.694214876
+-3.475073314 -39.340760743
+-3.465298143 -38.991319877
+-3.455522972 -38.645892278
+-3.445747801 -38.304477946
+-3.435972630 -37.967076880
+-3.426197458 -37.633689081
+-3.416422287 -37.304314548
+-3.406647116 -36.978953283
+-3.396871945 -36.657605284
+-3.387096774 -36.340270552
+-3.377321603 -36.026949086
+-3.367546432 -35.717640887
+-3.357771261 -35.412345955
+-3.347996090 -35.111064290
+-3.338220919 -34.813795891
+-3.328445748 -34.520540759
+-3.318670577 -34.231298894
+-3.308895406 -33.946070295
+-3.299120235 -33.664854963
+-3.289345064 -33.387652898
+-3.279569892 -33.114464100
+-3.269794721 -32.845288568
+-3.260019550 -32.580126303
+-3.250244379 -32.318977305
+-3.240469208 -32.061841573
+-3.230694037 -31.808719109
+-3.220918866 -31.559609910
+-3.211143695 -31.314513979
+-3.201368524 -31.073431314
+-3.191593353 -30.836361916
+-3.181818182 -30.603305785
+-3.172043011 -30.374262921
+-3.162267840 -30.149233323
+-3.152492669 -29.928216992
+-3.142717498 -29.711213927
+-3.132942326 -29.498224129
+-3.123167155 -29.289247598
+-3.113391984 -29.084284334
+-3.103616813 -28.883334337
+-3.093841642 -28.686397606
+-3.084066471 -28.493474142
+-3.074291300 -28.304563944
+-3.064516129 -28.119667014
+-3.054740958 -27.938783350
+-3.044965787 -27.761912952
+-3.035190616 -27.589055822
+-3.025415445 -27.420211958
+-3.015640274 -27.255381361
+-3.005865103 -27.094564030
+-2.996089932 -26.867287003
+-2.986314761 -26.537511144
+-2.976539589 -26.210601904
+-2.966764418 -25.886559283
+-2.956989247 -25.565383281
+-2.947214076 -25.247073899
+-2.937438905 -24.931631135
+-2.927663734 -24.619054990
+-2.917888563 -24.309345465
+-2.908113392 -24.002502558
+-2.898338221 -23.698526271
+-2.888563050 -23.397416603
+-2.878787879 -23.099173554
+-2.869012708 -22.803797124
+-2.859237537 -22.511287313
+-2.849462366 -22.221644121
+-2.839687195 -21.934867548
+-2.829912023 -21.650957594
+-2.820136852 -21.369914259
+-2.810361681 -21.091737544
+-2.800586510 -20.816427447
+-2.790811339 -20.543983970
+-2.781036168 -20.274407112
+-2.771260997 -20.007696872
+-2.761485826 -19.743853252
+-2.751710655 -19.482876251
+-2.741935484 -19.224765869
+-2.732160313 -18.969522106
+-2.722385142 -18.717144962
+-2.712609971 -18.467634437
+-2.702834800 -18.220990532
+-2.693059629 -17.977213245
+-2.683284457 -17.736302577
+-2.673509286 -17.498258529
+-2.663734115 -17.263081100
+-2.653958944 -17.030770289
+-2.644183773 -16.801326098
+-2.634408602 -16.574748526
+-2.624633431 -16.351037573
+-2.614858260 -16.130193239
+-2.605083089 -15.912215524
+-2.595307918 -15.697104428
+-2.585532747 -15.484859951
+-2.575757576 -15.275482094
+-2.565982405 -15.068970855
+-2.556207234 -14.865326236
+-2.546432063 -14.664548235
+-2.536656891 -14.466636854
+-2.526881720 -14.271592092
+-2.517106549 -14.079413948
+-2.507331378 -13.890102424
+-2.497556207 -13.703657519
+-2.487781036 -13.520079233
+-2.478005865 -13.339367566
+-2.468230694 -13.161522519
+-2.458455523 -12.986544090
+-2.448680352 -12.814432280
+-2.438905181 -12.645187090
+-2.429130010 -12.478808518
+-2.419354839 -12.315296566
+-2.409579668 -12.154651233
+-2.399804497 -11.996872519
+-2.390029326 -11.841960423
+-2.380254154 -11.689914947
+-2.370478983 -11.540736090
+-2.360703812 -11.394423853
+-2.350928641 -11.250978234
+-2.341153470 -11.110399234
+-2.331378299 -10.972686853
+-2.321603128 -10.837841092
+-2.311827957 -10.705861949
+-2.302052786 -10.576749426
+-2.292277615 -10.450503522
+-2.282502444 -10.327124236
+-2.272727273 -10.206611570
+-2.262952102 -10.088965523
+-2.253176931 -9.974186095
+-2.243401760 -9.862273286
+-2.233626588 -9.753227096
+-2.223851417 -9.647047526
+-2.214076246 -9.543734574
+-2.204301075 -9.443288241
+-2.194525904 -9.345708528
+-2.184750733 -9.250995433
+-2.174975562 -9.159148958
+-2.165200391 -9.070169102
+-2.155425220 -8.984055865
+-2.145650049 -8.900809247
+-2.135874878 -8.820429248
+-2.126099707 -8.742915868
+-2.116324536 -8.668269107
+-2.106549365 -8.596488965
+-2.096774194 -8.527575442
+-2.086999022 -8.461528539
+-2.077223851 -8.398348254
+-2.067448680 -8.338034589
+-2.057673509 -8.280587542
+-2.047898338 -8.226007115
+-2.038123167 -8.174293307
+-2.028347996 -8.125446118
+-2.018572825 -8.079465548
+-2.008797654 -8.036351597
+-1.999022483 -7.984368326
+-1.989247312 -7.828997572
+-1.979472141 -7.675346789
+-1.969696970 -7.523415978
+-1.959921799 -7.373205138
+-1.950146628 -7.224714270
+-1.940371457 -7.077943373
+-1.930596285 -6.932892447
+-1.920821114 -6.789561493
+-1.911045943 -6.647950511
+-1.901270772 -6.508059500
+-1.891495601 -6.369888460
+-1.881720430 -6.233437392
+-1.871945259 -6.098706295
+-1.862170088 -5.965695169
+-1.852394917 -5.834404016
+-1.842619746 -5.704832833
+-1.832844575 -5.576981622
+-1.823069404 -5.450850383
+-1.813294233 -5.326439114
+-1.803519062 -5.203747818
+-1.793743891 -5.082776493
+-1.783968719 -4.963525139
+-1.774193548 -4.845993757
+-1.764418377 -4.730182346
+-1.754643206 -4.616090906
+-1.744868035 -4.503719438
+-1.735092864 -4.393067942
+-1.725317693 -4.284136417
+-1.715542522 -4.176924863
+-1.705767351 -4.071433281
+-1.695992180 -3.967661670
+-1.686217009 -3.865610031
+-1.676441838 -3.765278363
+-1.666666667 -3.666666667
+-1.656891496 -3.569774942
+-1.647116325 -3.474603188
+-1.637341153 -3.381151406
+-1.627565982 -3.289419596
+-1.617790811 -3.199407756
+-1.608015640 -3.111115889
+-1.598240469 -3.024543993
+-1.588465298 -2.939692068
+-1.578690127 -2.856560114
+-1.568914956 -2.775148133
+-1.559139785 -2.695456122
+-1.549364614 -2.617484083
+-1.539589443 -2.541232016
+-1.529814272 -2.466699919
+-1.520039101 -2.393887795
+-1.510263930 -2.322795642
+-1.500488759 -2.253423460
+-1.490713587 -2.185771250
+-1.480938416 -2.119839011
+-1.471163245 -2.055626743
+-1.461388074 -1.993134447
+-1.451612903 -1.932362123
+-1.441837732 -1.873309770
+-1.432062561 -1.815977388
+-1.422287390 -1.760364978
+-1.412512219 -1.706472539
+-1.402737048 -1.654300072
+-1.392961877 -1.603847576
+-1.383186706 -1.555115052
+-1.373411535 -1.508102499
+-1.363636364 -1.462809917
+-1.353861193 -1.419237307
+-1.344086022 -1.377384669
+-1.334310850 -1.337252002
+-1.324535679 -1.298839306
+-1.314760508 -1.262146582
+-1.304985337 -1.227173829
+-1.295210166 -1.193921048
+-1.285434995 -1.162388238
+-1.275659824 -1.132575399
+-1.265884653 -1.104482532
+-1.256109482 -1.078109637
+-1.246334311 -1.053456713
+-1.236559140 -1.030523760
+-1.226783969 -1.009310779
+-1.217008798 -0.989817769
+-1.207233627 -0.972044731
+-1.197458456 -0.955991664
+-1.187683284 -0.941658568
+-1.177908113 -0.929045445
+-1.168132942 -0.918152292
+-1.158357771 -0.908979111
+-1.148582600 -0.901525901
+-1.138807429 -0.895792663
+-1.129032258 -0.891779396
+-1.119257087 -0.889486101
+-1.109481916 -0.888912777
+-1.099706745 -0.890059425
+-1.089931574 -0.892926044
+-1.080156403 -0.897512635
+-1.070381232 -0.903819197
+-1.060606061 -0.911845730
+-1.050830890 -0.921592235
+-1.041055718 -0.933058711
+-1.031280547 -0.946245159
+-1.021505376 -0.961151578
+-1.011730205 -0.977777969
+-1.001955034 -0.996124331
+-0.992179863 -0.968902916
+-0.982404692 -0.930547553
+-0.972629521 -0.892765513
+-0.962854350 -0.855556798
+-0.953079179 -0.818921406
+-0.943304008 -0.782859338
+-0.933528837 -0.747370594
+-0.923753666 -0.712455173
+-0.913978495 -0.678113077
+-0.904203324 -0.644344304
+-0.894428152 -0.611148855
+-0.884652981 -0.578526730
+-0.874877810 -0.546477928
+-0.865102639 -0.515002451
+-0.855327468 -0.484100297
+-0.845552297 -0.453771467
+-0.835777126 -0.424015961
+-0.826001955 -0.394833779
+-0.816226784 -0.366224921
+-0.806451613 -0.338189386
+-0.796676442 -0.310727175
+-0.786901271 -0.283838288
+-0.777126100 -0.257522725
+-0.767350929 -0.231780486
+-0.757575758 -0.206611570
+-0.747800587 -0.182015979
+-0.738025415 -0.157993711
+-0.728250244 -0.134544767
+-0.718475073 -0.111669146
+-0.708699902 -0.089366850
+-0.698924731 -0.067637877
+-0.689149560 -0.046482228
+-0.679374389 -0.025899903
+-0.669599218 -0.005890902
+-0.659824047 0.013544775
+-0.650048876 0.032407129
+-0.640273705 0.050696158
+-0.630498534 0.068411864
+-0.620723363 0.085554246
+-0.610948192 0.102123305
+-0.601173021 0.118119039
+-0.591397849 0.133541450
+-0.581622678 0.148390537
+-0.571847507 0.162666300
+-0.562072336 0.176368739
+-0.552297165 0.189497854
+-0.542521994 0.202053646
+-0.532746823 0.214036114
+-0.522971652 0.225445258
+-0.513196481 0.236281078
+-0.503421310 0.246543574
+-0.493646139 0.256232747
+-0.483870968 0.265348595
+-0.474095797 0.273891120
+-0.464320626 0.281860321
+-0.454545455 0.289256198
+-0.444770283 0.296078752
+-0.434995112 0.302327981
+-0.425219941 0.308003887
+-0.415444770 0.313106469
+-0.405669599 0.317635727
+-0.395894428 0.321591662
+-0.386119257 0.324974272
+-0.376344086 0.327783559
+-0.366568915 0.330019522
+-0.356793744 0.331682161
+-0.347018573 0.332771476
+-0.337243402 0.333287467
+-0.327468231 0.333230135
+-0.317693060 0.332599479
+-0.307917889 0.331395499
+-0.298142717 0.329618195
+-0.288367546 0.327267567
+-0.278592375 0.324343616
+-0.268817204 0.320846341
+-0.259042033 0.316775742
+-0.249266862 0.312131819
+-0.239491691 0.306914572
+-0.229716520 0.301124001
+-0.219941349 0.294760107
+-0.210166178 0.287822889
+-0.200391007 0.280312347
+-0.190615836 0.272228481
+-0.180840665 0.263571291
+-0.171065494 0.254340778
+-0.161290323 0.244536941
+-0.151515152 0.234159780
+-0.141739980 0.223209295
+-0.131964809 0.211685486
+-0.122189638 0.199588353
+-0.112414467 0.186917897
+-0.102639296 0.173674117
+-0.092864125 0.159857013
+-0.083088954 0.145466585
+-0.073313783 0.130502834
+-0.063538612 0.114965758
+-0.053763441 0.098855359
+-0.043988270 0.082171636
+-0.034213099 0.064914589
+-0.024437928 0.047084218
+-0.014662757 0.028680524
+-0.004887586 0.009703506
+0.004887586 -0.009703506
+0.014662757 -0.028680524
+0.024437928 -0.047084218
+0.034213099 -0.064914589
+0.043988270 -0.082171636
+0.053763441 -0.098855359
+0.063538612 -0.114965758
+0.073313783 -0.130502834
+0.083088954 -0.145466585
+0.092864125 -0.159857013
+0.102639296 -0.173674117
+0.112414467 -0.186917897
+0.122189638 -0.199588353
+0.131964809 -0.211685486
+0.141739980 -0.223209295
+0.151515152 -0.234159780
+0.161290323 -0.244536941
+0.171065494 -0.254340778
+0.180840665 -0.263571291
+0.190615836 -0.272228481
+0.200391007 -0.280312347
+0.210166178 -0.287822889
+0.219941349 -0.294760107
+0.229716520 -0.301124001
+0.239491691 -0.306914572
+0.249266862 -0.312131819
+0.259042033 -0.316775742
+0.268817204 -0.320846341
+0.278592375 -0.324343616
+0.288367546 -0.327267567
+0.298142717 -0.329618195
+0.307917889 -0.331395499
+0.317693060 -0.332599479
+0.327468231 -0.333230135
+0.337243402 -0.333287467
+0.347018573 -0.332771476
+0.356793744 -0.331682161
+0.366568915 -0.330019522
+0.376344086 -0.327783559
+0.386119257 -0.324974272
+0.395894428 -0.321591662
+0.405669599 -0.317635727
+0.415444770 -0.313106469
+0.425219941 -0.308003887
+0.434995112 -0.302327981
+0.444770283 -0.296078752
+0.454545455 -0.289256198
+0.464320626 -0.281860321
+0.474095797 -0.273891120
+0.483870968 -0.265348595
+0.493646139 -0.256232747
+0.503421310 -0.246543574
+0.513196481 -0.236281078
+0.522971652 -0.225445258
+0.532746823 -0.214036114
+0.542521994 -0.202053646
+0.552297165 -0.189497854
+0.562072336 -0.176368739
+0.571847507 -0.162666300
+0.581622678 -0.148390537
+0.591397849 -0.133541450
+0.601173021 -0.118119039
+0.610948192 -0.102123305
+0.620723363 -0.085554246
+0.630498534 -0.068411864
+0.640273705 -0.050696158
+0.650048876 -0.032407129
+0.659824047 -0.013544775
+0.669599218 0.005890902
+0.679374389 0.025899903
+0.689149560 0.046482228
+0.698924731 0.067637877
+0.708699902 0.089366850
+0.718475073 0.111669146
+0.728250244 0.134544767
+0.738025415 0.157993711
+0.747800587 0.182015979
+0.757575758 0.206611570
+0.767350929 0.231780486
+0.777126100 0.257522725
+0.786901271 0.283838288
+0.796676442 0.310727175
+0.806451613 0.338189386
+0.816226784 0.366224921
+0.826001955 0.394833779
+0.835777126 0.424015961
+0.845552297 0.453771467
+0.855327468 0.484100297
+0.865102639 0.515002451
+0.874877810 0.546477928
+0.884652981 0.578526730
+0.894428152 0.611148855
+0.904203324 0.644344304
+0.913978495 0.678113077
+0.923753666 0.712455173
+0.933528837 0.747370594
+0.943304008 0.782859338
+0.953079179 0.818921406
+0.962854350 0.855556798
+0.972629521 0.892765513
+0.982404692 0.930547553
+0.992179863 0.968902916
+1.001955034 0.996124331
+1.011730205 0.977777969
+1.021505376 0.961151578
+1.031280547 0.946245159
+1.041055718 0.933058711
+1.050830890 0.921592235
+1.060606061 0.911845730
+1.070381232 0.903819197
+1.080156403 0.897512635
+1.089931574 0.892926044
+1.099706745 0.890059425
+1.109481916 0.888912777
+1.119257087 0.889486101
+1.129032258 0.891779396
+1.138807429 0.895792663
+1.148582600 0.901525901
+1.158357771 0.908979111
+1.168132942 0.918152292
+1.177908113 0.929045445
+1.187683284 0.941658568
+1.197458456 0.955991664
+1.207233627 0.972044731
+1.217008798 0.989817769
+1.226783969 1.009310779
+1.236559140 1.030523760
+1.246334311 1.053456713
+1.256109482 1.078109637
+1.265884653 1.104482532
+1.275659824 1.132575399
+1.285434995 1.162388238
+1.295210166 1.193921048
+1.304985337 1.227173829
+1.314760508 1.262146582
+1.324535679 1.298839306
+1.334310850 1.337252002
+1.344086022 1.377384669
+1.353861193 1.419237307
+1.363636364 1.462809917
+1.373411535 1.508102499
+1.383186706 1.555115052
+1.392961877 1.603847576
+1.402737048 1.654300072
+1.412512219 1.706472539
+1.422287390 1.760364978
+1.432062561 1.815977388
+1.441837732 1.873309770
+1.451612903 1.932362123
+1.461388074 1.993134447
+1.471163245 2.055626743
+1.480938416 2.119839011
+1.490713587 2.185771250
+1.500488759 2.253423460
+1.510263930 2.322795642
+1.520039101 2.393887795
+1.529814272 2.466699919
+1.539589443 2.541232016
+1.549364614 2.617484083
+1.559139785 2.695456122
+1.568914956 2.775148133
+1.578690127 2.856560114
+1.588465298 2.939692068
+1.598240469 3.024543993
+1.608015640 3.111115889
+1.617790811 3.199407756
+1.627565982 3.289419596
+1.637341153 3.381151406
+1.647116325 3.474603188
+1.656891496 3.569774942
+1.666666667 3.666666667
+1.676441838 3.765278363
+1.686217009 3.865610031
+1.695992180 3.967661670
+1.705767351 4.071433281
+1.715542522 4.176924863
+1.725317693 4.284136417
+1.735092864 4.393067942
+1.744868035 4.503719438
+1.754643206 4.616090906
+1.764418377 4.730182346
+1.774193548 4.845993757
+1.783968719 4.963525139
+1.793743891 5.082776493
+1.803519062 5.203747818
+1.813294233 5.326439114
+1.823069404 5.450850383
+1.832844575 5.576981622
+1.842619746 5.704832833
+1.852394917 5.834404016
+1.862170088 5.965695169
+1.871945259 6.098706295
+1.881720430 6.233437392
+1.891495601 6.369888460
+1.901270772 6.508059500
+1.911045943 6.647950511
+1.920821114 6.789561493
+1.930596285 6.932892447
+1.940371457 7.077943373
+1.950146628 7.224714270
+1.959921799 7.373205138
+1.969696970 7.523415978
+1.979472141 7.675346789
+1.989247312 7.828997572
+1.999022483 7.984368326
+2.008797654 8.036351597
+2.018572825 8.079465548
+2.028347996 8.125446118
+2.038123167 8.174293307
+2.047898338 8.226007115
+2.057673509 8.280587542
+2.067448680 8.338034589
+2.077223851 8.398348254
+2.086999022 8.461528539
+2.096774194 8.527575442
+2.106549365 8.596488965
+2.116324536 8.668269107
+2.126099707 8.742915868
+2.135874878 8.820429248
+2.145650049 8.900809247
+2.155425220 8.984055865
+2.165200391 9.070169102
+2.174975562 9.159148958
+2.184750733 9.250995433
+2.194525904 9.345708528
+2.204301075 9.443288241
+2.214076246 9.543734574
+2.223851417 9.647047526
+2.233626588 9.753227096
+2.243401760 9.862273286
+2.253176931 9.974186095
+2.262952102 10.088965523
+2.272727273 10.206611570
+2.282502444 10.327124236
+2.292277615 10.450503522
+2.302052786 10.576749426
+2.311827957 10.705861949
+2.321603128 10.837841092
+2.331378299 10.972686853
+2.341153470 11.110399234
+2.350928641 11.250978234
+2.360703812 11.394423853
+2.370478983 11.540736090
+2.380254154 11.689914947
+2.390029326 11.841960423
+2.399804497 11.996872519
+2.409579668 12.154651233
+2.419354839 12.315296566
+2.429130010 12.478808518
+2.438905181 12.645187090
+2.448680352 12.814432280
+2.458455523 12.986544090
+2.468230694 13.161522519
+2.478005865 13.339367566
+2.487781036 13.520079233
+2.497556207 13.703657519
+2.507331378 13.890102424
+2.517106549 14.079413948
+2.526881720 14.271592092
+2.536656891 14.466636854
+2.546432063 14.664548235
+2.556207234 14.865326236
+2.565982405 15.068970855
+2.575757576 15.275482094
+2.585532747 15.484859951
+2.595307918 15.697104428
+2.605083089 15.912215524
+2.614858260 16.130193239
+2.624633431 16.351037573
+2.634408602 16.574748526
+2.644183773 16.801326098
+2.653958944 17.030770289
+2.663734115 17.263081100
+2.673509286 17.498258529
+2.683284457 17.736302577
+2.693059629 17.977213245
+2.702834800 18.220990532
+2.712609971 18.467634437
+2.722385142 18.717144962
+2.732160313 18.969522106
+2.741935484 19.224765869
+2.751710655 19.482876251
+2.761485826 19.743853252
+2.771260997 20.007696872
+2.781036168 20.274407112
+2.790811339 20.543983970
+2.800586510 20.816427447
+2.810361681 21.091737544
+2.820136852 21.369914259
+2.829912023 21.650957594
+2.839687195 21.934867548
+2.849462366 22.221644121
+2.859237537 22.511287313
+2.869012708 22.803797124
+2.878787879 23.099173554
+2.888563050 23.397416603
+2.898338221 23.698526271
+2.908113392 24.002502558
+2.917888563 24.309345465
+2.927663734 24.619054990
+2.937438905 24.931631135
+2.947214076 25.247073899
+2.956989247 25.565383281
+2.966764418 25.886559283
+2.976539589 26.210601904
+2.986314761 26.537511144
+2.996089932 26.867287003
+3.005865103 27.094564030
+3.015640274 27.255381361
+3.025415445 27.420211958
+3.035190616 27.589055822
+3.044965787 27.761912952
+3.054740958 27.938783350
+3.064516129 28.119667014
+3.074291300 28.304563944
+3.084066471 28.493474142
+3.093841642 28.686397606
+3.103616813 28.883334337
+3.113391984 29.084284334
+3.123167155 29.289247598
+3.132942326 29.498224129
+3.142717498 29.711213927
+3.152492669 29.928216992
+3.162267840 30.149233323
+3.172043011 30.374262921
+3.181818182 30.603305785
+3.191593353 30.836361916
+3.201368524 31.073431314
+3.211143695 31.314513979
+3.220918866 31.559609910
+3.230694037 31.808719109
+3.240469208 32.061841573
+3.250244379 32.318977305
+3.260019550 32.580126303
+3.269794721 32.845288568
+3.279569892 33.114464100
+3.289345064 33.387652898
+3.299120235 33.664854963
+3.308895406 33.946070295
+3.318670577 34.231298894
+3.328445748 34.520540759
+3.338220919 34.813795891
+3.347996090 35.111064290
+3.357771261 35.412345955
+3.367546432 35.717640887
+3.377321603 36.026949086
+3.387096774 36.340270552
+3.396871945 36.657605284
+3.406647116 36.978953283
+3.416422287 37.304314548
+3.426197458 37.633689081
+3.435972630 37.967076880
+3.445747801 38.304477946
+3.455522972 38.645892278
+3.465298143 38.991319877
+3.475073314 39.340760743
+3.484848485 39.694214876
+3.494623656 40.051682275
+3.504398827 40.413162941
+3.514173998 40.778656874
+3.523949169 41.148164074
+3.533724340 41.521684540
+3.543499511 41.899218273
+3.553274682 42.280765273
+3.563049853 42.666325539
+3.572825024 43.055899072
+3.582600196 43.449485872
+3.592375367 43.847085938
+3.602150538 44.248699272
+3.611925709 44.654325872
+3.621700880 45.063965738
+3.631476051 45.477618872
+3.641251222 45.895285272
+3.651026393 46.316964938
+3.660801564 46.742657872
+3.670576735 47.172364072
+3.680351906 47.606083539
+3.690127077 48.043816273
+3.699902248 48.485562273
+3.709677419 48.931321540
+3.719452590 49.381094074
+3.729227761 49.834879874
+3.739002933 50.292678942
+3.748778104 50.754491275
+3.758553275 51.220316876
+3.768328446 51.690155743
+3.778103617 52.164007877
+3.787878788 52.641873278
+3.797653959 53.123751946
+3.807429130 53.609643880
+3.817204301 54.099549081
+3.826979472 54.593467548
+3.836754643 55.091399283
+3.846529814 55.593344284
+3.856304985 56.099302552
+3.866080156 56.609274086
+3.875855327 57.123258887
+3.885630499 57.641256955
+3.895405670 58.163268290
+3.905180841 58.689292891
+3.914956012 59.219330759
+3.924731183 59.753381894
+3.934506354 60.291446295
+3.944281525 60.833523964
+3.954056696 61.379614898
+3.963831867 61.929719100
+3.973607038 62.483836568
+3.983382209 63.041967303
+3.993157380 63.604111305
+4.002932551 64.099938941
+4.012707722 64.436422689
+4.022482893 64.778066351
+4.032258065 65.124869927
+4.042033236 65.476833418
+4.051808407 65.833956823
+4.061583578 66.196240142
+4.071358749 66.563683376
+4.081133920 66.936286524
+4.090909091 67.314049587
+4.100684262 67.696972564
+4.110459433 68.085055455
+4.120234604 68.478298260
+4.130009775 68.876700980
+4.139784946 69.280263614
+4.149560117 69.688986163
+4.159335288 70.102868626
+4.169110459 70.521911003
+4.178885630 70.946113295
+4.188660802 71.375475500
+4.198435973 71.809997621
+4.208211144 72.249679655
+4.217986315 72.694521604
+4.227761486 73.144523468
+4.237536657 73.599685245
+4.247311828 74.060006937
+4.257086999 74.525488544
+4.266862170 74.996130064
+4.276637341 75.471931499
+4.286412512 75.952892849
+4.296187683 76.439014112
+4.305962854 76.930295290
+4.315738025 77.426736383
+4.325513196 77.928337390
+4.335288368 78.435098311
+4.345063539 78.947019146
+4.354838710 79.464099896
+4.364613881 79.986340560
+4.374389052 80.513741139
+4.384164223 81.046301631
+4.393939394 81.584022039
+4.403714565 82.126902360
+4.413489736 82.674942596
+4.423264907 83.228142746
+4.433040078 83.786502811
+4.442815249 84.350022790
+4.452590420 84.918702683
+4.462365591 85.492542490
+4.472140762 86.071542212
+4.481915934 86.655701849
+4.491691105 87.245021399
+4.501466276 87.839500864
+4.511241447 88.439140244
+4.521016618 89.043939537
+4.530791789 89.653898745
+4.540566960 90.269017868
+4.550342131 90.889296904
+4.560117302 91.514735855
+4.569892473 92.145334721
+4.579667644 92.781093501
+4.589442815 93.422012195
+4.599217986 94.068090803
+4.608993157 94.719329326
+4.618768328 95.375727763
+4.628543500 96.037286114
+4.638318671 96.704004380
+4.648093842 97.375882560
+4.657869013 98.052920655
+4.667644184 98.735118664
+4.677419355 99.422476587
+4.687194526 100.114994424
+4.696969697 100.812672176
+4.706744868 101.515509843
+4.716520039 102.223507423
+4.726295210 102.936664918
+4.736070381 103.654982327
+4.745845552 104.378459651
+4.755620723 105.107096889
+4.765395894 105.840894041
+4.775171065 106.579851108
+4.784946237 107.323968089
+4.794721408 108.073244984
+4.804496579 108.827681794
+4.814271750 109.587278518
+4.824046921 110.352035156
+4.833822092 111.121951709
+4.843597263 111.897028176
+4.853372434 112.677264557
+4.863147605 113.462660853
+4.872922776 114.253217063
+4.882697947 115.048933188
+4.892473118 115.849809227
+4.902248289 116.655845180
+4.912023460 117.467041047
+4.921798631 118.283396829
+4.931573803 119.104912525
+4.941348974 119.931588136
+4.951124145 120.763423661
+4.960899316 121.600419100
+4.970674487 122.442574453
+4.980449658 123.289889721
+4.990224829 124.142364903
+5.000000000 125.000000000
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.fll b/examples/takagi-sugeno/octave/cubic_approximator.fll
new file mode 100644
index 0000000..22b8fa6
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.fll
@@ -0,0 +1,52 @@
+Engine: cubic_approximator
+InputVariable: X
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ term: AboutNegFive Triangle -6.000 -5.000 -4.000
+ term: AboutNegFour Triangle -5.000 -4.000 -3.000
+ term: AboutNegThree Triangle -4.000 -3.000 -2.000
+ term: AboutNegTwo Triangle -3.000 -2.000 -1.000
+ term: AboutNegOne Triangle -2.000 -1.000 0.000
+ term: AboutZero Triangle -1.000 0.000 1.000
+ term: AboutOne Triangle 0.000 1.000 2.000
+ term: AboutTwo Triangle 1.000 2.000 3.000
+ term: AboutThree Triangle 2.000 3.000 4.000
+ term: AboutFour Triangle 3.000 4.000 5.000
+ term: AboutFive Triangle 4.000 5.000 6.000
+OutputVariable: ApproxXCubed
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: TangentatNegFive Linear 75.000 250.000
+ term: TangentatNegFour Linear 48.000 128.000
+ term: TangentatNegThree Linear 27.000 54.000
+ term: TangentatNegTwo Linear 12.000 16.000
+ term: TangentatNegOne Linear 3.000 2.000
+ term: TangentatZero Linear 0.000 0.000
+ term: TangentatOne Linear 3.000 -2.000
+ term: TangentatTwo Linear 12.000 -16.000
+ term: TangentatThree Linear 27.000 -54.000
+ term: TangentatFour Linear 48.000 -128.000
+ term: TangentatFive Linear 75.000 -250.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if X is AboutNegFive then ApproxXCubed is TangentatNegFive
+ rule: if X is AboutNegFour then ApproxXCubed is TangentatNegFour
+ rule: if X is AboutNegThree then ApproxXCubed is TangentatNegThree
+ rule: if X is AboutNegTwo then ApproxXCubed is TangentatNegTwo
+ rule: if X is AboutNegOne then ApproxXCubed is TangentatNegOne
+ rule: if X is AboutZero then ApproxXCubed is TangentatZero
+ rule: if X is AboutOne then ApproxXCubed is TangentatOne
+ rule: if X is AboutTwo then ApproxXCubed is TangentatTwo
+ rule: if X is AboutThree then ApproxXCubed is TangentatThree
+ rule: if X is AboutFour then ApproxXCubed is TangentatFour
+ rule: if X is AboutFive then ApproxXCubed is TangentatFive \ No newline at end of file
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.java b/examples/takagi-sugeno/octave/cubic_approximator.java
new file mode 100644
index 0000000..ed64870
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.java
@@ -0,0 +1,87 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class cubic_approximator{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("cubic_approximator");
+engine.setDescription("");
+
+InputVariable X = new InputVariable();
+X.setName("X");
+X.setDescription("");
+X.setEnabled(true);
+X.setRange(-5.000, 5.000);
+X.setLockValueInRange(false);
+X.addTerm(new Triangle("AboutNegFive", -6.000, -5.000, -4.000));
+X.addTerm(new Triangle("AboutNegFour", -5.000, -4.000, -3.000));
+X.addTerm(new Triangle("AboutNegThree", -4.000, -3.000, -2.000));
+X.addTerm(new Triangle("AboutNegTwo", -3.000, -2.000, -1.000));
+X.addTerm(new Triangle("AboutNegOne", -2.000, -1.000, 0.000));
+X.addTerm(new Triangle("AboutZero", -1.000, 0.000, 1.000));
+X.addTerm(new Triangle("AboutOne", 0.000, 1.000, 2.000));
+X.addTerm(new Triangle("AboutTwo", 1.000, 2.000, 3.000));
+X.addTerm(new Triangle("AboutThree", 2.000, 3.000, 4.000));
+X.addTerm(new Triangle("AboutFour", 3.000, 4.000, 5.000));
+X.addTerm(new Triangle("AboutFive", 4.000, 5.000, 6.000));
+engine.addInputVariable(X);
+
+OutputVariable ApproxXCubed = new OutputVariable();
+ApproxXCubed.setName("ApproxXCubed");
+ApproxXCubed.setDescription("");
+ApproxXCubed.setEnabled(true);
+ApproxXCubed.setRange(-5.000, 5.000);
+ApproxXCubed.setLockValueInRange(false);
+ApproxXCubed.setAggregation(null);
+ApproxXCubed.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+ApproxXCubed.setDefaultValue(Double.NaN);
+ApproxXCubed.setLockPreviousValue(false);
+ApproxXCubed.addTerm(Linear.create("TangentatNegFive", engine, 75.000, 250.000));
+ApproxXCubed.addTerm(Linear.create("TangentatNegFour", engine, 48.000, 128.000));
+ApproxXCubed.addTerm(Linear.create("TangentatNegThree", engine, 27.000, 54.000));
+ApproxXCubed.addTerm(Linear.create("TangentatNegTwo", engine, 12.000, 16.000));
+ApproxXCubed.addTerm(Linear.create("TangentatNegOne", engine, 3.000, 2.000));
+ApproxXCubed.addTerm(Linear.create("TangentatZero", engine, 0.000, 0.000));
+ApproxXCubed.addTerm(Linear.create("TangentatOne", engine, 3.000, -2.000));
+ApproxXCubed.addTerm(Linear.create("TangentatTwo", engine, 12.000, -16.000));
+ApproxXCubed.addTerm(Linear.create("TangentatThree", engine, 27.000, -54.000));
+ApproxXCubed.addTerm(Linear.create("TangentatFour", engine, 48.000, -128.000));
+ApproxXCubed.addTerm(Linear.create("TangentatFive", engine, 75.000, -250.000));
+engine.addOutputVariable(ApproxXCubed);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if X is AboutNegFive then ApproxXCubed is TangentatNegFive", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutNegFour then ApproxXCubed is TangentatNegFour", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutNegThree then ApproxXCubed is TangentatNegThree", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutNegTwo then ApproxXCubed is TangentatNegTwo", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutNegOne then ApproxXCubed is TangentatNegOne", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutZero then ApproxXCubed is TangentatZero", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutOne then ApproxXCubed is TangentatOne", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutTwo then ApproxXCubed is TangentatTwo", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutThree then ApproxXCubed is TangentatThree", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutFour then ApproxXCubed is TangentatFour", engine));
+ruleBlock.addRule(Rule.parse("if X is AboutFive then ApproxXCubed is TangentatFive", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/octave/cubic_approximator.pdf b/examples/takagi-sugeno/octave/cubic_approximator.pdf
new file mode 100644
index 0000000..62d12ee
--- /dev/null
+++ b/examples/takagi-sugeno/octave/cubic_approximator.pdf
Binary files differ
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.R b/examples/takagi-sugeno/octave/heart_disease_risk.R
new file mode 100644
index 0000000..6ea4240
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.R
@@ -0,0 +1,84 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "heart_disease_risk"
+engine.fll = "Engine: heart_disease_risk
+InputVariable: LDLLevel
+ enabled: true
+ range: 0.000 300.000
+ lock-range: false
+ term: Low Trapezoid -1.000 0.000 90.000 110.000
+ term: LowBorderline Trapezoid 90.000 110.000 120.000 140.000
+ term: Borderline Trapezoid 120.000 140.000 150.000 170.000
+ term: HighBorderline Trapezoid 150.000 170.000 180.000 200.000
+ term: High Trapezoid 180.000 200.000 300.000 301.000
+InputVariable: HDLLevel
+ enabled: true
+ range: 0.000 100.000
+ lock-range: false
+ term: LowHDL Trapezoid -1.000 0.000 35.000 45.000
+ term: ModerateHDL Trapezoid 35.000 45.000 55.000 65.000
+ term: HighHDL Trapezoid 55.000 65.000 100.000 101.000
+OutputVariable: HeartDiseaseRisk
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: NoRisk Constant 0.000
+ term: LowRisk Constant 2.500
+ term: MediumRisk Constant 5.000
+ term: HighRisk Constant 7.500
+ term: ExtremeRisk Constant 10.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if LDLLevel is Low and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is Low and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is Low and HDLLevel is HighHDL then HeartDiseaseRisk is NoRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is Borderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is Borderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is Borderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is High and HDLLevel is LowHDL then HeartDiseaseRisk is ExtremeRisk
+ rule: if LDLLevel is High and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is High and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk"
+
+engine.fldFile = "heart_disease_risk.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(LDLLevel, HDLLevel)) +
+ geom_tile(aes(fill=HeartDiseaseRisk)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=LDLLevel, y=HDLLevel, z=HeartDiseaseRisk), color="black") +
+ ggtitle("(LDLLevel, HDLLevel) = HeartDiseaseRisk")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(HDLLevel, LDLLevel)) +
+ geom_tile(aes(fill=HeartDiseaseRisk)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=HDLLevel, y=LDLLevel, z=HeartDiseaseRisk), color="black") +
+ ggtitle("(HDLLevel, LDLLevel) = HeartDiseaseRisk")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.cpp b/examples/takagi-sugeno/octave/heart_disease_risk.cpp
new file mode 100644
index 0000000..12e7f72
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.cpp
@@ -0,0 +1,79 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("heart_disease_risk");
+engine->setDescription("");
+
+InputVariable* LDLLevel = new InputVariable;
+LDLLevel->setName("LDLLevel");
+LDLLevel->setDescription("");
+LDLLevel->setEnabled(true);
+LDLLevel->setRange(0.000, 300.000);
+LDLLevel->setLockValueInRange(false);
+LDLLevel->addTerm(new Trapezoid("Low", -1.000, 0.000, 90.000, 110.000));
+LDLLevel->addTerm(new Trapezoid("LowBorderline", 90.000, 110.000, 120.000, 140.000));
+LDLLevel->addTerm(new Trapezoid("Borderline", 120.000, 140.000, 150.000, 170.000));
+LDLLevel->addTerm(new Trapezoid("HighBorderline", 150.000, 170.000, 180.000, 200.000));
+LDLLevel->addTerm(new Trapezoid("High", 180.000, 200.000, 300.000, 301.000));
+engine->addInputVariable(LDLLevel);
+
+InputVariable* HDLLevel = new InputVariable;
+HDLLevel->setName("HDLLevel");
+HDLLevel->setDescription("");
+HDLLevel->setEnabled(true);
+HDLLevel->setRange(0.000, 100.000);
+HDLLevel->setLockValueInRange(false);
+HDLLevel->addTerm(new Trapezoid("LowHDL", -1.000, 0.000, 35.000, 45.000));
+HDLLevel->addTerm(new Trapezoid("ModerateHDL", 35.000, 45.000, 55.000, 65.000));
+HDLLevel->addTerm(new Trapezoid("HighHDL", 55.000, 65.000, 100.000, 101.000));
+engine->addInputVariable(HDLLevel);
+
+OutputVariable* HeartDiseaseRisk = new OutputVariable;
+HeartDiseaseRisk->setName("HeartDiseaseRisk");
+HeartDiseaseRisk->setDescription("");
+HeartDiseaseRisk->setEnabled(true);
+HeartDiseaseRisk->setRange(0.000, 10.000);
+HeartDiseaseRisk->setLockValueInRange(false);
+HeartDiseaseRisk->setAggregation(fl::null);
+HeartDiseaseRisk->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+HeartDiseaseRisk->setDefaultValue(fl::nan);
+HeartDiseaseRisk->setLockPreviousValue(false);
+HeartDiseaseRisk->addTerm(new Constant("NoRisk", 0.000));
+HeartDiseaseRisk->addTerm(new Constant("LowRisk", 2.500));
+HeartDiseaseRisk->addTerm(new Constant("MediumRisk", 5.000));
+HeartDiseaseRisk->addTerm(new Constant("HighRisk", 7.500));
+HeartDiseaseRisk->addTerm(new Constant("ExtremeRisk", 10.000));
+engine->addOutputVariable(HeartDiseaseRisk);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new Minimum);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if LDLLevel is Low and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is Low and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is Low and HDLLevel is HighHDL then HeartDiseaseRisk is NoRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is LowBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is LowBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is LowBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is Borderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is Borderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is Borderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is HighBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is HighBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is HighBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is High and HDLLevel is LowHDL then HeartDiseaseRisk is ExtremeRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is High and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock->addRule(Rule::parse("if LDLLevel is High and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.fcl b/examples/takagi-sugeno/octave/heart_disease_risk.fcl
new file mode 100644
index 0000000..4e09d59
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.fcl
@@ -0,0 +1,60 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK heart_disease_risk
+
+VAR_INPUT
+ LDLLevel: REAL;
+ HDLLevel: REAL;
+END_VAR
+
+VAR_OUTPUT
+ HeartDiseaseRisk: REAL;
+END_VAR
+
+FUZZIFY LDLLevel
+ RANGE := (0.000 .. 300.000);
+ TERM Low := Trapezoid -1.000 0.000 90.000 110.000;
+ TERM LowBorderline := Trapezoid 90.000 110.000 120.000 140.000;
+ TERM Borderline := Trapezoid 120.000 140.000 150.000 170.000;
+ TERM HighBorderline := Trapezoid 150.000 170.000 180.000 200.000;
+ TERM High := Trapezoid 180.000 200.000 300.000 301.000;
+END_FUZZIFY
+
+FUZZIFY HDLLevel
+ RANGE := (0.000 .. 100.000);
+ TERM LowHDL := Trapezoid -1.000 0.000 35.000 45.000;
+ TERM ModerateHDL := Trapezoid 35.000 45.000 55.000 65.000;
+ TERM HighHDL := Trapezoid 55.000 65.000 100.000 101.000;
+END_FUZZIFY
+
+DEFUZZIFY HeartDiseaseRisk
+ RANGE := (0.000 .. 10.000);
+ TERM NoRisk := 0.000;
+ TERM LowRisk := 2.500;
+ TERM MediumRisk := 5.000;
+ TERM HighRisk := 7.500;
+ TERM ExtremeRisk := 10.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : MIN;
+ RULE 1 : if LDLLevel is Low and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ RULE 2 : if LDLLevel is Low and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ RULE 3 : if LDLLevel is Low and HDLLevel is HighHDL then HeartDiseaseRisk is NoRisk
+ RULE 4 : if LDLLevel is LowBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ RULE 5 : if LDLLevel is LowBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ RULE 6 : if LDLLevel is LowBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ RULE 7 : if LDLLevel is Borderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ RULE 8 : if LDLLevel is Borderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is MediumRisk
+ RULE 9 : if LDLLevel is Borderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ RULE 10 : if LDLLevel is HighBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ RULE 11 : if LDLLevel is HighBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ RULE 12 : if LDLLevel is HighBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk
+ RULE 13 : if LDLLevel is High and HDLLevel is LowHDL then HeartDiseaseRisk is ExtremeRisk
+ RULE 14 : if LDLLevel is High and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ RULE 15 : if LDLLevel is High and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.fis b/examples/takagi-sugeno/octave/heart_disease_risk.fis
new file mode 100644
index 0000000..485d8d9
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.fis
@@ -0,0 +1,59 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='heart_disease_risk'
+Type='sugeno'
+Version=6.0
+NumInputs=2
+NumOutputs=1
+NumRules=15
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='LDLLevel'
+Range=[0.000 300.000]
+NumMFs=5
+MF1='Low':'trapmf',[-1.000 0.000 90.000 110.000]
+MF2='LowBorderline':'trapmf',[90.000 110.000 120.000 140.000]
+MF3='Borderline':'trapmf',[120.000 140.000 150.000 170.000]
+MF4='HighBorderline':'trapmf',[150.000 170.000 180.000 200.000]
+MF5='High':'trapmf',[180.000 200.000 300.000 301.000]
+
+[Input2]
+Name='HDLLevel'
+Range=[0.000 100.000]
+NumMFs=3
+MF1='LowHDL':'trapmf',[-1.000 0.000 35.000 45.000]
+MF2='ModerateHDL':'trapmf',[35.000 45.000 55.000 65.000]
+MF3='HighHDL':'trapmf',[55.000 65.000 100.000 101.000]
+
+[Output1]
+Name='HeartDiseaseRisk'
+Range=[0.000 10.000]
+NumMFs=5
+MF1='NoRisk':'constant',[0.000]
+MF2='LowRisk':'constant',[2.500]
+MF3='MediumRisk':'constant',[5.000]
+MF4='HighRisk':'constant',[7.500]
+MF5='ExtremeRisk':'constant',[10.000]
+
+[Rules]
+1.000 1.000 , 3.000 (1.000) : 1
+1.000 2.000 , 2.000 (1.000) : 1
+1.000 3.000 , 1.000 (1.000) : 1
+2.000 1.000 , 3.000 (1.000) : 1
+2.000 2.000 , 2.000 (1.000) : 1
+2.000 3.000 , 2.000 (1.000) : 1
+3.000 1.000 , 4.000 (1.000) : 1
+3.000 2.000 , 3.000 (1.000) : 1
+3.000 3.000 , 2.000 (1.000) : 1
+4.000 1.000 , 4.000 (1.000) : 1
+4.000 2.000 , 4.000 (1.000) : 1
+4.000 3.000 , 3.000 (1.000) : 1
+5.000 1.000 , 5.000 (1.000) : 1
+5.000 2.000 , 4.000 (1.000) : 1
+5.000 3.000 , 3.000 (1.000) : 1
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.fld b/examples/takagi-sugeno/octave/heart_disease_risk.fld
new file mode 100644
index 0000000..7b9a00e
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.fld
@@ -0,0 +1,1025 @@
+LDLLevel HDLLevel HeartDiseaseRisk
+0.000000000 0.000000000 5.000000000
+0.000000000 3.225806452 5.000000000
+0.000000000 6.451612903 5.000000000
+0.000000000 9.677419355 5.000000000
+0.000000000 12.903225806 5.000000000
+0.000000000 16.129032258 5.000000000
+0.000000000 19.354838710 5.000000000
+0.000000000 22.580645161 5.000000000
+0.000000000 25.806451613 5.000000000
+0.000000000 29.032258065 5.000000000
+0.000000000 32.258064516 5.000000000
+0.000000000 35.483870968 4.879032258
+0.000000000 38.709677419 4.072580645
+0.000000000 41.935483871 3.266129032
+0.000000000 45.161290323 2.500000000
+0.000000000 48.387096774 2.500000000
+0.000000000 51.612903226 2.500000000
+0.000000000 54.838709677 2.500000000
+0.000000000 58.064516129 1.733870968
+0.000000000 61.290322581 0.927419355
+0.000000000 64.516129032 0.120967742
+0.000000000 67.741935484 0.000000000
+0.000000000 70.967741935 0.000000000
+0.000000000 74.193548387 0.000000000
+0.000000000 77.419354839 0.000000000
+0.000000000 80.645161290 0.000000000
+0.000000000 83.870967742 0.000000000
+0.000000000 87.096774194 0.000000000
+0.000000000 90.322580645 0.000000000
+0.000000000 93.548387097 0.000000000
+0.000000000 96.774193548 0.000000000
+0.000000000 100.000000000 0.000000000
+9.677419355 0.000000000 5.000000000
+9.677419355 3.225806452 5.000000000
+9.677419355 6.451612903 5.000000000
+9.677419355 9.677419355 5.000000000
+9.677419355 12.903225806 5.000000000
+9.677419355 16.129032258 5.000000000
+9.677419355 19.354838710 5.000000000
+9.677419355 22.580645161 5.000000000
+9.677419355 25.806451613 5.000000000
+9.677419355 29.032258065 5.000000000
+9.677419355 32.258064516 5.000000000
+9.677419355 35.483870968 4.879032258
+9.677419355 38.709677419 4.072580645
+9.677419355 41.935483871 3.266129032
+9.677419355 45.161290323 2.500000000
+9.677419355 48.387096774 2.500000000
+9.677419355 51.612903226 2.500000000
+9.677419355 54.838709677 2.500000000
+9.677419355 58.064516129 1.733870968
+9.677419355 61.290322581 0.927419355
+9.677419355 64.516129032 0.120967742
+9.677419355 67.741935484 0.000000000
+9.677419355 70.967741935 0.000000000
+9.677419355 74.193548387 0.000000000
+9.677419355 77.419354839 0.000000000
+9.677419355 80.645161290 0.000000000
+9.677419355 83.870967742 0.000000000
+9.677419355 87.096774194 0.000000000
+9.677419355 90.322580645 0.000000000
+9.677419355 93.548387097 0.000000000
+9.677419355 96.774193548 0.000000000
+9.677419355 100.000000000 0.000000000
+19.354838710 0.000000000 5.000000000
+19.354838710 3.225806452 5.000000000
+19.354838710 6.451612903 5.000000000
+19.354838710 9.677419355 5.000000000
+19.354838710 12.903225806 5.000000000
+19.354838710 16.129032258 5.000000000
+19.354838710 19.354838710 5.000000000
+19.354838710 22.580645161 5.000000000
+19.354838710 25.806451613 5.000000000
+19.354838710 29.032258065 5.000000000
+19.354838710 32.258064516 5.000000000
+19.354838710 35.483870968 4.879032258
+19.354838710 38.709677419 4.072580645
+19.354838710 41.935483871 3.266129032
+19.354838710 45.161290323 2.500000000
+19.354838710 48.387096774 2.500000000
+19.354838710 51.612903226 2.500000000
+19.354838710 54.838709677 2.500000000
+19.354838710 58.064516129 1.733870968
+19.354838710 61.290322581 0.927419355
+19.354838710 64.516129032 0.120967742
+19.354838710 67.741935484 0.000000000
+19.354838710 70.967741935 0.000000000
+19.354838710 74.193548387 0.000000000
+19.354838710 77.419354839 0.000000000
+19.354838710 80.645161290 0.000000000
+19.354838710 83.870967742 0.000000000
+19.354838710 87.096774194 0.000000000
+19.354838710 90.322580645 0.000000000
+19.354838710 93.548387097 0.000000000
+19.354838710 96.774193548 0.000000000
+19.354838710 100.000000000 0.000000000
+29.032258065 0.000000000 5.000000000
+29.032258065 3.225806452 5.000000000
+29.032258065 6.451612903 5.000000000
+29.032258065 9.677419355 5.000000000
+29.032258065 12.903225806 5.000000000
+29.032258065 16.129032258 5.000000000
+29.032258065 19.354838710 5.000000000
+29.032258065 22.580645161 5.000000000
+29.032258065 25.806451613 5.000000000
+29.032258065 29.032258065 5.000000000
+29.032258065 32.258064516 5.000000000
+29.032258065 35.483870968 4.879032258
+29.032258065 38.709677419 4.072580645
+29.032258065 41.935483871 3.266129032
+29.032258065 45.161290323 2.500000000
+29.032258065 48.387096774 2.500000000
+29.032258065 51.612903226 2.500000000
+29.032258065 54.838709677 2.500000000
+29.032258065 58.064516129 1.733870968
+29.032258065 61.290322581 0.927419355
+29.032258065 64.516129032 0.120967742
+29.032258065 67.741935484 0.000000000
+29.032258065 70.967741935 0.000000000
+29.032258065 74.193548387 0.000000000
+29.032258065 77.419354839 0.000000000
+29.032258065 80.645161290 0.000000000
+29.032258065 83.870967742 0.000000000
+29.032258065 87.096774194 0.000000000
+29.032258065 90.322580645 0.000000000
+29.032258065 93.548387097 0.000000000
+29.032258065 96.774193548 0.000000000
+29.032258065 100.000000000 0.000000000
+38.709677419 0.000000000 5.000000000
+38.709677419 3.225806452 5.000000000
+38.709677419 6.451612903 5.000000000
+38.709677419 9.677419355 5.000000000
+38.709677419 12.903225806 5.000000000
+38.709677419 16.129032258 5.000000000
+38.709677419 19.354838710 5.000000000
+38.709677419 22.580645161 5.000000000
+38.709677419 25.806451613 5.000000000
+38.709677419 29.032258065 5.000000000
+38.709677419 32.258064516 5.000000000
+38.709677419 35.483870968 4.879032258
+38.709677419 38.709677419 4.072580645
+38.709677419 41.935483871 3.266129032
+38.709677419 45.161290323 2.500000000
+38.709677419 48.387096774 2.500000000
+38.709677419 51.612903226 2.500000000
+38.709677419 54.838709677 2.500000000
+38.709677419 58.064516129 1.733870968
+38.709677419 61.290322581 0.927419355
+38.709677419 64.516129032 0.120967742
+38.709677419 67.741935484 0.000000000
+38.709677419 70.967741935 0.000000000
+38.709677419 74.193548387 0.000000000
+38.709677419 77.419354839 0.000000000
+38.709677419 80.645161290 0.000000000
+38.709677419 83.870967742 0.000000000
+38.709677419 87.096774194 0.000000000
+38.709677419 90.322580645 0.000000000
+38.709677419 93.548387097 0.000000000
+38.709677419 96.774193548 0.000000000
+38.709677419 100.000000000 0.000000000
+48.387096774 0.000000000 5.000000000
+48.387096774 3.225806452 5.000000000
+48.387096774 6.451612903 5.000000000
+48.387096774 9.677419355 5.000000000
+48.387096774 12.903225806 5.000000000
+48.387096774 16.129032258 5.000000000
+48.387096774 19.354838710 5.000000000
+48.387096774 22.580645161 5.000000000
+48.387096774 25.806451613 5.000000000
+48.387096774 29.032258065 5.000000000
+48.387096774 32.258064516 5.000000000
+48.387096774 35.483870968 4.879032258
+48.387096774 38.709677419 4.072580645
+48.387096774 41.935483871 3.266129032
+48.387096774 45.161290323 2.500000000
+48.387096774 48.387096774 2.500000000
+48.387096774 51.612903226 2.500000000
+48.387096774 54.838709677 2.500000000
+48.387096774 58.064516129 1.733870968
+48.387096774 61.290322581 0.927419355
+48.387096774 64.516129032 0.120967742
+48.387096774 67.741935484 0.000000000
+48.387096774 70.967741935 0.000000000
+48.387096774 74.193548387 0.000000000
+48.387096774 77.419354839 0.000000000
+48.387096774 80.645161290 0.000000000
+48.387096774 83.870967742 0.000000000
+48.387096774 87.096774194 0.000000000
+48.387096774 90.322580645 0.000000000
+48.387096774 93.548387097 0.000000000
+48.387096774 96.774193548 0.000000000
+48.387096774 100.000000000 0.000000000
+58.064516129 0.000000000 5.000000000
+58.064516129 3.225806452 5.000000000
+58.064516129 6.451612903 5.000000000
+58.064516129 9.677419355 5.000000000
+58.064516129 12.903225806 5.000000000
+58.064516129 16.129032258 5.000000000
+58.064516129 19.354838710 5.000000000
+58.064516129 22.580645161 5.000000000
+58.064516129 25.806451613 5.000000000
+58.064516129 29.032258065 5.000000000
+58.064516129 32.258064516 5.000000000
+58.064516129 35.483870968 4.879032258
+58.064516129 38.709677419 4.072580645
+58.064516129 41.935483871 3.266129032
+58.064516129 45.161290323 2.500000000
+58.064516129 48.387096774 2.500000000
+58.064516129 51.612903226 2.500000000
+58.064516129 54.838709677 2.500000000
+58.064516129 58.064516129 1.733870968
+58.064516129 61.290322581 0.927419355
+58.064516129 64.516129032 0.120967742
+58.064516129 67.741935484 0.000000000
+58.064516129 70.967741935 0.000000000
+58.064516129 74.193548387 0.000000000
+58.064516129 77.419354839 0.000000000
+58.064516129 80.645161290 0.000000000
+58.064516129 83.870967742 0.000000000
+58.064516129 87.096774194 0.000000000
+58.064516129 90.322580645 0.000000000
+58.064516129 93.548387097 0.000000000
+58.064516129 96.774193548 0.000000000
+58.064516129 100.000000000 0.000000000
+67.741935484 0.000000000 5.000000000
+67.741935484 3.225806452 5.000000000
+67.741935484 6.451612903 5.000000000
+67.741935484 9.677419355 5.000000000
+67.741935484 12.903225806 5.000000000
+67.741935484 16.129032258 5.000000000
+67.741935484 19.354838710 5.000000000
+67.741935484 22.580645161 5.000000000
+67.741935484 25.806451613 5.000000000
+67.741935484 29.032258065 5.000000000
+67.741935484 32.258064516 5.000000000
+67.741935484 35.483870968 4.879032258
+67.741935484 38.709677419 4.072580645
+67.741935484 41.935483871 3.266129032
+67.741935484 45.161290323 2.500000000
+67.741935484 48.387096774 2.500000000
+67.741935484 51.612903226 2.500000000
+67.741935484 54.838709677 2.500000000
+67.741935484 58.064516129 1.733870968
+67.741935484 61.290322581 0.927419355
+67.741935484 64.516129032 0.120967742
+67.741935484 67.741935484 0.000000000
+67.741935484 70.967741935 0.000000000
+67.741935484 74.193548387 0.000000000
+67.741935484 77.419354839 0.000000000
+67.741935484 80.645161290 0.000000000
+67.741935484 83.870967742 0.000000000
+67.741935484 87.096774194 0.000000000
+67.741935484 90.322580645 0.000000000
+67.741935484 93.548387097 0.000000000
+67.741935484 96.774193548 0.000000000
+67.741935484 100.000000000 0.000000000
+77.419354839 0.000000000 5.000000000
+77.419354839 3.225806452 5.000000000
+77.419354839 6.451612903 5.000000000
+77.419354839 9.677419355 5.000000000
+77.419354839 12.903225806 5.000000000
+77.419354839 16.129032258 5.000000000
+77.419354839 19.354838710 5.000000000
+77.419354839 22.580645161 5.000000000
+77.419354839 25.806451613 5.000000000
+77.419354839 29.032258065 5.000000000
+77.419354839 32.258064516 5.000000000
+77.419354839 35.483870968 4.879032258
+77.419354839 38.709677419 4.072580645
+77.419354839 41.935483871 3.266129032
+77.419354839 45.161290323 2.500000000
+77.419354839 48.387096774 2.500000000
+77.419354839 51.612903226 2.500000000
+77.419354839 54.838709677 2.500000000
+77.419354839 58.064516129 1.733870968
+77.419354839 61.290322581 0.927419355
+77.419354839 64.516129032 0.120967742
+77.419354839 67.741935484 0.000000000
+77.419354839 70.967741935 0.000000000
+77.419354839 74.193548387 0.000000000
+77.419354839 77.419354839 0.000000000
+77.419354839 80.645161290 0.000000000
+77.419354839 83.870967742 0.000000000
+77.419354839 87.096774194 0.000000000
+77.419354839 90.322580645 0.000000000
+77.419354839 93.548387097 0.000000000
+77.419354839 96.774193548 0.000000000
+77.419354839 100.000000000 0.000000000
+87.096774194 0.000000000 5.000000000
+87.096774194 3.225806452 5.000000000
+87.096774194 6.451612903 5.000000000
+87.096774194 9.677419355 5.000000000
+87.096774194 12.903225806 5.000000000
+87.096774194 16.129032258 5.000000000
+87.096774194 19.354838710 5.000000000
+87.096774194 22.580645161 5.000000000
+87.096774194 25.806451613 5.000000000
+87.096774194 29.032258065 5.000000000
+87.096774194 32.258064516 5.000000000
+87.096774194 35.483870968 4.879032258
+87.096774194 38.709677419 4.072580645
+87.096774194 41.935483871 3.266129032
+87.096774194 45.161290323 2.500000000
+87.096774194 48.387096774 2.500000000
+87.096774194 51.612903226 2.500000000
+87.096774194 54.838709677 2.500000000
+87.096774194 58.064516129 1.733870968
+87.096774194 61.290322581 0.927419355
+87.096774194 64.516129032 0.120967742
+87.096774194 67.741935484 0.000000000
+87.096774194 70.967741935 0.000000000
+87.096774194 74.193548387 0.000000000
+87.096774194 77.419354839 0.000000000
+87.096774194 80.645161290 0.000000000
+87.096774194 83.870967742 0.000000000
+87.096774194 87.096774194 0.000000000
+87.096774194 90.322580645 0.000000000
+87.096774194 93.548387097 0.000000000
+87.096774194 96.774193548 0.000000000
+87.096774194 100.000000000 0.000000000
+96.774193548 0.000000000 5.000000000
+96.774193548 3.225806452 5.000000000
+96.774193548 6.451612903 5.000000000
+96.774193548 9.677419355 5.000000000
+96.774193548 12.903225806 5.000000000
+96.774193548 16.129032258 5.000000000
+96.774193548 19.354838710 5.000000000
+96.774193548 22.580645161 5.000000000
+96.774193548 25.806451613 5.000000000
+96.774193548 29.032258065 5.000000000
+96.774193548 32.258064516 5.000000000
+96.774193548 35.483870968 4.779411765
+96.774193548 38.709677419 3.942307692
+96.774193548 41.935483871 3.450000000
+96.774193548 45.161290323 2.500000000
+96.774193548 48.387096774 2.500000000
+96.774193548 51.612903226 2.500000000
+96.774193548 54.838709677 2.500000000
+96.774193548 58.064516129 2.025000000
+96.774193548 61.290322581 1.562500000
+96.774193548 64.516129032 0.992647059
+96.774193548 67.741935484 0.846774194
+96.774193548 70.967741935 0.846774194
+96.774193548 74.193548387 0.846774194
+96.774193548 77.419354839 0.846774194
+96.774193548 80.645161290 0.846774194
+96.774193548 83.870967742 0.846774194
+96.774193548 87.096774194 0.846774194
+96.774193548 90.322580645 0.846774194
+96.774193548 93.548387097 0.846774194
+96.774193548 96.774193548 0.846774194
+96.774193548 100.000000000 0.846774194
+106.451612903 0.000000000 5.000000000
+106.451612903 3.225806452 5.000000000
+106.451612903 6.451612903 5.000000000
+106.451612903 9.677419355 5.000000000
+106.451612903 12.903225806 5.000000000
+106.451612903 16.129032258 5.000000000
+106.451612903 19.354838710 5.000000000
+106.451612903 22.580645161 5.000000000
+106.451612903 25.806451613 5.000000000
+106.451612903 29.032258065 5.000000000
+106.451612903 32.258064516 5.000000000
+106.451612903 35.483870968 4.779411765
+106.451612903 38.709677419 3.988095238
+106.451612903 41.935483871 3.392857143
+106.451612903 45.161290323 2.500000000
+106.451612903 48.387096774 2.500000000
+106.451612903 51.612903226 2.500000000
+106.451612903 54.838709677 2.500000000
+106.451612903 58.064516129 2.172619048
+106.451612903 61.290322581 2.172619048
+106.451612903 64.516129032 2.095588235
+106.451612903 67.741935484 2.056451613
+106.451612903 70.967741935 2.056451613
+106.451612903 74.193548387 2.056451613
+106.451612903 77.419354839 2.056451613
+106.451612903 80.645161290 2.056451613
+106.451612903 83.870967742 2.056451613
+106.451612903 87.096774194 2.056451613
+106.451612903 90.322580645 2.056451613
+106.451612903 93.548387097 2.056451613
+106.451612903 96.774193548 2.056451613
+106.451612903 100.000000000 2.056451613
+116.129032258 0.000000000 5.000000000
+116.129032258 3.225806452 5.000000000
+116.129032258 6.451612903 5.000000000
+116.129032258 9.677419355 5.000000000
+116.129032258 12.903225806 5.000000000
+116.129032258 16.129032258 5.000000000
+116.129032258 19.354838710 5.000000000
+116.129032258 22.580645161 5.000000000
+116.129032258 25.806451613 5.000000000
+116.129032258 29.032258065 5.000000000
+116.129032258 32.258064516 5.000000000
+116.129032258 35.483870968 4.879032258
+116.129032258 38.709677419 4.072580645
+116.129032258 41.935483871 3.266129032
+116.129032258 45.161290323 2.500000000
+116.129032258 48.387096774 2.500000000
+116.129032258 51.612903226 2.500000000
+116.129032258 54.838709677 2.500000000
+116.129032258 58.064516129 2.500000000
+116.129032258 61.290322581 2.500000000
+116.129032258 64.516129032 2.500000000
+116.129032258 67.741935484 2.500000000
+116.129032258 70.967741935 2.500000000
+116.129032258 74.193548387 2.500000000
+116.129032258 77.419354839 2.500000000
+116.129032258 80.645161290 2.500000000
+116.129032258 83.870967742 2.500000000
+116.129032258 87.096774194 2.500000000
+116.129032258 90.322580645 2.500000000
+116.129032258 93.548387097 2.500000000
+116.129032258 96.774193548 2.500000000
+116.129032258 100.000000000 2.500000000
+125.806451613 0.000000000 5.725806452
+125.806451613 3.225806452 5.725806452
+125.806451613 6.451612903 5.725806452
+125.806451613 9.677419355 5.725806452
+125.806451613 12.903225806 5.725806452
+125.806451613 16.129032258 5.725806452
+125.806451613 19.354838710 5.725806452
+125.806451613 22.580645161 5.725806452
+125.806451613 25.806451613 5.725806452
+125.806451613 29.032258065 5.725806452
+125.806451613 32.258064516 5.725806452
+125.806451613 35.483870968 5.551470588
+125.806451613 38.709677419 4.872448980
+125.806451613 41.935483871 4.362244898
+125.806451613 45.161290323 3.225806452
+125.806451613 48.387096774 3.225806452
+125.806451613 51.612903226 3.225806452
+125.806451613 54.838709677 3.225806452
+125.806451613 58.064516129 2.959183673
+125.806451613 61.290322581 2.959183673
+125.806451613 64.516129032 2.610294118
+125.806451613 67.741935484 2.500000000
+125.806451613 70.967741935 2.500000000
+125.806451613 74.193548387 2.500000000
+125.806451613 77.419354839 2.500000000
+125.806451613 80.645161290 2.500000000
+125.806451613 83.870967742 2.500000000
+125.806451613 87.096774194 2.500000000
+125.806451613 90.322580645 2.500000000
+125.806451613 93.548387097 2.500000000
+125.806451613 96.774193548 2.500000000
+125.806451613 100.000000000 2.500000000
+135.483870968 0.000000000 6.935483871
+135.483870968 3.225806452 6.935483871
+135.483870968 6.451612903 6.935483871
+135.483870968 9.677419355 6.935483871
+135.483870968 12.903225806 6.935483871
+135.483870968 16.129032258 6.935483871
+135.483870968 19.354838710 6.935483871
+135.483870968 22.580645161 6.935483871
+135.483870968 25.806451613 6.935483871
+135.483870968 29.032258065 6.935483871
+135.483870968 32.258064516 6.935483871
+135.483870968 35.483870968 6.654411765
+135.483870968 38.709677419 5.694444444
+135.483870968 41.935483871 5.138888889
+135.483870968 45.161290323 4.435483871
+135.483870968 48.387096774 4.435483871
+135.483870968 51.612903226 4.435483871
+135.483870968 54.838709677 4.435483871
+135.483870968 58.064516129 3.694444444
+135.483870968 61.290322581 3.138888889
+135.483870968 64.516129032 2.610294118
+135.483870968 67.741935484 2.500000000
+135.483870968 70.967741935 2.500000000
+135.483870968 74.193548387 2.500000000
+135.483870968 77.419354839 2.500000000
+135.483870968 80.645161290 2.500000000
+135.483870968 83.870967742 2.500000000
+135.483870968 87.096774194 2.500000000
+135.483870968 90.322580645 2.500000000
+135.483870968 93.548387097 2.500000000
+135.483870968 96.774193548 2.500000000
+135.483870968 100.000000000 2.500000000
+145.161290323 0.000000000 7.500000000
+145.161290323 3.225806452 7.500000000
+145.161290323 6.451612903 7.500000000
+145.161290323 9.677419355 7.500000000
+145.161290323 12.903225806 7.500000000
+145.161290323 16.129032258 7.500000000
+145.161290323 19.354838710 7.500000000
+145.161290323 22.580645161 7.500000000
+145.161290323 25.806451613 7.500000000
+145.161290323 29.032258065 7.500000000
+145.161290323 32.258064516 7.500000000
+145.161290323 35.483870968 7.379032258
+145.161290323 38.709677419 6.572580645
+145.161290323 41.935483871 5.766129032
+145.161290323 45.161290323 5.000000000
+145.161290323 48.387096774 5.000000000
+145.161290323 51.612903226 5.000000000
+145.161290323 54.838709677 5.000000000
+145.161290323 58.064516129 4.233870968
+145.161290323 61.290322581 3.427419355
+145.161290323 64.516129032 2.620967742
+145.161290323 67.741935484 2.500000000
+145.161290323 70.967741935 2.500000000
+145.161290323 74.193548387 2.500000000
+145.161290323 77.419354839 2.500000000
+145.161290323 80.645161290 2.500000000
+145.161290323 83.870967742 2.500000000
+145.161290323 87.096774194 2.500000000
+145.161290323 90.322580645 2.500000000
+145.161290323 93.548387097 2.500000000
+145.161290323 96.774193548 2.500000000
+145.161290323 100.000000000 2.500000000
+154.838709677 0.000000000 7.500000000
+154.838709677 3.225806452 7.500000000
+154.838709677 6.451612903 7.500000000
+154.838709677 9.677419355 7.500000000
+154.838709677 12.903225806 7.500000000
+154.838709677 16.129032258 7.500000000
+154.838709677 19.354838710 7.500000000
+154.838709677 22.580645161 7.500000000
+154.838709677 25.806451613 7.500000000
+154.838709677 29.032258065 7.500000000
+154.838709677 32.258064516 7.500000000
+154.838709677 35.483870968 7.389705882
+154.838709677 38.709677419 6.875000000
+154.838709677 41.935483871 6.331521739
+154.838709677 45.161290323 5.604838710
+154.838709677 48.387096774 5.604838710
+154.838709677 51.612903226 5.604838710
+154.838709677 54.838709677 5.604838710
+154.838709677 58.064516129 4.891304348
+154.838709677 61.290322581 4.347826087
+154.838709677 64.516129032 3.382352941
+154.838709677 67.741935484 3.104838710
+154.838709677 70.967741935 3.104838710
+154.838709677 74.193548387 3.104838710
+154.838709677 77.419354839 3.104838710
+154.838709677 80.645161290 3.104838710
+154.838709677 83.870967742 3.104838710
+154.838709677 87.096774194 3.104838710
+154.838709677 90.322580645 3.104838710
+154.838709677 93.548387097 3.104838710
+154.838709677 96.774193548 3.104838710
+154.838709677 100.000000000 3.104838710
+164.516129032 0.000000000 7.500000000
+164.516129032 3.225806452 7.500000000
+164.516129032 6.451612903 7.500000000
+164.516129032 9.677419355 7.500000000
+164.516129032 12.903225806 7.500000000
+164.516129032 16.129032258 7.500000000
+164.516129032 19.354838710 7.500000000
+164.516129032 22.580645161 7.500000000
+164.516129032 25.806451613 7.500000000
+164.516129032 29.032258065 7.500000000
+164.516129032 32.258064516 7.500000000
+164.516129032 35.483870968 7.389705882
+164.516129032 38.709677419 7.057291667
+164.516129032 41.935483871 7.057291667
+164.516129032 45.161290323 6.814516129
+164.516129032 48.387096774 6.814516129
+164.516129032 51.612903226 6.814516129
+164.516129032 54.838709677 6.814516129
+164.516129032 58.064516129 5.677083333
+164.516129032 61.290322581 5.156250000
+164.516129032 64.516129032 4.485294118
+164.516129032 67.741935484 4.314516129
+164.516129032 70.967741935 4.314516129
+164.516129032 74.193548387 4.314516129
+164.516129032 77.419354839 4.314516129
+164.516129032 80.645161290 4.314516129
+164.516129032 83.870967742 4.314516129
+164.516129032 87.096774194 4.314516129
+164.516129032 90.322580645 4.314516129
+164.516129032 93.548387097 4.314516129
+164.516129032 96.774193548 4.314516129
+164.516129032 100.000000000 4.314516129
+174.193548387 0.000000000 7.500000000
+174.193548387 3.225806452 7.500000000
+174.193548387 6.451612903 7.500000000
+174.193548387 9.677419355 7.500000000
+174.193548387 12.903225806 7.500000000
+174.193548387 16.129032258 7.500000000
+174.193548387 19.354838710 7.500000000
+174.193548387 22.580645161 7.500000000
+174.193548387 25.806451613 7.500000000
+174.193548387 29.032258065 7.500000000
+174.193548387 32.258064516 7.500000000
+174.193548387 35.483870968 7.500000000
+174.193548387 38.709677419 7.500000000
+174.193548387 41.935483871 7.500000000
+174.193548387 45.161290323 7.500000000
+174.193548387 48.387096774 7.500000000
+174.193548387 51.612903226 7.500000000
+174.193548387 54.838709677 7.500000000
+174.193548387 58.064516129 6.733870968
+174.193548387 61.290322581 5.927419355
+174.193548387 64.516129032 5.120967742
+174.193548387 67.741935484 5.000000000
+174.193548387 70.967741935 5.000000000
+174.193548387 74.193548387 5.000000000
+174.193548387 77.419354839 5.000000000
+174.193548387 80.645161290 5.000000000
+174.193548387 83.870967742 5.000000000
+174.193548387 87.096774194 5.000000000
+174.193548387 90.322580645 5.000000000
+174.193548387 93.548387097 5.000000000
+174.193548387 96.774193548 5.000000000
+174.193548387 100.000000000 5.000000000
+183.870967742 0.000000000 7.983870968
+183.870967742 3.225806452 7.983870968
+183.870967742 6.451612903 7.983870968
+183.870967742 9.677419355 7.983870968
+183.870967742 12.903225806 7.983870968
+183.870967742 16.129032258 7.983870968
+183.870967742 19.354838710 7.983870968
+183.870967742 22.580645161 7.983870968
+183.870967742 25.806451613 7.983870968
+183.870967742 29.032258065 7.983870968
+183.870967742 32.258064516 7.983870968
+183.870967742 35.483870968 7.941176471
+183.870967742 38.709677419 7.848837209
+183.870967742 41.935483871 7.848837209
+183.870967742 45.161290323 7.500000000
+183.870967742 48.387096774 7.500000000
+183.870967742 51.612903226 7.500000000
+183.870967742 54.838709677 7.500000000
+183.870967742 58.064516129 6.598837209
+183.870967742 61.290322581 6.017441860
+183.870967742 64.516129032 5.220588235
+183.870967742 67.741935484 5.000000000
+183.870967742 70.967741935 5.000000000
+183.870967742 74.193548387 5.000000000
+183.870967742 77.419354839 5.000000000
+183.870967742 80.645161290 5.000000000
+183.870967742 83.870967742 5.000000000
+183.870967742 87.096774194 5.000000000
+183.870967742 90.322580645 5.000000000
+183.870967742 93.548387097 5.000000000
+183.870967742 96.774193548 5.000000000
+183.870967742 100.000000000 5.000000000
+193.548387097 0.000000000 9.193548387
+193.548387097 3.225806452 9.193548387
+193.548387097 6.451612903 9.193548387
+193.548387097 9.677419355 9.193548387
+193.548387097 12.903225806 9.193548387
+193.548387097 16.129032258 9.193548387
+193.548387097 19.354838710 9.193548387
+193.548387097 22.580645161 9.193548387
+193.548387097 25.806451613 9.193548387
+193.548387097 29.032258065 9.193548387
+193.548387097 32.258064516 9.193548387
+193.548387097 35.483870968 9.044117647
+193.548387097 38.709677419 8.455882353
+193.548387097 41.935483871 7.975000000
+193.548387097 45.161290323 7.500000000
+193.548387097 48.387096774 7.500000000
+193.548387097 51.612903226 7.500000000
+193.548387097 54.838709677 7.500000000
+193.548387097 58.064516129 6.550000000
+193.548387097 61.290322581 6.053921569
+193.548387097 64.516129032 5.220588235
+193.548387097 67.741935484 5.000000000
+193.548387097 70.967741935 5.000000000
+193.548387097 74.193548387 5.000000000
+193.548387097 77.419354839 5.000000000
+193.548387097 80.645161290 5.000000000
+193.548387097 83.870967742 5.000000000
+193.548387097 87.096774194 5.000000000
+193.548387097 90.322580645 5.000000000
+193.548387097 93.548387097 5.000000000
+193.548387097 96.774193548 5.000000000
+193.548387097 100.000000000 5.000000000
+203.225806452 0.000000000 10.000000000
+203.225806452 3.225806452 10.000000000
+203.225806452 6.451612903 10.000000000
+203.225806452 9.677419355 10.000000000
+203.225806452 12.903225806 10.000000000
+203.225806452 16.129032258 10.000000000
+203.225806452 19.354838710 10.000000000
+203.225806452 22.580645161 10.000000000
+203.225806452 25.806451613 10.000000000
+203.225806452 29.032258065 10.000000000
+203.225806452 32.258064516 10.000000000
+203.225806452 35.483870968 9.879032258
+203.225806452 38.709677419 9.072580645
+203.225806452 41.935483871 8.266129032
+203.225806452 45.161290323 7.500000000
+203.225806452 48.387096774 7.500000000
+203.225806452 51.612903226 7.500000000
+203.225806452 54.838709677 7.500000000
+203.225806452 58.064516129 6.733870968
+203.225806452 61.290322581 5.927419355
+203.225806452 64.516129032 5.120967742
+203.225806452 67.741935484 5.000000000
+203.225806452 70.967741935 5.000000000
+203.225806452 74.193548387 5.000000000
+203.225806452 77.419354839 5.000000000
+203.225806452 80.645161290 5.000000000
+203.225806452 83.870967742 5.000000000
+203.225806452 87.096774194 5.000000000
+203.225806452 90.322580645 5.000000000
+203.225806452 93.548387097 5.000000000
+203.225806452 96.774193548 5.000000000
+203.225806452 100.000000000 5.000000000
+212.903225806 0.000000000 10.000000000
+212.903225806 3.225806452 10.000000000
+212.903225806 6.451612903 10.000000000
+212.903225806 9.677419355 10.000000000
+212.903225806 12.903225806 10.000000000
+212.903225806 16.129032258 10.000000000
+212.903225806 19.354838710 10.000000000
+212.903225806 22.580645161 10.000000000
+212.903225806 25.806451613 10.000000000
+212.903225806 29.032258065 10.000000000
+212.903225806 32.258064516 10.000000000
+212.903225806 35.483870968 9.879032258
+212.903225806 38.709677419 9.072580645
+212.903225806 41.935483871 8.266129032
+212.903225806 45.161290323 7.500000000
+212.903225806 48.387096774 7.500000000
+212.903225806 51.612903226 7.500000000
+212.903225806 54.838709677 7.500000000
+212.903225806 58.064516129 6.733870968
+212.903225806 61.290322581 5.927419355
+212.903225806 64.516129032 5.120967742
+212.903225806 67.741935484 5.000000000
+212.903225806 70.967741935 5.000000000
+212.903225806 74.193548387 5.000000000
+212.903225806 77.419354839 5.000000000
+212.903225806 80.645161290 5.000000000
+212.903225806 83.870967742 5.000000000
+212.903225806 87.096774194 5.000000000
+212.903225806 90.322580645 5.000000000
+212.903225806 93.548387097 5.000000000
+212.903225806 96.774193548 5.000000000
+212.903225806 100.000000000 5.000000000
+222.580645161 0.000000000 10.000000000
+222.580645161 3.225806452 10.000000000
+222.580645161 6.451612903 10.000000000
+222.580645161 9.677419355 10.000000000
+222.580645161 12.903225806 10.000000000
+222.580645161 16.129032258 10.000000000
+222.580645161 19.354838710 10.000000000
+222.580645161 22.580645161 10.000000000
+222.580645161 25.806451613 10.000000000
+222.580645161 29.032258065 10.000000000
+222.580645161 32.258064516 10.000000000
+222.580645161 35.483870968 9.879032258
+222.580645161 38.709677419 9.072580645
+222.580645161 41.935483871 8.266129032
+222.580645161 45.161290323 7.500000000
+222.580645161 48.387096774 7.500000000
+222.580645161 51.612903226 7.500000000
+222.580645161 54.838709677 7.500000000
+222.580645161 58.064516129 6.733870968
+222.580645161 61.290322581 5.927419355
+222.580645161 64.516129032 5.120967742
+222.580645161 67.741935484 5.000000000
+222.580645161 70.967741935 5.000000000
+222.580645161 74.193548387 5.000000000
+222.580645161 77.419354839 5.000000000
+222.580645161 80.645161290 5.000000000
+222.580645161 83.870967742 5.000000000
+222.580645161 87.096774194 5.000000000
+222.580645161 90.322580645 5.000000000
+222.580645161 93.548387097 5.000000000
+222.580645161 96.774193548 5.000000000
+222.580645161 100.000000000 5.000000000
+232.258064516 0.000000000 10.000000000
+232.258064516 3.225806452 10.000000000
+232.258064516 6.451612903 10.000000000
+232.258064516 9.677419355 10.000000000
+232.258064516 12.903225806 10.000000000
+232.258064516 16.129032258 10.000000000
+232.258064516 19.354838710 10.000000000
+232.258064516 22.580645161 10.000000000
+232.258064516 25.806451613 10.000000000
+232.258064516 29.032258065 10.000000000
+232.258064516 32.258064516 10.000000000
+232.258064516 35.483870968 9.879032258
+232.258064516 38.709677419 9.072580645
+232.258064516 41.935483871 8.266129032
+232.258064516 45.161290323 7.500000000
+232.258064516 48.387096774 7.500000000
+232.258064516 51.612903226 7.500000000
+232.258064516 54.838709677 7.500000000
+232.258064516 58.064516129 6.733870968
+232.258064516 61.290322581 5.927419355
+232.258064516 64.516129032 5.120967742
+232.258064516 67.741935484 5.000000000
+232.258064516 70.967741935 5.000000000
+232.258064516 74.193548387 5.000000000
+232.258064516 77.419354839 5.000000000
+232.258064516 80.645161290 5.000000000
+232.258064516 83.870967742 5.000000000
+232.258064516 87.096774194 5.000000000
+232.258064516 90.322580645 5.000000000
+232.258064516 93.548387097 5.000000000
+232.258064516 96.774193548 5.000000000
+232.258064516 100.000000000 5.000000000
+241.935483871 0.000000000 10.000000000
+241.935483871 3.225806452 10.000000000
+241.935483871 6.451612903 10.000000000
+241.935483871 9.677419355 10.000000000
+241.935483871 12.903225806 10.000000000
+241.935483871 16.129032258 10.000000000
+241.935483871 19.354838710 10.000000000
+241.935483871 22.580645161 10.000000000
+241.935483871 25.806451613 10.000000000
+241.935483871 29.032258065 10.000000000
+241.935483871 32.258064516 10.000000000
+241.935483871 35.483870968 9.879032258
+241.935483871 38.709677419 9.072580645
+241.935483871 41.935483871 8.266129032
+241.935483871 45.161290323 7.500000000
+241.935483871 48.387096774 7.500000000
+241.935483871 51.612903226 7.500000000
+241.935483871 54.838709677 7.500000000
+241.935483871 58.064516129 6.733870968
+241.935483871 61.290322581 5.927419355
+241.935483871 64.516129032 5.120967742
+241.935483871 67.741935484 5.000000000
+241.935483871 70.967741935 5.000000000
+241.935483871 74.193548387 5.000000000
+241.935483871 77.419354839 5.000000000
+241.935483871 80.645161290 5.000000000
+241.935483871 83.870967742 5.000000000
+241.935483871 87.096774194 5.000000000
+241.935483871 90.322580645 5.000000000
+241.935483871 93.548387097 5.000000000
+241.935483871 96.774193548 5.000000000
+241.935483871 100.000000000 5.000000000
+251.612903226 0.000000000 10.000000000
+251.612903226 3.225806452 10.000000000
+251.612903226 6.451612903 10.000000000
+251.612903226 9.677419355 10.000000000
+251.612903226 12.903225806 10.000000000
+251.612903226 16.129032258 10.000000000
+251.612903226 19.354838710 10.000000000
+251.612903226 22.580645161 10.000000000
+251.612903226 25.806451613 10.000000000
+251.612903226 29.032258065 10.000000000
+251.612903226 32.258064516 10.000000000
+251.612903226 35.483870968 9.879032258
+251.612903226 38.709677419 9.072580645
+251.612903226 41.935483871 8.266129032
+251.612903226 45.161290323 7.500000000
+251.612903226 48.387096774 7.500000000
+251.612903226 51.612903226 7.500000000
+251.612903226 54.838709677 7.500000000
+251.612903226 58.064516129 6.733870968
+251.612903226 61.290322581 5.927419355
+251.612903226 64.516129032 5.120967742
+251.612903226 67.741935484 5.000000000
+251.612903226 70.967741935 5.000000000
+251.612903226 74.193548387 5.000000000
+251.612903226 77.419354839 5.000000000
+251.612903226 80.645161290 5.000000000
+251.612903226 83.870967742 5.000000000
+251.612903226 87.096774194 5.000000000
+251.612903226 90.322580645 5.000000000
+251.612903226 93.548387097 5.000000000
+251.612903226 96.774193548 5.000000000
+251.612903226 100.000000000 5.000000000
+261.290322581 0.000000000 10.000000000
+261.290322581 3.225806452 10.000000000
+261.290322581 6.451612903 10.000000000
+261.290322581 9.677419355 10.000000000
+261.290322581 12.903225806 10.000000000
+261.290322581 16.129032258 10.000000000
+261.290322581 19.354838710 10.000000000
+261.290322581 22.580645161 10.000000000
+261.290322581 25.806451613 10.000000000
+261.290322581 29.032258065 10.000000000
+261.290322581 32.258064516 10.000000000
+261.290322581 35.483870968 9.879032258
+261.290322581 38.709677419 9.072580645
+261.290322581 41.935483871 8.266129032
+261.290322581 45.161290323 7.500000000
+261.290322581 48.387096774 7.500000000
+261.290322581 51.612903226 7.500000000
+261.290322581 54.838709677 7.500000000
+261.290322581 58.064516129 6.733870968
+261.290322581 61.290322581 5.927419355
+261.290322581 64.516129032 5.120967742
+261.290322581 67.741935484 5.000000000
+261.290322581 70.967741935 5.000000000
+261.290322581 74.193548387 5.000000000
+261.290322581 77.419354839 5.000000000
+261.290322581 80.645161290 5.000000000
+261.290322581 83.870967742 5.000000000
+261.290322581 87.096774194 5.000000000
+261.290322581 90.322580645 5.000000000
+261.290322581 93.548387097 5.000000000
+261.290322581 96.774193548 5.000000000
+261.290322581 100.000000000 5.000000000
+270.967741935 0.000000000 10.000000000
+270.967741935 3.225806452 10.000000000
+270.967741935 6.451612903 10.000000000
+270.967741935 9.677419355 10.000000000
+270.967741935 12.903225806 10.000000000
+270.967741935 16.129032258 10.000000000
+270.967741935 19.354838710 10.000000000
+270.967741935 22.580645161 10.000000000
+270.967741935 25.806451613 10.000000000
+270.967741935 29.032258065 10.000000000
+270.967741935 32.258064516 10.000000000
+270.967741935 35.483870968 9.879032258
+270.967741935 38.709677419 9.072580645
+270.967741935 41.935483871 8.266129032
+270.967741935 45.161290323 7.500000000
+270.967741935 48.387096774 7.500000000
+270.967741935 51.612903226 7.500000000
+270.967741935 54.838709677 7.500000000
+270.967741935 58.064516129 6.733870968
+270.967741935 61.290322581 5.927419355
+270.967741935 64.516129032 5.120967742
+270.967741935 67.741935484 5.000000000
+270.967741935 70.967741935 5.000000000
+270.967741935 74.193548387 5.000000000
+270.967741935 77.419354839 5.000000000
+270.967741935 80.645161290 5.000000000
+270.967741935 83.870967742 5.000000000
+270.967741935 87.096774194 5.000000000
+270.967741935 90.322580645 5.000000000
+270.967741935 93.548387097 5.000000000
+270.967741935 96.774193548 5.000000000
+270.967741935 100.000000000 5.000000000
+280.645161290 0.000000000 10.000000000
+280.645161290 3.225806452 10.000000000
+280.645161290 6.451612903 10.000000000
+280.645161290 9.677419355 10.000000000
+280.645161290 12.903225806 10.000000000
+280.645161290 16.129032258 10.000000000
+280.645161290 19.354838710 10.000000000
+280.645161290 22.580645161 10.000000000
+280.645161290 25.806451613 10.000000000
+280.645161290 29.032258065 10.000000000
+280.645161290 32.258064516 10.000000000
+280.645161290 35.483870968 9.879032258
+280.645161290 38.709677419 9.072580645
+280.645161290 41.935483871 8.266129032
+280.645161290 45.161290323 7.500000000
+280.645161290 48.387096774 7.500000000
+280.645161290 51.612903226 7.500000000
+280.645161290 54.838709677 7.500000000
+280.645161290 58.064516129 6.733870968
+280.645161290 61.290322581 5.927419355
+280.645161290 64.516129032 5.120967742
+280.645161290 67.741935484 5.000000000
+280.645161290 70.967741935 5.000000000
+280.645161290 74.193548387 5.000000000
+280.645161290 77.419354839 5.000000000
+280.645161290 80.645161290 5.000000000
+280.645161290 83.870967742 5.000000000
+280.645161290 87.096774194 5.000000000
+280.645161290 90.322580645 5.000000000
+280.645161290 93.548387097 5.000000000
+280.645161290 96.774193548 5.000000000
+280.645161290 100.000000000 5.000000000
+290.322580645 0.000000000 10.000000000
+290.322580645 3.225806452 10.000000000
+290.322580645 6.451612903 10.000000000
+290.322580645 9.677419355 10.000000000
+290.322580645 12.903225806 10.000000000
+290.322580645 16.129032258 10.000000000
+290.322580645 19.354838710 10.000000000
+290.322580645 22.580645161 10.000000000
+290.322580645 25.806451613 10.000000000
+290.322580645 29.032258065 10.000000000
+290.322580645 32.258064516 10.000000000
+290.322580645 35.483870968 9.879032258
+290.322580645 38.709677419 9.072580645
+290.322580645 41.935483871 8.266129032
+290.322580645 45.161290323 7.500000000
+290.322580645 48.387096774 7.500000000
+290.322580645 51.612903226 7.500000000
+290.322580645 54.838709677 7.500000000
+290.322580645 58.064516129 6.733870968
+290.322580645 61.290322581 5.927419355
+290.322580645 64.516129032 5.120967742
+290.322580645 67.741935484 5.000000000
+290.322580645 70.967741935 5.000000000
+290.322580645 74.193548387 5.000000000
+290.322580645 77.419354839 5.000000000
+290.322580645 80.645161290 5.000000000
+290.322580645 83.870967742 5.000000000
+290.322580645 87.096774194 5.000000000
+290.322580645 90.322580645 5.000000000
+290.322580645 93.548387097 5.000000000
+290.322580645 96.774193548 5.000000000
+290.322580645 100.000000000 5.000000000
+300.000000000 0.000000000 10.000000000
+300.000000000 3.225806452 10.000000000
+300.000000000 6.451612903 10.000000000
+300.000000000 9.677419355 10.000000000
+300.000000000 12.903225806 10.000000000
+300.000000000 16.129032258 10.000000000
+300.000000000 19.354838710 10.000000000
+300.000000000 22.580645161 10.000000000
+300.000000000 25.806451613 10.000000000
+300.000000000 29.032258065 10.000000000
+300.000000000 32.258064516 10.000000000
+300.000000000 35.483870968 9.879032258
+300.000000000 38.709677419 9.072580645
+300.000000000 41.935483871 8.266129032
+300.000000000 45.161290323 7.500000000
+300.000000000 48.387096774 7.500000000
+300.000000000 51.612903226 7.500000000
+300.000000000 54.838709677 7.500000000
+300.000000000 58.064516129 6.733870968
+300.000000000 61.290322581 5.927419355
+300.000000000 64.516129032 5.120967742
+300.000000000 67.741935484 5.000000000
+300.000000000 70.967741935 5.000000000
+300.000000000 74.193548387 5.000000000
+300.000000000 77.419354839 5.000000000
+300.000000000 80.645161290 5.000000000
+300.000000000 83.870967742 5.000000000
+300.000000000 87.096774194 5.000000000
+300.000000000 90.322580645 5.000000000
+300.000000000 93.548387097 5.000000000
+300.000000000 96.774193548 5.000000000
+300.000000000 100.000000000 5.000000000
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.fll b/examples/takagi-sugeno/octave/heart_disease_risk.fll
new file mode 100644
index 0000000..4ab822f
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.fll
@@ -0,0 +1,51 @@
+Engine: heart_disease_risk
+InputVariable: LDLLevel
+ enabled: true
+ range: 0.000 300.000
+ lock-range: false
+ term: Low Trapezoid -1.000 0.000 90.000 110.000
+ term: LowBorderline Trapezoid 90.000 110.000 120.000 140.000
+ term: Borderline Trapezoid 120.000 140.000 150.000 170.000
+ term: HighBorderline Trapezoid 150.000 170.000 180.000 200.000
+ term: High Trapezoid 180.000 200.000 300.000 301.000
+InputVariable: HDLLevel
+ enabled: true
+ range: 0.000 100.000
+ lock-range: false
+ term: LowHDL Trapezoid -1.000 0.000 35.000 45.000
+ term: ModerateHDL Trapezoid 35.000 45.000 55.000 65.000
+ term: HighHDL Trapezoid 55.000 65.000 100.000 101.000
+OutputVariable: HeartDiseaseRisk
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: NoRisk Constant 0.000
+ term: LowRisk Constant 2.500
+ term: MediumRisk Constant 5.000
+ term: HighRisk Constant 7.500
+ term: ExtremeRisk Constant 10.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if LDLLevel is Low and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is Low and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is Low and HDLLevel is HighHDL then HeartDiseaseRisk is NoRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is LowBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is Borderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is Borderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is Borderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is HighBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk
+ rule: if LDLLevel is High and HDLLevel is LowHDL then HeartDiseaseRisk is ExtremeRisk
+ rule: if LDLLevel is High and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk
+ rule: if LDLLevel is High and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk \ No newline at end of file
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.java b/examples/takagi-sugeno/octave/heart_disease_risk.java
new file mode 100644
index 0000000..febd1c7
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.java
@@ -0,0 +1,90 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class heart_disease_risk{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("heart_disease_risk");
+engine.setDescription("");
+
+InputVariable LDLLevel = new InputVariable();
+LDLLevel.setName("LDLLevel");
+LDLLevel.setDescription("");
+LDLLevel.setEnabled(true);
+LDLLevel.setRange(0.000, 300.000);
+LDLLevel.setLockValueInRange(false);
+LDLLevel.addTerm(new Trapezoid("Low", -1.000, 0.000, 90.000, 110.000));
+LDLLevel.addTerm(new Trapezoid("LowBorderline", 90.000, 110.000, 120.000, 140.000));
+LDLLevel.addTerm(new Trapezoid("Borderline", 120.000, 140.000, 150.000, 170.000));
+LDLLevel.addTerm(new Trapezoid("HighBorderline", 150.000, 170.000, 180.000, 200.000));
+LDLLevel.addTerm(new Trapezoid("High", 180.000, 200.000, 300.000, 301.000));
+engine.addInputVariable(LDLLevel);
+
+InputVariable HDLLevel = new InputVariable();
+HDLLevel.setName("HDLLevel");
+HDLLevel.setDescription("");
+HDLLevel.setEnabled(true);
+HDLLevel.setRange(0.000, 100.000);
+HDLLevel.setLockValueInRange(false);
+HDLLevel.addTerm(new Trapezoid("LowHDL", -1.000, 0.000, 35.000, 45.000));
+HDLLevel.addTerm(new Trapezoid("ModerateHDL", 35.000, 45.000, 55.000, 65.000));
+HDLLevel.addTerm(new Trapezoid("HighHDL", 55.000, 65.000, 100.000, 101.000));
+engine.addInputVariable(HDLLevel);
+
+OutputVariable HeartDiseaseRisk = new OutputVariable();
+HeartDiseaseRisk.setName("HeartDiseaseRisk");
+HeartDiseaseRisk.setDescription("");
+HeartDiseaseRisk.setEnabled(true);
+HeartDiseaseRisk.setRange(0.000, 10.000);
+HeartDiseaseRisk.setLockValueInRange(false);
+HeartDiseaseRisk.setAggregation(null);
+HeartDiseaseRisk.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+HeartDiseaseRisk.setDefaultValue(Double.NaN);
+HeartDiseaseRisk.setLockPreviousValue(false);
+HeartDiseaseRisk.addTerm(new Constant("NoRisk", 0.000));
+HeartDiseaseRisk.addTerm(new Constant("LowRisk", 2.500));
+HeartDiseaseRisk.addTerm(new Constant("MediumRisk", 5.000));
+HeartDiseaseRisk.addTerm(new Constant("HighRisk", 7.500));
+HeartDiseaseRisk.addTerm(new Constant("ExtremeRisk", 10.000));
+engine.addOutputVariable(HeartDiseaseRisk);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new Minimum());
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if LDLLevel is Low and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is Low and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is Low and HDLLevel is HighHDL then HeartDiseaseRisk is NoRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is LowBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is LowBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is LowBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is Borderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is Borderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is Borderline and HDLLevel is HighHDL then HeartDiseaseRisk is LowRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is HighBorderline and HDLLevel is LowHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is HighBorderline and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is HighBorderline and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is High and HDLLevel is LowHDL then HeartDiseaseRisk is ExtremeRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is High and HDLLevel is ModerateHDL then HeartDiseaseRisk is HighRisk", engine));
+ruleBlock.addRule(Rule.parse("if LDLLevel is High and HDLLevel is HighHDL then HeartDiseaseRisk is MediumRisk", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/octave/heart_disease_risk.pdf b/examples/takagi-sugeno/octave/heart_disease_risk.pdf
new file mode 100644
index 0000000..e712d54
--- /dev/null
+++ b/examples/takagi-sugeno/octave/heart_disease_risk.pdf
Binary files differ
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.R b/examples/takagi-sugeno/octave/linear_tip_calculator.R
new file mode 100644
index 0000000..e6a7058
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.R
@@ -0,0 +1,67 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "linear_tip_calculator"
+engine.fll = "Engine: linear_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: Tip
+ enabled: true
+ range: 10.000 20.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: TenPercent Linear 0.000 0.000 10.000
+ term: FifteenPercent Linear 0.000 0.000 15.000
+ term: TwentyPercent Linear 0.000 0.000 20.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is Bad and Service is Bad then Tip is TenPercent
+ rule: if FoodQuality is Bad and Service is Good then Tip is FifteenPercent
+ rule: if FoodQuality is Good and Service is Bad then Tip is FifteenPercent
+ rule: if FoodQuality is Good and Service is Good then Tip is TwentyPercent"
+
+engine.fldFile = "linear_tip_calculator.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(FoodQuality, Service)) +
+ geom_tile(aes(fill=Tip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=FoodQuality, y=Service, z=Tip), color="black") +
+ ggtitle("(FoodQuality, Service) = Tip")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(Service, FoodQuality)) +
+ geom_tile(aes(fill=Tip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Service, y=FoodQuality, z=Tip), color="black") +
+ ggtitle("(Service, FoodQuality) = Tip")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.cpp b/examples/takagi-sugeno/octave/linear_tip_calculator.cpp
new file mode 100644
index 0000000..f0d4a43
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.cpp
@@ -0,0 +1,62 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("linear_tip_calculator");
+engine->setDescription("");
+
+InputVariable* FoodQuality = new InputVariable;
+FoodQuality->setName("FoodQuality");
+FoodQuality->setDescription("");
+FoodQuality->setEnabled(true);
+FoodQuality->setRange(1.000, 10.000);
+FoodQuality->setLockValueInRange(false);
+FoodQuality->addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+FoodQuality->addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine->addInputVariable(FoodQuality);
+
+InputVariable* Service = new InputVariable;
+Service->setName("Service");
+Service->setDescription("");
+Service->setEnabled(true);
+Service->setRange(1.000, 10.000);
+Service->setLockValueInRange(false);
+Service->addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+Service->addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine->addInputVariable(Service);
+
+OutputVariable* Tip = new OutputVariable;
+Tip->setName("Tip");
+Tip->setDescription("");
+Tip->setEnabled(true);
+Tip->setRange(10.000, 20.000);
+Tip->setLockValueInRange(false);
+Tip->setAggregation(fl::null);
+Tip->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+Tip->setDefaultValue(fl::nan);
+Tip->setLockPreviousValue(false);
+Tip->addTerm(Linear::create("TenPercent", engine, 0.000, 0.000, 10.000));
+Tip->addTerm(Linear::create("FifteenPercent", engine, 0.000, 0.000, 15.000));
+Tip->addTerm(Linear::create("TwentyPercent", engine, 0.000, 0.000, 20.000));
+engine->addOutputVariable(Tip);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new Minimum);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if FoodQuality is Bad and Service is Bad then Tip is TenPercent", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Bad and Service is Good then Tip is FifteenPercent", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is Bad then Tip is FifteenPercent", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is Good then Tip is TwentyPercent", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.fcl b/examples/takagi-sugeno/octave/linear_tip_calculator.fcl
new file mode 100644
index 0000000..9b28c0e
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.fcl
@@ -0,0 +1,43 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK linear_tip_calculator
+
+VAR_INPUT
+ FoodQuality: REAL;
+ Service: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Tip: REAL;
+END_VAR
+
+FUZZIFY FoodQuality
+ RANGE := (1.000 .. 10.000);
+ TERM Bad := Trapezoid 0.000 1.000 3.000 7.000;
+ TERM Good := Trapezoid 3.000 7.000 10.000 11.000;
+END_FUZZIFY
+
+FUZZIFY Service
+ RANGE := (1.000 .. 10.000);
+ TERM Bad := Trapezoid 0.000 1.000 3.000 7.000;
+ TERM Good := Trapezoid 3.000 7.000 10.000 11.000;
+END_FUZZIFY
+
+DEFUZZIFY Tip
+ RANGE := (10.000 .. 20.000);
+ TERM TenPercent := Linear 0.000 0.000 10.000;
+ TERM FifteenPercent := Linear 0.000 0.000 15.000;
+ TERM TwentyPercent := Linear 0.000 0.000 20.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : MIN;
+ RULE 1 : if FoodQuality is Bad and Service is Bad then Tip is TenPercent
+ RULE 2 : if FoodQuality is Bad and Service is Good then Tip is FifteenPercent
+ RULE 3 : if FoodQuality is Good and Service is Bad then Tip is FifteenPercent
+ RULE 4 : if FoodQuality is Good and Service is Good then Tip is TwentyPercent
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.fis b/examples/takagi-sugeno/octave/linear_tip_calculator.fis
new file mode 100644
index 0000000..58b4016
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.fis
@@ -0,0 +1,42 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='linear_tip_calculator'
+Type='sugeno'
+Version=6.0
+NumInputs=2
+NumOutputs=1
+NumRules=4
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='FoodQuality'
+Range=[1.000 10.000]
+NumMFs=2
+MF1='Bad':'trapmf',[0.000 1.000 3.000 7.000]
+MF2='Good':'trapmf',[3.000 7.000 10.000 11.000]
+
+[Input2]
+Name='Service'
+Range=[1.000 10.000]
+NumMFs=2
+MF1='Bad':'trapmf',[0.000 1.000 3.000 7.000]
+MF2='Good':'trapmf',[3.000 7.000 10.000 11.000]
+
+[Output1]
+Name='Tip'
+Range=[10.000 20.000]
+NumMFs=3
+MF1='TenPercent':'linear',[0.000 0.000 10.000]
+MF2='FifteenPercent':'linear',[0.000 0.000 15.000]
+MF3='TwentyPercent':'linear',[0.000 0.000 20.000]
+
+[Rules]
+1.000 1.000 , 1.000 (1.000) : 1
+1.000 2.000 , 2.000 (1.000) : 1
+2.000 1.000 , 2.000 (1.000) : 1
+2.000 2.000 , 3.000 (1.000) : 1
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.fld b/examples/takagi-sugeno/octave/linear_tip_calculator.fld
new file mode 100644
index 0000000..60f4542
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.fld
@@ -0,0 +1,1025 @@
+FoodQuality Service Tip
+1.000000000 1.000000000 10.000000000
+1.000000000 1.290322581 10.000000000
+1.000000000 1.580645161 10.000000000
+1.000000000 1.870967742 10.000000000
+1.000000000 2.161290323 10.000000000
+1.000000000 2.451612903 10.000000000
+1.000000000 2.741935484 10.000000000
+1.000000000 3.032258065 10.040322581
+1.000000000 3.322580645 10.403225806
+1.000000000 3.612903226 10.766129032
+1.000000000 3.903225806 11.129032258
+1.000000000 4.193548387 11.491935484
+1.000000000 4.483870968 11.854838710
+1.000000000 4.774193548 12.217741935
+1.000000000 5.064516129 12.580645161
+1.000000000 5.354838710 12.943548387
+1.000000000 5.645161290 13.306451613
+1.000000000 5.935483871 13.669354839
+1.000000000 6.225806452 14.032258065
+1.000000000 6.516129032 14.395161290
+1.000000000 6.806451613 14.758064516
+1.000000000 7.096774194 15.000000000
+1.000000000 7.387096774 15.000000000
+1.000000000 7.677419355 15.000000000
+1.000000000 7.967741935 15.000000000
+1.000000000 8.258064516 15.000000000
+1.000000000 8.548387097 15.000000000
+1.000000000 8.838709677 15.000000000
+1.000000000 9.129032258 15.000000000
+1.000000000 9.419354839 15.000000000
+1.000000000 9.709677419 15.000000000
+1.000000000 10.000000000 15.000000000
+1.290322581 1.000000000 10.000000000
+1.290322581 1.290322581 10.000000000
+1.290322581 1.580645161 10.000000000
+1.290322581 1.870967742 10.000000000
+1.290322581 2.161290323 10.000000000
+1.290322581 2.451612903 10.000000000
+1.290322581 2.741935484 10.000000000
+1.290322581 3.032258065 10.040322581
+1.290322581 3.322580645 10.403225806
+1.290322581 3.612903226 10.766129032
+1.290322581 3.903225806 11.129032258
+1.290322581 4.193548387 11.491935484
+1.290322581 4.483870968 11.854838710
+1.290322581 4.774193548 12.217741935
+1.290322581 5.064516129 12.580645161
+1.290322581 5.354838710 12.943548387
+1.290322581 5.645161290 13.306451613
+1.290322581 5.935483871 13.669354839
+1.290322581 6.225806452 14.032258065
+1.290322581 6.516129032 14.395161290
+1.290322581 6.806451613 14.758064516
+1.290322581 7.096774194 15.000000000
+1.290322581 7.387096774 15.000000000
+1.290322581 7.677419355 15.000000000
+1.290322581 7.967741935 15.000000000
+1.290322581 8.258064516 15.000000000
+1.290322581 8.548387097 15.000000000
+1.290322581 8.838709677 15.000000000
+1.290322581 9.129032258 15.000000000
+1.290322581 9.419354839 15.000000000
+1.290322581 9.709677419 15.000000000
+1.290322581 10.000000000 15.000000000
+1.580645161 1.000000000 10.000000000
+1.580645161 1.290322581 10.000000000
+1.580645161 1.580645161 10.000000000
+1.580645161 1.870967742 10.000000000
+1.580645161 2.161290323 10.000000000
+1.580645161 2.451612903 10.000000000
+1.580645161 2.741935484 10.000000000
+1.580645161 3.032258065 10.040322581
+1.580645161 3.322580645 10.403225806
+1.580645161 3.612903226 10.766129032
+1.580645161 3.903225806 11.129032258
+1.580645161 4.193548387 11.491935484
+1.580645161 4.483870968 11.854838710
+1.580645161 4.774193548 12.217741935
+1.580645161 5.064516129 12.580645161
+1.580645161 5.354838710 12.943548387
+1.580645161 5.645161290 13.306451613
+1.580645161 5.935483871 13.669354839
+1.580645161 6.225806452 14.032258065
+1.580645161 6.516129032 14.395161290
+1.580645161 6.806451613 14.758064516
+1.580645161 7.096774194 15.000000000
+1.580645161 7.387096774 15.000000000
+1.580645161 7.677419355 15.000000000
+1.580645161 7.967741935 15.000000000
+1.580645161 8.258064516 15.000000000
+1.580645161 8.548387097 15.000000000
+1.580645161 8.838709677 15.000000000
+1.580645161 9.129032258 15.000000000
+1.580645161 9.419354839 15.000000000
+1.580645161 9.709677419 15.000000000
+1.580645161 10.000000000 15.000000000
+1.870967742 1.000000000 10.000000000
+1.870967742 1.290322581 10.000000000
+1.870967742 1.580645161 10.000000000
+1.870967742 1.870967742 10.000000000
+1.870967742 2.161290323 10.000000000
+1.870967742 2.451612903 10.000000000
+1.870967742 2.741935484 10.000000000
+1.870967742 3.032258065 10.040322581
+1.870967742 3.322580645 10.403225806
+1.870967742 3.612903226 10.766129032
+1.870967742 3.903225806 11.129032258
+1.870967742 4.193548387 11.491935484
+1.870967742 4.483870968 11.854838710
+1.870967742 4.774193548 12.217741935
+1.870967742 5.064516129 12.580645161
+1.870967742 5.354838710 12.943548387
+1.870967742 5.645161290 13.306451613
+1.870967742 5.935483871 13.669354839
+1.870967742 6.225806452 14.032258065
+1.870967742 6.516129032 14.395161290
+1.870967742 6.806451613 14.758064516
+1.870967742 7.096774194 15.000000000
+1.870967742 7.387096774 15.000000000
+1.870967742 7.677419355 15.000000000
+1.870967742 7.967741935 15.000000000
+1.870967742 8.258064516 15.000000000
+1.870967742 8.548387097 15.000000000
+1.870967742 8.838709677 15.000000000
+1.870967742 9.129032258 15.000000000
+1.870967742 9.419354839 15.000000000
+1.870967742 9.709677419 15.000000000
+1.870967742 10.000000000 15.000000000
+2.161290323 1.000000000 10.000000000
+2.161290323 1.290322581 10.000000000
+2.161290323 1.580645161 10.000000000
+2.161290323 1.870967742 10.000000000
+2.161290323 2.161290323 10.000000000
+2.161290323 2.451612903 10.000000000
+2.161290323 2.741935484 10.000000000
+2.161290323 3.032258065 10.040322581
+2.161290323 3.322580645 10.403225806
+2.161290323 3.612903226 10.766129032
+2.161290323 3.903225806 11.129032258
+2.161290323 4.193548387 11.491935484
+2.161290323 4.483870968 11.854838710
+2.161290323 4.774193548 12.217741935
+2.161290323 5.064516129 12.580645161
+2.161290323 5.354838710 12.943548387
+2.161290323 5.645161290 13.306451613
+2.161290323 5.935483871 13.669354839
+2.161290323 6.225806452 14.032258065
+2.161290323 6.516129032 14.395161290
+2.161290323 6.806451613 14.758064516
+2.161290323 7.096774194 15.000000000
+2.161290323 7.387096774 15.000000000
+2.161290323 7.677419355 15.000000000
+2.161290323 7.967741935 15.000000000
+2.161290323 8.258064516 15.000000000
+2.161290323 8.548387097 15.000000000
+2.161290323 8.838709677 15.000000000
+2.161290323 9.129032258 15.000000000
+2.161290323 9.419354839 15.000000000
+2.161290323 9.709677419 15.000000000
+2.161290323 10.000000000 15.000000000
+2.451612903 1.000000000 10.000000000
+2.451612903 1.290322581 10.000000000
+2.451612903 1.580645161 10.000000000
+2.451612903 1.870967742 10.000000000
+2.451612903 2.161290323 10.000000000
+2.451612903 2.451612903 10.000000000
+2.451612903 2.741935484 10.000000000
+2.451612903 3.032258065 10.040322581
+2.451612903 3.322580645 10.403225806
+2.451612903 3.612903226 10.766129032
+2.451612903 3.903225806 11.129032258
+2.451612903 4.193548387 11.491935484
+2.451612903 4.483870968 11.854838710
+2.451612903 4.774193548 12.217741935
+2.451612903 5.064516129 12.580645161
+2.451612903 5.354838710 12.943548387
+2.451612903 5.645161290 13.306451613
+2.451612903 5.935483871 13.669354839
+2.451612903 6.225806452 14.032258065
+2.451612903 6.516129032 14.395161290
+2.451612903 6.806451613 14.758064516
+2.451612903 7.096774194 15.000000000
+2.451612903 7.387096774 15.000000000
+2.451612903 7.677419355 15.000000000
+2.451612903 7.967741935 15.000000000
+2.451612903 8.258064516 15.000000000
+2.451612903 8.548387097 15.000000000
+2.451612903 8.838709677 15.000000000
+2.451612903 9.129032258 15.000000000
+2.451612903 9.419354839 15.000000000
+2.451612903 9.709677419 15.000000000
+2.451612903 10.000000000 15.000000000
+2.741935484 1.000000000 10.000000000
+2.741935484 1.290322581 10.000000000
+2.741935484 1.580645161 10.000000000
+2.741935484 1.870967742 10.000000000
+2.741935484 2.161290323 10.000000000
+2.741935484 2.451612903 10.000000000
+2.741935484 2.741935484 10.000000000
+2.741935484 3.032258065 10.040322581
+2.741935484 3.322580645 10.403225806
+2.741935484 3.612903226 10.766129032
+2.741935484 3.903225806 11.129032258
+2.741935484 4.193548387 11.491935484
+2.741935484 4.483870968 11.854838710
+2.741935484 4.774193548 12.217741935
+2.741935484 5.064516129 12.580645161
+2.741935484 5.354838710 12.943548387
+2.741935484 5.645161290 13.306451613
+2.741935484 5.935483871 13.669354839
+2.741935484 6.225806452 14.032258065
+2.741935484 6.516129032 14.395161290
+2.741935484 6.806451613 14.758064516
+2.741935484 7.096774194 15.000000000
+2.741935484 7.387096774 15.000000000
+2.741935484 7.677419355 15.000000000
+2.741935484 7.967741935 15.000000000
+2.741935484 8.258064516 15.000000000
+2.741935484 8.548387097 15.000000000
+2.741935484 8.838709677 15.000000000
+2.741935484 9.129032258 15.000000000
+2.741935484 9.419354839 15.000000000
+2.741935484 9.709677419 15.000000000
+2.741935484 10.000000000 15.000000000
+3.032258065 1.000000000 10.040322581
+3.032258065 1.290322581 10.040322581
+3.032258065 1.580645161 10.040322581
+3.032258065 1.870967742 10.040322581
+3.032258065 2.161290323 10.040322581
+3.032258065 2.451612903 10.040322581
+3.032258065 2.741935484 10.040322581
+3.032258065 3.032258065 10.158730159
+3.032258065 3.322580645 10.515873016
+3.032258065 3.612903226 10.873015873
+3.032258065 3.903225806 11.230158730
+3.032258065 4.193548387 11.587301587
+3.032258065 4.483870968 11.944444444
+3.032258065 4.774193548 12.301587302
+3.032258065 5.064516129 12.658730159
+3.032258065 5.354838710 13.015873016
+3.032258065 5.645161290 13.373015873
+3.032258065 5.935483871 13.730158730
+3.032258065 6.225806452 14.087301587
+3.032258065 6.516129032 14.444444444
+3.032258065 6.806451613 14.801587302
+3.032258065 7.096774194 15.040322581
+3.032258065 7.387096774 15.040322581
+3.032258065 7.677419355 15.040322581
+3.032258065 7.967741935 15.040322581
+3.032258065 8.258064516 15.040322581
+3.032258065 8.548387097 15.040322581
+3.032258065 8.838709677 15.040322581
+3.032258065 9.129032258 15.040322581
+3.032258065 9.419354839 15.040322581
+3.032258065 9.709677419 15.040322581
+3.032258065 10.000000000 15.040322581
+3.322580645 1.000000000 10.403225806
+3.322580645 1.290322581 10.403225806
+3.322580645 1.580645161 10.403225806
+3.322580645 1.870967742 10.403225806
+3.322580645 2.161290323 10.403225806
+3.322580645 2.451612903 10.403225806
+3.322580645 2.741935484 10.403225806
+3.322580645 3.032258065 10.515873016
+3.322580645 3.322580645 11.388888889
+3.322580645 3.612903226 11.701388889
+3.322580645 3.903225806 12.013888889
+3.322580645 4.193548387 12.326388889
+3.322580645 4.483870968 12.638888889
+3.322580645 4.774193548 12.951388889
+3.322580645 5.064516129 13.263888889
+3.322580645 5.354838710 13.576388889
+3.322580645 5.645161290 13.888888889
+3.322580645 5.935483871 14.201388889
+3.322580645 6.225806452 14.513888889
+3.322580645 6.516129032 14.826388889
+3.322580645 6.806451613 15.147058824
+3.322580645 7.096774194 15.403225806
+3.322580645 7.387096774 15.403225806
+3.322580645 7.677419355 15.403225806
+3.322580645 7.967741935 15.403225806
+3.322580645 8.258064516 15.403225806
+3.322580645 8.548387097 15.403225806
+3.322580645 8.838709677 15.403225806
+3.322580645 9.129032258 15.403225806
+3.322580645 9.419354839 15.403225806
+3.322580645 9.709677419 15.403225806
+3.322580645 10.000000000 15.403225806
+3.612903226 1.000000000 10.766129032
+3.612903226 1.290322581 10.766129032
+3.612903226 1.580645161 10.766129032
+3.612903226 1.870967742 10.766129032
+3.612903226 2.161290323 10.766129032
+3.612903226 2.451612903 10.766129032
+3.612903226 2.741935484 10.766129032
+3.612903226 3.032258065 10.873015873
+3.612903226 3.322580645 11.701388889
+3.612903226 3.612903226 12.345679012
+3.612903226 3.903225806 12.623456790
+3.612903226 4.193548387 12.901234568
+3.612903226 4.483870968 13.179012346
+3.612903226 4.774193548 13.456790123
+3.612903226 5.064516129 13.734567901
+3.612903226 5.354838710 14.012345679
+3.612903226 5.645161290 14.290123457
+3.612903226 5.935483871 14.567901235
+3.612903226 6.225806452 14.845679012
+3.612903226 6.516129032 15.129870130
+3.612903226 6.806451613 15.477941176
+3.612903226 7.096774194 15.766129032
+3.612903226 7.387096774 15.766129032
+3.612903226 7.677419355 15.766129032
+3.612903226 7.967741935 15.766129032
+3.612903226 8.258064516 15.766129032
+3.612903226 8.548387097 15.766129032
+3.612903226 8.838709677 15.766129032
+3.612903226 9.129032258 15.766129032
+3.612903226 9.419354839 15.766129032
+3.612903226 9.709677419 15.766129032
+3.612903226 10.000000000 15.766129032
+3.903225806 1.000000000 11.129032258
+3.903225806 1.290322581 11.129032258
+3.903225806 1.580645161 11.129032258
+3.903225806 1.870967742 11.129032258
+3.903225806 2.161290323 11.129032258
+3.903225806 2.451612903 11.129032258
+3.903225806 2.741935484 11.129032258
+3.903225806 3.032258065 11.230158730
+3.903225806 3.322580645 12.013888889
+3.903225806 3.612903226 12.623456790
+3.903225806 3.903225806 13.111111111
+3.903225806 4.193548387 13.361111111
+3.903225806 4.483870968 13.611111111
+3.903225806 4.774193548 13.861111111
+3.903225806 5.064516129 14.111111111
+3.903225806 5.354838710 14.361111111
+3.903225806 5.645161290 14.611111111
+3.903225806 5.935483871 14.861111111
+3.903225806 6.225806452 15.116279070
+3.903225806 6.516129032 15.422077922
+3.903225806 6.806451613 15.808823529
+3.903225806 7.096774194 16.129032258
+3.903225806 7.387096774 16.129032258
+3.903225806 7.677419355 16.129032258
+3.903225806 7.967741935 16.129032258
+3.903225806 8.258064516 16.129032258
+3.903225806 8.548387097 16.129032258
+3.903225806 8.838709677 16.129032258
+3.903225806 9.129032258 16.129032258
+3.903225806 9.419354839 16.129032258
+3.903225806 9.709677419 16.129032258
+3.903225806 10.000000000 16.129032258
+4.193548387 1.000000000 11.491935484
+4.193548387 1.290322581 11.491935484
+4.193548387 1.580645161 11.491935484
+4.193548387 1.870967742 11.491935484
+4.193548387 2.161290323 11.491935484
+4.193548387 2.451612903 11.491935484
+4.193548387 2.741935484 11.491935484
+4.193548387 3.032258065 11.587301587
+4.193548387 3.322580645 12.326388889
+4.193548387 3.612903226 12.901234568
+4.193548387 3.903225806 13.361111111
+4.193548387 4.193548387 13.737373737
+4.193548387 4.483870968 13.964646465
+4.193548387 4.774193548 14.191919192
+4.193548387 5.064516129 14.419191919
+4.193548387 5.354838710 14.646464646
+4.193548387 5.645161290 14.873737374
+4.193548387 5.935483871 15.105263158
+4.193548387 6.225806452 15.377906977
+4.193548387 6.516129032 15.714285714
+4.193548387 6.806451613 16.139705882
+4.193548387 7.096774194 16.491935484
+4.193548387 7.387096774 16.491935484
+4.193548387 7.677419355 16.491935484
+4.193548387 7.967741935 16.491935484
+4.193548387 8.258064516 16.491935484
+4.193548387 8.548387097 16.491935484
+4.193548387 8.838709677 16.491935484
+4.193548387 9.129032258 16.491935484
+4.193548387 9.419354839 16.491935484
+4.193548387 9.709677419 16.491935484
+4.193548387 10.000000000 16.491935484
+4.483870968 1.000000000 11.854838710
+4.483870968 1.290322581 11.854838710
+4.483870968 1.580645161 11.854838710
+4.483870968 1.870967742 11.854838710
+4.483870968 2.161290323 11.854838710
+4.483870968 2.451612903 11.854838710
+4.483870968 2.741935484 11.854838710
+4.483870968 3.032258065 11.944444444
+4.483870968 3.322580645 12.638888889
+4.483870968 3.612903226 13.179012346
+4.483870968 3.903225806 13.611111111
+4.483870968 4.193548387 13.964646465
+4.483870968 4.483870968 14.259259259
+4.483870968 4.774193548 14.467592593
+4.483870968 5.064516129 14.675925926
+4.483870968 5.354838710 14.884259259
+4.483870968 5.645161290 15.096153846
+4.483870968 5.935483871 15.342105263
+4.483870968 6.225806452 15.639534884
+4.483870968 6.516129032 16.006493506
+4.483870968 6.806451613 16.470588235
+4.483870968 7.096774194 16.854838710
+4.483870968 7.387096774 16.854838710
+4.483870968 7.677419355 16.854838710
+4.483870968 7.967741935 16.854838710
+4.483870968 8.258064516 16.854838710
+4.483870968 8.548387097 16.854838710
+4.483870968 8.838709677 16.854838710
+4.483870968 9.129032258 16.854838710
+4.483870968 9.419354839 16.854838710
+4.483870968 9.709677419 16.854838710
+4.483870968 10.000000000 16.854838710
+4.774193548 1.000000000 12.217741935
+4.774193548 1.290322581 12.217741935
+4.774193548 1.580645161 12.217741935
+4.774193548 1.870967742 12.217741935
+4.774193548 2.161290323 12.217741935
+4.774193548 2.451612903 12.217741935
+4.774193548 2.741935484 12.217741935
+4.774193548 3.032258065 12.301587302
+4.774193548 3.322580645 12.951388889
+4.774193548 3.612903226 13.456790123
+4.774193548 3.903225806 13.861111111
+4.774193548 4.193548387 14.191919192
+4.774193548 4.483870968 14.467592593
+4.774193548 4.774193548 14.700854701
+4.774193548 5.064516129 14.893162393
+4.774193548 5.354838710 15.088495575
+4.774193548 5.645161290 15.312500000
+4.774193548 5.935483871 15.578947368
+4.774193548 6.225806452 15.901162791
+4.774193548 6.516129032 16.298701299
+4.774193548 6.806451613 16.801470588
+4.774193548 7.096774194 17.217741935
+4.774193548 7.387096774 17.217741935
+4.774193548 7.677419355 17.217741935
+4.774193548 7.967741935 17.217741935
+4.774193548 8.258064516 17.217741935
+4.774193548 8.548387097 17.217741935
+4.774193548 8.838709677 17.217741935
+4.774193548 9.129032258 17.217741935
+4.774193548 9.419354839 17.217741935
+4.774193548 9.709677419 17.217741935
+4.774193548 10.000000000 17.217741935
+5.064516129 1.000000000 12.580645161
+5.064516129 1.290322581 12.580645161
+5.064516129 1.580645161 12.580645161
+5.064516129 1.870967742 12.580645161
+5.064516129 2.161290323 12.580645161
+5.064516129 2.451612903 12.580645161
+5.064516129 2.741935484 12.580645161
+5.064516129 3.032258065 12.658730159
+5.064516129 3.322580645 13.263888889
+5.064516129 3.612903226 13.734567901
+5.064516129 3.903225806 14.111111111
+5.064516129 4.193548387 14.419191919
+5.064516129 4.483870968 14.675925926
+5.064516129 4.774193548 14.893162393
+5.064516129 5.064516129 15.081967213
+5.064516129 5.354838710 15.287610619
+5.064516129 5.645161290 15.528846154
+5.064516129 5.935483871 15.815789474
+5.064516129 6.225806452 16.162790698
+5.064516129 6.516129032 16.590909091
+5.064516129 6.806451613 17.132352941
+5.064516129 7.096774194 17.580645161
+5.064516129 7.387096774 17.580645161
+5.064516129 7.677419355 17.580645161
+5.064516129 7.967741935 17.580645161
+5.064516129 8.258064516 17.580645161
+5.064516129 8.548387097 17.580645161
+5.064516129 8.838709677 17.580645161
+5.064516129 9.129032258 17.580645161
+5.064516129 9.419354839 17.580645161
+5.064516129 9.709677419 17.580645161
+5.064516129 10.000000000 17.580645161
+5.354838710 1.000000000 12.943548387
+5.354838710 1.290322581 12.943548387
+5.354838710 1.580645161 12.943548387
+5.354838710 1.870967742 12.943548387
+5.354838710 2.161290323 12.943548387
+5.354838710 2.451612903 12.943548387
+5.354838710 2.741935484 12.943548387
+5.354838710 3.032258065 13.015873016
+5.354838710 3.322580645 13.576388889
+5.354838710 3.612903226 14.012345679
+5.354838710 3.903225806 14.361111111
+5.354838710 4.193548387 14.646464646
+5.354838710 4.483870968 14.884259259
+5.354838710 4.774193548 15.088495575
+5.354838710 5.064516129 15.287610619
+5.354838710 5.354838710 15.486725664
+5.354838710 5.645161290 15.745192308
+5.354838710 5.935483871 16.052631579
+5.354838710 6.225806452 16.424418605
+5.354838710 6.516129032 16.883116883
+5.354838710 6.806451613 17.463235294
+5.354838710 7.096774194 17.943548387
+5.354838710 7.387096774 17.943548387
+5.354838710 7.677419355 17.943548387
+5.354838710 7.967741935 17.943548387
+5.354838710 8.258064516 17.943548387
+5.354838710 8.548387097 17.943548387
+5.354838710 8.838709677 17.943548387
+5.354838710 9.129032258 17.943548387
+5.354838710 9.419354839 17.943548387
+5.354838710 9.709677419 17.943548387
+5.354838710 10.000000000 17.943548387
+5.645161290 1.000000000 13.306451613
+5.645161290 1.290322581 13.306451613
+5.645161290 1.580645161 13.306451613
+5.645161290 1.870967742 13.306451613
+5.645161290 2.161290323 13.306451613
+5.645161290 2.451612903 13.306451613
+5.645161290 2.741935484 13.306451613
+5.645161290 3.032258065 13.373015873
+5.645161290 3.322580645 13.888888889
+5.645161290 3.612903226 14.290123457
+5.645161290 3.903225806 14.611111111
+5.645161290 4.193548387 14.873737374
+5.645161290 4.483870968 15.096153846
+5.645161290 4.774193548 15.312500000
+5.645161290 5.064516129 15.528846154
+5.645161290 5.354838710 15.745192308
+5.645161290 5.645161290 15.961538462
+5.645161290 5.935483871 16.289473684
+5.645161290 6.225806452 16.686046512
+5.645161290 6.516129032 17.175324675
+5.645161290 6.806451613 17.794117647
+5.645161290 7.096774194 18.306451613
+5.645161290 7.387096774 18.306451613
+5.645161290 7.677419355 18.306451613
+5.645161290 7.967741935 18.306451613
+5.645161290 8.258064516 18.306451613
+5.645161290 8.548387097 18.306451613
+5.645161290 8.838709677 18.306451613
+5.645161290 9.129032258 18.306451613
+5.645161290 9.419354839 18.306451613
+5.645161290 9.709677419 18.306451613
+5.645161290 10.000000000 18.306451613
+5.935483871 1.000000000 13.669354839
+5.935483871 1.290322581 13.669354839
+5.935483871 1.580645161 13.669354839
+5.935483871 1.870967742 13.669354839
+5.935483871 2.161290323 13.669354839
+5.935483871 2.451612903 13.669354839
+5.935483871 2.741935484 13.669354839
+5.935483871 3.032258065 13.730158730
+5.935483871 3.322580645 14.201388889
+5.935483871 3.612903226 14.567901235
+5.935483871 3.903225806 14.861111111
+5.935483871 4.193548387 15.105263158
+5.935483871 4.483870968 15.342105263
+5.935483871 4.774193548 15.578947368
+5.935483871 5.064516129 15.815789474
+5.935483871 5.354838710 16.052631579
+5.935483871 5.645161290 16.289473684
+5.935483871 5.935483871 16.526315789
+5.935483871 6.225806452 16.947674419
+5.935483871 6.516129032 17.467532468
+5.935483871 6.806451613 18.125000000
+5.935483871 7.096774194 18.669354839
+5.935483871 7.387096774 18.669354839
+5.935483871 7.677419355 18.669354839
+5.935483871 7.967741935 18.669354839
+5.935483871 8.258064516 18.669354839
+5.935483871 8.548387097 18.669354839
+5.935483871 8.838709677 18.669354839
+5.935483871 9.129032258 18.669354839
+5.935483871 9.419354839 18.669354839
+5.935483871 9.709677419 18.669354839
+5.935483871 10.000000000 18.669354839
+6.225806452 1.000000000 14.032258065
+6.225806452 1.290322581 14.032258065
+6.225806452 1.580645161 14.032258065
+6.225806452 1.870967742 14.032258065
+6.225806452 2.161290323 14.032258065
+6.225806452 2.451612903 14.032258065
+6.225806452 2.741935484 14.032258065
+6.225806452 3.032258065 14.087301587
+6.225806452 3.322580645 14.513888889
+6.225806452 3.612903226 14.845679012
+6.225806452 3.903225806 15.116279070
+6.225806452 4.193548387 15.377906977
+6.225806452 4.483870968 15.639534884
+6.225806452 4.774193548 15.901162791
+6.225806452 5.064516129 16.162790698
+6.225806452 5.354838710 16.424418605
+6.225806452 5.645161290 16.686046512
+6.225806452 5.935483871 16.947674419
+6.225806452 6.225806452 17.209302326
+6.225806452 6.516129032 17.759740260
+6.225806452 6.806451613 18.455882353
+6.225806452 7.096774194 19.032258065
+6.225806452 7.387096774 19.032258065
+6.225806452 7.677419355 19.032258065
+6.225806452 7.967741935 19.032258065
+6.225806452 8.258064516 19.032258065
+6.225806452 8.548387097 19.032258065
+6.225806452 8.838709677 19.032258065
+6.225806452 9.129032258 19.032258065
+6.225806452 9.419354839 19.032258065
+6.225806452 9.709677419 19.032258065
+6.225806452 10.000000000 19.032258065
+6.516129032 1.000000000 14.395161290
+6.516129032 1.290322581 14.395161290
+6.516129032 1.580645161 14.395161290
+6.516129032 1.870967742 14.395161290
+6.516129032 2.161290323 14.395161290
+6.516129032 2.451612903 14.395161290
+6.516129032 2.741935484 14.395161290
+6.516129032 3.032258065 14.444444444
+6.516129032 3.322580645 14.826388889
+6.516129032 3.612903226 15.129870130
+6.516129032 3.903225806 15.422077922
+6.516129032 4.193548387 15.714285714
+6.516129032 4.483870968 16.006493506
+6.516129032 4.774193548 16.298701299
+6.516129032 5.064516129 16.590909091
+6.516129032 5.354838710 16.883116883
+6.516129032 5.645161290 17.175324675
+6.516129032 5.935483871 17.467532468
+6.516129032 6.225806452 17.759740260
+6.516129032 6.516129032 18.051948052
+6.516129032 6.806451613 18.786764706
+6.516129032 7.096774194 19.395161290
+6.516129032 7.387096774 19.395161290
+6.516129032 7.677419355 19.395161290
+6.516129032 7.967741935 19.395161290
+6.516129032 8.258064516 19.395161290
+6.516129032 8.548387097 19.395161290
+6.516129032 8.838709677 19.395161290
+6.516129032 9.129032258 19.395161290
+6.516129032 9.419354839 19.395161290
+6.516129032 9.709677419 19.395161290
+6.516129032 10.000000000 19.395161290
+6.806451613 1.000000000 14.758064516
+6.806451613 1.290322581 14.758064516
+6.806451613 1.580645161 14.758064516
+6.806451613 1.870967742 14.758064516
+6.806451613 2.161290323 14.758064516
+6.806451613 2.451612903 14.758064516
+6.806451613 2.741935484 14.758064516
+6.806451613 3.032258065 14.801587302
+6.806451613 3.322580645 15.147058824
+6.806451613 3.612903226 15.477941176
+6.806451613 3.903225806 15.808823529
+6.806451613 4.193548387 16.139705882
+6.806451613 4.483870968 16.470588235
+6.806451613 4.774193548 16.801470588
+6.806451613 5.064516129 17.132352941
+6.806451613 5.354838710 17.463235294
+6.806451613 5.645161290 17.794117647
+6.806451613 5.935483871 18.125000000
+6.806451613 6.225806452 18.455882353
+6.806451613 6.516129032 18.786764706
+6.806451613 6.806451613 19.117647059
+6.806451613 7.096774194 19.758064516
+6.806451613 7.387096774 19.758064516
+6.806451613 7.677419355 19.758064516
+6.806451613 7.967741935 19.758064516
+6.806451613 8.258064516 19.758064516
+6.806451613 8.548387097 19.758064516
+6.806451613 8.838709677 19.758064516
+6.806451613 9.129032258 19.758064516
+6.806451613 9.419354839 19.758064516
+6.806451613 9.709677419 19.758064516
+6.806451613 10.000000000 19.758064516
+7.096774194 1.000000000 15.000000000
+7.096774194 1.290322581 15.000000000
+7.096774194 1.580645161 15.000000000
+7.096774194 1.870967742 15.000000000
+7.096774194 2.161290323 15.000000000
+7.096774194 2.451612903 15.000000000
+7.096774194 2.741935484 15.000000000
+7.096774194 3.032258065 15.040322581
+7.096774194 3.322580645 15.403225806
+7.096774194 3.612903226 15.766129032
+7.096774194 3.903225806 16.129032258
+7.096774194 4.193548387 16.491935484
+7.096774194 4.483870968 16.854838710
+7.096774194 4.774193548 17.217741935
+7.096774194 5.064516129 17.580645161
+7.096774194 5.354838710 17.943548387
+7.096774194 5.645161290 18.306451613
+7.096774194 5.935483871 18.669354839
+7.096774194 6.225806452 19.032258065
+7.096774194 6.516129032 19.395161290
+7.096774194 6.806451613 19.758064516
+7.096774194 7.096774194 20.000000000
+7.096774194 7.387096774 20.000000000
+7.096774194 7.677419355 20.000000000
+7.096774194 7.967741935 20.000000000
+7.096774194 8.258064516 20.000000000
+7.096774194 8.548387097 20.000000000
+7.096774194 8.838709677 20.000000000
+7.096774194 9.129032258 20.000000000
+7.096774194 9.419354839 20.000000000
+7.096774194 9.709677419 20.000000000
+7.096774194 10.000000000 20.000000000
+7.387096774 1.000000000 15.000000000
+7.387096774 1.290322581 15.000000000
+7.387096774 1.580645161 15.000000000
+7.387096774 1.870967742 15.000000000
+7.387096774 2.161290323 15.000000000
+7.387096774 2.451612903 15.000000000
+7.387096774 2.741935484 15.000000000
+7.387096774 3.032258065 15.040322581
+7.387096774 3.322580645 15.403225806
+7.387096774 3.612903226 15.766129032
+7.387096774 3.903225806 16.129032258
+7.387096774 4.193548387 16.491935484
+7.387096774 4.483870968 16.854838710
+7.387096774 4.774193548 17.217741935
+7.387096774 5.064516129 17.580645161
+7.387096774 5.354838710 17.943548387
+7.387096774 5.645161290 18.306451613
+7.387096774 5.935483871 18.669354839
+7.387096774 6.225806452 19.032258065
+7.387096774 6.516129032 19.395161290
+7.387096774 6.806451613 19.758064516
+7.387096774 7.096774194 20.000000000
+7.387096774 7.387096774 20.000000000
+7.387096774 7.677419355 20.000000000
+7.387096774 7.967741935 20.000000000
+7.387096774 8.258064516 20.000000000
+7.387096774 8.548387097 20.000000000
+7.387096774 8.838709677 20.000000000
+7.387096774 9.129032258 20.000000000
+7.387096774 9.419354839 20.000000000
+7.387096774 9.709677419 20.000000000
+7.387096774 10.000000000 20.000000000
+7.677419355 1.000000000 15.000000000
+7.677419355 1.290322581 15.000000000
+7.677419355 1.580645161 15.000000000
+7.677419355 1.870967742 15.000000000
+7.677419355 2.161290323 15.000000000
+7.677419355 2.451612903 15.000000000
+7.677419355 2.741935484 15.000000000
+7.677419355 3.032258065 15.040322581
+7.677419355 3.322580645 15.403225806
+7.677419355 3.612903226 15.766129032
+7.677419355 3.903225806 16.129032258
+7.677419355 4.193548387 16.491935484
+7.677419355 4.483870968 16.854838710
+7.677419355 4.774193548 17.217741935
+7.677419355 5.064516129 17.580645161
+7.677419355 5.354838710 17.943548387
+7.677419355 5.645161290 18.306451613
+7.677419355 5.935483871 18.669354839
+7.677419355 6.225806452 19.032258065
+7.677419355 6.516129032 19.395161290
+7.677419355 6.806451613 19.758064516
+7.677419355 7.096774194 20.000000000
+7.677419355 7.387096774 20.000000000
+7.677419355 7.677419355 20.000000000
+7.677419355 7.967741935 20.000000000
+7.677419355 8.258064516 20.000000000
+7.677419355 8.548387097 20.000000000
+7.677419355 8.838709677 20.000000000
+7.677419355 9.129032258 20.000000000
+7.677419355 9.419354839 20.000000000
+7.677419355 9.709677419 20.000000000
+7.677419355 10.000000000 20.000000000
+7.967741935 1.000000000 15.000000000
+7.967741935 1.290322581 15.000000000
+7.967741935 1.580645161 15.000000000
+7.967741935 1.870967742 15.000000000
+7.967741935 2.161290323 15.000000000
+7.967741935 2.451612903 15.000000000
+7.967741935 2.741935484 15.000000000
+7.967741935 3.032258065 15.040322581
+7.967741935 3.322580645 15.403225806
+7.967741935 3.612903226 15.766129032
+7.967741935 3.903225806 16.129032258
+7.967741935 4.193548387 16.491935484
+7.967741935 4.483870968 16.854838710
+7.967741935 4.774193548 17.217741935
+7.967741935 5.064516129 17.580645161
+7.967741935 5.354838710 17.943548387
+7.967741935 5.645161290 18.306451613
+7.967741935 5.935483871 18.669354839
+7.967741935 6.225806452 19.032258065
+7.967741935 6.516129032 19.395161290
+7.967741935 6.806451613 19.758064516
+7.967741935 7.096774194 20.000000000
+7.967741935 7.387096774 20.000000000
+7.967741935 7.677419355 20.000000000
+7.967741935 7.967741935 20.000000000
+7.967741935 8.258064516 20.000000000
+7.967741935 8.548387097 20.000000000
+7.967741935 8.838709677 20.000000000
+7.967741935 9.129032258 20.000000000
+7.967741935 9.419354839 20.000000000
+7.967741935 9.709677419 20.000000000
+7.967741935 10.000000000 20.000000000
+8.258064516 1.000000000 15.000000000
+8.258064516 1.290322581 15.000000000
+8.258064516 1.580645161 15.000000000
+8.258064516 1.870967742 15.000000000
+8.258064516 2.161290323 15.000000000
+8.258064516 2.451612903 15.000000000
+8.258064516 2.741935484 15.000000000
+8.258064516 3.032258065 15.040322581
+8.258064516 3.322580645 15.403225806
+8.258064516 3.612903226 15.766129032
+8.258064516 3.903225806 16.129032258
+8.258064516 4.193548387 16.491935484
+8.258064516 4.483870968 16.854838710
+8.258064516 4.774193548 17.217741935
+8.258064516 5.064516129 17.580645161
+8.258064516 5.354838710 17.943548387
+8.258064516 5.645161290 18.306451613
+8.258064516 5.935483871 18.669354839
+8.258064516 6.225806452 19.032258065
+8.258064516 6.516129032 19.395161290
+8.258064516 6.806451613 19.758064516
+8.258064516 7.096774194 20.000000000
+8.258064516 7.387096774 20.000000000
+8.258064516 7.677419355 20.000000000
+8.258064516 7.967741935 20.000000000
+8.258064516 8.258064516 20.000000000
+8.258064516 8.548387097 20.000000000
+8.258064516 8.838709677 20.000000000
+8.258064516 9.129032258 20.000000000
+8.258064516 9.419354839 20.000000000
+8.258064516 9.709677419 20.000000000
+8.258064516 10.000000000 20.000000000
+8.548387097 1.000000000 15.000000000
+8.548387097 1.290322581 15.000000000
+8.548387097 1.580645161 15.000000000
+8.548387097 1.870967742 15.000000000
+8.548387097 2.161290323 15.000000000
+8.548387097 2.451612903 15.000000000
+8.548387097 2.741935484 15.000000000
+8.548387097 3.032258065 15.040322581
+8.548387097 3.322580645 15.403225806
+8.548387097 3.612903226 15.766129032
+8.548387097 3.903225806 16.129032258
+8.548387097 4.193548387 16.491935484
+8.548387097 4.483870968 16.854838710
+8.548387097 4.774193548 17.217741935
+8.548387097 5.064516129 17.580645161
+8.548387097 5.354838710 17.943548387
+8.548387097 5.645161290 18.306451613
+8.548387097 5.935483871 18.669354839
+8.548387097 6.225806452 19.032258065
+8.548387097 6.516129032 19.395161290
+8.548387097 6.806451613 19.758064516
+8.548387097 7.096774194 20.000000000
+8.548387097 7.387096774 20.000000000
+8.548387097 7.677419355 20.000000000
+8.548387097 7.967741935 20.000000000
+8.548387097 8.258064516 20.000000000
+8.548387097 8.548387097 20.000000000
+8.548387097 8.838709677 20.000000000
+8.548387097 9.129032258 20.000000000
+8.548387097 9.419354839 20.000000000
+8.548387097 9.709677419 20.000000000
+8.548387097 10.000000000 20.000000000
+8.838709677 1.000000000 15.000000000
+8.838709677 1.290322581 15.000000000
+8.838709677 1.580645161 15.000000000
+8.838709677 1.870967742 15.000000000
+8.838709677 2.161290323 15.000000000
+8.838709677 2.451612903 15.000000000
+8.838709677 2.741935484 15.000000000
+8.838709677 3.032258065 15.040322581
+8.838709677 3.322580645 15.403225806
+8.838709677 3.612903226 15.766129032
+8.838709677 3.903225806 16.129032258
+8.838709677 4.193548387 16.491935484
+8.838709677 4.483870968 16.854838710
+8.838709677 4.774193548 17.217741935
+8.838709677 5.064516129 17.580645161
+8.838709677 5.354838710 17.943548387
+8.838709677 5.645161290 18.306451613
+8.838709677 5.935483871 18.669354839
+8.838709677 6.225806452 19.032258065
+8.838709677 6.516129032 19.395161290
+8.838709677 6.806451613 19.758064516
+8.838709677 7.096774194 20.000000000
+8.838709677 7.387096774 20.000000000
+8.838709677 7.677419355 20.000000000
+8.838709677 7.967741935 20.000000000
+8.838709677 8.258064516 20.000000000
+8.838709677 8.548387097 20.000000000
+8.838709677 8.838709677 20.000000000
+8.838709677 9.129032258 20.000000000
+8.838709677 9.419354839 20.000000000
+8.838709677 9.709677419 20.000000000
+8.838709677 10.000000000 20.000000000
+9.129032258 1.000000000 15.000000000
+9.129032258 1.290322581 15.000000000
+9.129032258 1.580645161 15.000000000
+9.129032258 1.870967742 15.000000000
+9.129032258 2.161290323 15.000000000
+9.129032258 2.451612903 15.000000000
+9.129032258 2.741935484 15.000000000
+9.129032258 3.032258065 15.040322581
+9.129032258 3.322580645 15.403225806
+9.129032258 3.612903226 15.766129032
+9.129032258 3.903225806 16.129032258
+9.129032258 4.193548387 16.491935484
+9.129032258 4.483870968 16.854838710
+9.129032258 4.774193548 17.217741935
+9.129032258 5.064516129 17.580645161
+9.129032258 5.354838710 17.943548387
+9.129032258 5.645161290 18.306451613
+9.129032258 5.935483871 18.669354839
+9.129032258 6.225806452 19.032258065
+9.129032258 6.516129032 19.395161290
+9.129032258 6.806451613 19.758064516
+9.129032258 7.096774194 20.000000000
+9.129032258 7.387096774 20.000000000
+9.129032258 7.677419355 20.000000000
+9.129032258 7.967741935 20.000000000
+9.129032258 8.258064516 20.000000000
+9.129032258 8.548387097 20.000000000
+9.129032258 8.838709677 20.000000000
+9.129032258 9.129032258 20.000000000
+9.129032258 9.419354839 20.000000000
+9.129032258 9.709677419 20.000000000
+9.129032258 10.000000000 20.000000000
+9.419354839 1.000000000 15.000000000
+9.419354839 1.290322581 15.000000000
+9.419354839 1.580645161 15.000000000
+9.419354839 1.870967742 15.000000000
+9.419354839 2.161290323 15.000000000
+9.419354839 2.451612903 15.000000000
+9.419354839 2.741935484 15.000000000
+9.419354839 3.032258065 15.040322581
+9.419354839 3.322580645 15.403225806
+9.419354839 3.612903226 15.766129032
+9.419354839 3.903225806 16.129032258
+9.419354839 4.193548387 16.491935484
+9.419354839 4.483870968 16.854838710
+9.419354839 4.774193548 17.217741935
+9.419354839 5.064516129 17.580645161
+9.419354839 5.354838710 17.943548387
+9.419354839 5.645161290 18.306451613
+9.419354839 5.935483871 18.669354839
+9.419354839 6.225806452 19.032258065
+9.419354839 6.516129032 19.395161290
+9.419354839 6.806451613 19.758064516
+9.419354839 7.096774194 20.000000000
+9.419354839 7.387096774 20.000000000
+9.419354839 7.677419355 20.000000000
+9.419354839 7.967741935 20.000000000
+9.419354839 8.258064516 20.000000000
+9.419354839 8.548387097 20.000000000
+9.419354839 8.838709677 20.000000000
+9.419354839 9.129032258 20.000000000
+9.419354839 9.419354839 20.000000000
+9.419354839 9.709677419 20.000000000
+9.419354839 10.000000000 20.000000000
+9.709677419 1.000000000 15.000000000
+9.709677419 1.290322581 15.000000000
+9.709677419 1.580645161 15.000000000
+9.709677419 1.870967742 15.000000000
+9.709677419 2.161290323 15.000000000
+9.709677419 2.451612903 15.000000000
+9.709677419 2.741935484 15.000000000
+9.709677419 3.032258065 15.040322581
+9.709677419 3.322580645 15.403225806
+9.709677419 3.612903226 15.766129032
+9.709677419 3.903225806 16.129032258
+9.709677419 4.193548387 16.491935484
+9.709677419 4.483870968 16.854838710
+9.709677419 4.774193548 17.217741935
+9.709677419 5.064516129 17.580645161
+9.709677419 5.354838710 17.943548387
+9.709677419 5.645161290 18.306451613
+9.709677419 5.935483871 18.669354839
+9.709677419 6.225806452 19.032258065
+9.709677419 6.516129032 19.395161290
+9.709677419 6.806451613 19.758064516
+9.709677419 7.096774194 20.000000000
+9.709677419 7.387096774 20.000000000
+9.709677419 7.677419355 20.000000000
+9.709677419 7.967741935 20.000000000
+9.709677419 8.258064516 20.000000000
+9.709677419 8.548387097 20.000000000
+9.709677419 8.838709677 20.000000000
+9.709677419 9.129032258 20.000000000
+9.709677419 9.419354839 20.000000000
+9.709677419 9.709677419 20.000000000
+9.709677419 10.000000000 20.000000000
+10.000000000 1.000000000 15.000000000
+10.000000000 1.290322581 15.000000000
+10.000000000 1.580645161 15.000000000
+10.000000000 1.870967742 15.000000000
+10.000000000 2.161290323 15.000000000
+10.000000000 2.451612903 15.000000000
+10.000000000 2.741935484 15.000000000
+10.000000000 3.032258065 15.040322581
+10.000000000 3.322580645 15.403225806
+10.000000000 3.612903226 15.766129032
+10.000000000 3.903225806 16.129032258
+10.000000000 4.193548387 16.491935484
+10.000000000 4.483870968 16.854838710
+10.000000000 4.774193548 17.217741935
+10.000000000 5.064516129 17.580645161
+10.000000000 5.354838710 17.943548387
+10.000000000 5.645161290 18.306451613
+10.000000000 5.935483871 18.669354839
+10.000000000 6.225806452 19.032258065
+10.000000000 6.516129032 19.395161290
+10.000000000 6.806451613 19.758064516
+10.000000000 7.096774194 20.000000000
+10.000000000 7.387096774 20.000000000
+10.000000000 7.677419355 20.000000000
+10.000000000 7.967741935 20.000000000
+10.000000000 8.258064516 20.000000000
+10.000000000 8.548387097 20.000000000
+10.000000000 8.838709677 20.000000000
+10.000000000 9.129032258 20.000000000
+10.000000000 9.419354839 20.000000000
+10.000000000 9.709677419 20.000000000
+10.000000000 10.000000000 20.000000000
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.fll b/examples/takagi-sugeno/octave/linear_tip_calculator.fll
new file mode 100644
index 0000000..510d8a4
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.fll
@@ -0,0 +1,34 @@
+Engine: linear_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: Tip
+ enabled: true
+ range: 10.000 20.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: TenPercent Linear 0.000 0.000 10.000
+ term: FifteenPercent Linear 0.000 0.000 15.000
+ term: TwentyPercent Linear 0.000 0.000 20.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is Bad and Service is Bad then Tip is TenPercent
+ rule: if FoodQuality is Bad and Service is Good then Tip is FifteenPercent
+ rule: if FoodQuality is Good and Service is Bad then Tip is FifteenPercent
+ rule: if FoodQuality is Good and Service is Good then Tip is TwentyPercent \ No newline at end of file
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.java b/examples/takagi-sugeno/octave/linear_tip_calculator.java
new file mode 100644
index 0000000..7046734
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.java
@@ -0,0 +1,73 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class linear_tip_calculator{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("linear_tip_calculator");
+engine.setDescription("");
+
+InputVariable FoodQuality = new InputVariable();
+FoodQuality.setName("FoodQuality");
+FoodQuality.setDescription("");
+FoodQuality.setEnabled(true);
+FoodQuality.setRange(1.000, 10.000);
+FoodQuality.setLockValueInRange(false);
+FoodQuality.addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+FoodQuality.addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine.addInputVariable(FoodQuality);
+
+InputVariable Service = new InputVariable();
+Service.setName("Service");
+Service.setDescription("");
+Service.setEnabled(true);
+Service.setRange(1.000, 10.000);
+Service.setLockValueInRange(false);
+Service.addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+Service.addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine.addInputVariable(Service);
+
+OutputVariable Tip = new OutputVariable();
+Tip.setName("Tip");
+Tip.setDescription("");
+Tip.setEnabled(true);
+Tip.setRange(10.000, 20.000);
+Tip.setLockValueInRange(false);
+Tip.setAggregation(null);
+Tip.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+Tip.setDefaultValue(Double.NaN);
+Tip.setLockPreviousValue(false);
+Tip.addTerm(Linear.create("TenPercent", engine, 0.000, 0.000, 10.000));
+Tip.addTerm(Linear.create("FifteenPercent", engine, 0.000, 0.000, 15.000));
+Tip.addTerm(Linear.create("TwentyPercent", engine, 0.000, 0.000, 20.000));
+engine.addOutputVariable(Tip);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new Minimum());
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if FoodQuality is Bad and Service is Bad then Tip is TenPercent", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Bad and Service is Good then Tip is FifteenPercent", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is Bad then Tip is FifteenPercent", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is Good then Tip is TwentyPercent", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/octave/linear_tip_calculator.pdf b/examples/takagi-sugeno/octave/linear_tip_calculator.pdf
new file mode 100644
index 0000000..357f529
--- /dev/null
+++ b/examples/takagi-sugeno/octave/linear_tip_calculator.pdf
Binary files differ
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.R b/examples/takagi-sugeno/octave/sugeno_tip_calculator.R
new file mode 100644
index 0000000..1491a96
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.R
@@ -0,0 +1,119 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "sugeno_tip_calculator"
+engine.fll = "Engine: sugeno_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: CheapTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: AverageTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: GenerousTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low
+ rule: if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High"
+
+engine.fldFile = "sugeno_tip_calculator.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1i2_o1 = ggplot(engine.df, aes(FoodQuality, Service)) +
+ geom_tile(aes(fill=CheapTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=FoodQuality, y=Service, z=CheapTip), color="black") +
+ ggtitle("(FoodQuality, Service) = CheapTip")
+
+engine.plot.i2i1_o1 = ggplot(engine.df, aes(Service, FoodQuality)) +
+ geom_tile(aes(fill=CheapTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Service, y=FoodQuality, z=CheapTip), color="black") +
+ ggtitle("(Service, FoodQuality) = CheapTip")
+
+engine.plot.i1i2_o2 = ggplot(engine.df, aes(FoodQuality, Service)) +
+ geom_tile(aes(fill=AverageTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=FoodQuality, y=Service, z=AverageTip), color="black") +
+ ggtitle("(FoodQuality, Service) = AverageTip")
+
+engine.plot.i2i1_o2 = ggplot(engine.df, aes(Service, FoodQuality)) +
+ geom_tile(aes(fill=AverageTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Service, y=FoodQuality, z=AverageTip), color="black") +
+ ggtitle("(Service, FoodQuality) = AverageTip")
+
+engine.plot.i1i2_o3 = ggplot(engine.df, aes(FoodQuality, Service)) +
+ geom_tile(aes(fill=GenerousTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=FoodQuality, y=Service, z=GenerousTip), color="black") +
+ ggtitle("(FoodQuality, Service) = GenerousTip")
+
+engine.plot.i2i1_o3 = ggplot(engine.df, aes(Service, FoodQuality)) +
+ geom_tile(aes(fill=GenerousTip)) +
+ scale_fill_gradient(low="yellow", high="red") +
+ stat_contour(aes(x=Service, y=FoodQuality, z=GenerousTip), color="black") +
+ ggtitle("(Service, FoodQuality) = GenerousTip")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1i2_o1, engine.plot.i2i1_o1, engine.plot.i1i2_o2, engine.plot.i2i1_o2, engine.plot.i1i2_o3, engine.plot.i2i1_o3, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.cpp b/examples/takagi-sugeno/octave/sugeno_tip_calculator.cpp
new file mode 100644
index 0000000..96536fa
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.cpp
@@ -0,0 +1,98 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("sugeno_tip_calculator");
+engine->setDescription("");
+
+InputVariable* FoodQuality = new InputVariable;
+FoodQuality->setName("FoodQuality");
+FoodQuality->setDescription("");
+FoodQuality->setEnabled(true);
+FoodQuality->setRange(1.000, 10.000);
+FoodQuality->setLockValueInRange(false);
+FoodQuality->addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+FoodQuality->addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine->addInputVariable(FoodQuality);
+
+InputVariable* Service = new InputVariable;
+Service->setName("Service");
+Service->setDescription("");
+Service->setEnabled(true);
+Service->setRange(1.000, 10.000);
+Service->setLockValueInRange(false);
+Service->addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+Service->addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine->addInputVariable(Service);
+
+OutputVariable* CheapTip = new OutputVariable;
+CheapTip->setName("CheapTip");
+CheapTip->setDescription("");
+CheapTip->setEnabled(true);
+CheapTip->setRange(5.000, 25.000);
+CheapTip->setLockValueInRange(false);
+CheapTip->setAggregation(fl::null);
+CheapTip->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+CheapTip->setDefaultValue(fl::nan);
+CheapTip->setLockPreviousValue(false);
+CheapTip->addTerm(new Constant("Low", 10.000));
+CheapTip->addTerm(new Constant("Medium", 15.000));
+CheapTip->addTerm(new Constant("High", 20.000));
+engine->addOutputVariable(CheapTip);
+
+OutputVariable* AverageTip = new OutputVariable;
+AverageTip->setName("AverageTip");
+AverageTip->setDescription("");
+AverageTip->setEnabled(true);
+AverageTip->setRange(5.000, 25.000);
+AverageTip->setLockValueInRange(false);
+AverageTip->setAggregation(fl::null);
+AverageTip->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+AverageTip->setDefaultValue(fl::nan);
+AverageTip->setLockPreviousValue(false);
+AverageTip->addTerm(new Constant("Low", 10.000));
+AverageTip->addTerm(new Constant("Medium", 15.000));
+AverageTip->addTerm(new Constant("High", 20.000));
+engine->addOutputVariable(AverageTip);
+
+OutputVariable* GenerousTip = new OutputVariable;
+GenerousTip->setName("GenerousTip");
+GenerousTip->setDescription("");
+GenerousTip->setEnabled(true);
+GenerousTip->setRange(5.000, 25.000);
+GenerousTip->setLockValueInRange(false);
+GenerousTip->setAggregation(fl::null);
+GenerousTip->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+GenerousTip->setDefaultValue(fl::nan);
+GenerousTip->setLockPreviousValue(false);
+GenerousTip->addTerm(new Constant("Low", 10.000));
+GenerousTip->addTerm(new Constant("Medium", 15.000));
+GenerousTip->addTerm(new Constant("High", 20.000));
+engine->addOutputVariable(GenerousTip);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(new EinsteinProduct);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock->addRule(Rule::parse("if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.fcl b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fcl
new file mode 100644
index 0000000..fcb857c
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fcl
@@ -0,0 +1,69 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK sugeno_tip_calculator
+
+VAR_INPUT
+ FoodQuality: REAL;
+ Service: REAL;
+END_VAR
+
+VAR_OUTPUT
+ CheapTip: REAL;
+ AverageTip: REAL;
+ GenerousTip: REAL;
+END_VAR
+
+FUZZIFY FoodQuality
+ RANGE := (1.000 .. 10.000);
+ TERM Bad := Trapezoid 0.000 1.000 3.000 7.000;
+ TERM Good := Trapezoid 3.000 7.000 10.000 11.000;
+END_FUZZIFY
+
+FUZZIFY Service
+ RANGE := (1.000 .. 10.000);
+ TERM Bad := Trapezoid 0.000 1.000 3.000 7.000;
+ TERM Good := Trapezoid 3.000 7.000 10.000 11.000;
+END_FUZZIFY
+
+DEFUZZIFY CheapTip
+ RANGE := (5.000 .. 25.000);
+ TERM Low := 10.000;
+ TERM Medium := 15.000;
+ TERM High := 20.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY AverageTip
+ RANGE := (5.000 .. 25.000);
+ TERM Low := 10.000;
+ TERM Medium := 15.000;
+ TERM High := 20.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY GenerousTip
+ RANGE := (5.000 .. 25.000);
+ TERM Low := 10.000;
+ TERM Medium := 15.000;
+ TERM High := 20.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ AND : EPROD;
+ RULE 1 : if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low
+ RULE 2 : if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ RULE 3 : if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ RULE 4 : if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ RULE 5 : if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ RULE 6 : if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High
+ RULE 7 : if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ RULE 8 : if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High
+ RULE 9 : if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ RULE 10 : if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.fis b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fis
new file mode 100644
index 0000000..3d28f10
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fis
@@ -0,0 +1,64 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='sugeno_tip_calculator'
+Type='sugeno'
+Version=6.0
+NumInputs=2
+NumOutputs=3
+NumRules=10
+AndMethod='einstein_product'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='FoodQuality'
+Range=[1.000 10.000]
+NumMFs=2
+MF1='Bad':'trapmf',[0.000 1.000 3.000 7.000]
+MF2='Good':'trapmf',[3.000 7.000 10.000 11.000]
+
+[Input2]
+Name='Service'
+Range=[1.000 10.000]
+NumMFs=2
+MF1='Bad':'trapmf',[0.000 1.000 3.000 7.000]
+MF2='Good':'trapmf',[3.000 7.000 10.000 11.000]
+
+[Output1]
+Name='CheapTip'
+Range=[5.000 25.000]
+NumMFs=3
+MF1='Low':'constant',[10.000]
+MF2='Medium':'constant',[15.000]
+MF3='High':'constant',[20.000]
+
+[Output2]
+Name='AverageTip'
+Range=[5.000 25.000]
+NumMFs=3
+MF1='Low':'constant',[10.000]
+MF2='Medium':'constant',[15.000]
+MF3='High':'constant',[20.000]
+
+[Output3]
+Name='GenerousTip'
+Range=[5.000 25.000]
+NumMFs=3
+MF1='Low':'constant',[10.000]
+MF2='Medium':'constant',[15.000]
+MF3='High':'constant',[20.000]
+
+[Rules]
+1.300 1.300 , 1.300 1.200 1.000 (1.000) : 1
+2.000 1.300 , 1.000 1.000 2.000 (1.000) : 1
+2.200 1.200 , 1.000 2.000 3.000 (1.000) : 1
+1.000 1.000 , 1.000 1.000 2.000 (1.000) : 1
+2.000 1.000 , 1.000 2.000 3.000 (1.000) : 1
+2.300 1.000 , 1.000 2.000 3.200 (1.000) : 1
+1.000 2.000 , 1.000 2.000 3.000 (1.000) : 1
+2.000 2.000 , 2.000 2.000 3.200 (1.000) : 1
+1.200 2.200 , 1.000 2.000 3.000 (1.000) : 1
+2.400 2.400 , 3.000 3.200 3.300 (1.000) : 1
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.fld b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fld
new file mode 100644
index 0000000..ce942fd
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fld
@@ -0,0 +1,1025 @@
+FoodQuality Service CheapTip AverageTip GenerousTip
+1.000000000 1.000000000 10.000000000 10.000000000 12.500000000
+1.000000000 1.290322581 10.000000000 10.000000000 12.500000000
+1.000000000 1.580645161 10.000000000 10.000000000 12.500000000
+1.000000000 1.870967742 10.000000000 10.000000000 12.500000000
+1.000000000 2.161290323 10.000000000 10.000000000 12.500000000
+1.000000000 2.451612903 10.000000000 10.000000000 12.500000000
+1.000000000 2.741935484 10.000000000 10.000000000 12.500000000
+1.000000000 3.032258065 10.000000000 10.020323221 12.520404599
+1.000000000 3.322580645 10.000000000 10.217239082 12.726188365
+1.000000000 3.612903226 10.000000000 10.438541426 12.978595315
+1.000000000 3.903225806 10.000000000 10.688605148 13.303233716
+1.000000000 4.193548387 10.000000000 10.985194151 13.754553905
+1.000000000 4.483870968 10.000000000 11.368962007 14.431095437
+1.000000000 4.774193548 10.000000000 11.913195856 15.489093970
+1.000000000 5.064516129 10.000000000 12.682234786 17.023032304
+1.000000000 5.354838710 10.000000000 13.342744072 18.155449447
+1.000000000 5.645161290 10.000000000 13.792466240 18.754193916
+1.000000000 5.935483871 10.000000000 14.130816184 19.125588403
+1.000000000 6.225806452 10.000000000 14.413282130 19.412900315
+1.000000000 6.516129032 10.000000000 14.658795531 19.658787254
+1.000000000 6.806451613 10.000000000 14.873037538 19.873037533
+1.000000000 7.096774194 10.000000000 15.000000000 20.000000000
+1.000000000 7.387096774 10.000000000 15.000000000 20.000000000
+1.000000000 7.677419355 10.000000000 15.000000000 20.000000000
+1.000000000 7.967741935 10.000000000 15.000000000 20.000000000
+1.000000000 8.258064516 10.000000000 15.000000000 20.000000000
+1.000000000 8.548387097 10.000000000 15.000000000 20.000000000
+1.000000000 8.838709677 10.000000000 15.000000000 20.000000000
+1.000000000 9.129032258 10.000000000 15.000000000 20.000000000
+1.000000000 9.419354839 10.000000000 15.000000000 20.000000000
+1.000000000 9.709677419 10.000000000 15.000000000 20.000000000
+1.000000000 10.000000000 10.000000000 15.000000000 20.000000000
+1.290322581 1.000000000 10.000000000 10.000000000 12.500000000
+1.290322581 1.290322581 10.000000000 10.000000000 12.500000000
+1.290322581 1.580645161 10.000000000 10.000000000 12.500000000
+1.290322581 1.870967742 10.000000000 10.000000000 12.500000000
+1.290322581 2.161290323 10.000000000 10.000000000 12.500000000
+1.290322581 2.451612903 10.000000000 10.000000000 12.500000000
+1.290322581 2.741935484 10.000000000 10.000000000 12.500000000
+1.290322581 3.032258065 10.000000000 10.020323221 12.520404599
+1.290322581 3.322580645 10.000000000 10.217239082 12.726188365
+1.290322581 3.612903226 10.000000000 10.438541426 12.978595315
+1.290322581 3.903225806 10.000000000 10.688605148 13.303233716
+1.290322581 4.193548387 10.000000000 10.985194151 13.754553905
+1.290322581 4.483870968 10.000000000 11.368962007 14.431095437
+1.290322581 4.774193548 10.000000000 11.913195856 15.489093970
+1.290322581 5.064516129 10.000000000 12.682234786 17.023032304
+1.290322581 5.354838710 10.000000000 13.342744072 18.155449447
+1.290322581 5.645161290 10.000000000 13.792466240 18.754193916
+1.290322581 5.935483871 10.000000000 14.130816184 19.125588403
+1.290322581 6.225806452 10.000000000 14.413282130 19.412900315
+1.290322581 6.516129032 10.000000000 14.658795531 19.658787254
+1.290322581 6.806451613 10.000000000 14.873037538 19.873037533
+1.290322581 7.096774194 10.000000000 15.000000000 20.000000000
+1.290322581 7.387096774 10.000000000 15.000000000 20.000000000
+1.290322581 7.677419355 10.000000000 15.000000000 20.000000000
+1.290322581 7.967741935 10.000000000 15.000000000 20.000000000
+1.290322581 8.258064516 10.000000000 15.000000000 20.000000000
+1.290322581 8.548387097 10.000000000 15.000000000 20.000000000
+1.290322581 8.838709677 10.000000000 15.000000000 20.000000000
+1.290322581 9.129032258 10.000000000 15.000000000 20.000000000
+1.290322581 9.419354839 10.000000000 15.000000000 20.000000000
+1.290322581 9.709677419 10.000000000 15.000000000 20.000000000
+1.290322581 10.000000000 10.000000000 15.000000000 20.000000000
+1.580645161 1.000000000 10.000000000 10.000000000 12.500000000
+1.580645161 1.290322581 10.000000000 10.000000000 12.500000000
+1.580645161 1.580645161 10.000000000 10.000000000 12.500000000
+1.580645161 1.870967742 10.000000000 10.000000000 12.500000000
+1.580645161 2.161290323 10.000000000 10.000000000 12.500000000
+1.580645161 2.451612903 10.000000000 10.000000000 12.500000000
+1.580645161 2.741935484 10.000000000 10.000000000 12.500000000
+1.580645161 3.032258065 10.000000000 10.020323221 12.520404599
+1.580645161 3.322580645 10.000000000 10.217239082 12.726188365
+1.580645161 3.612903226 10.000000000 10.438541426 12.978595315
+1.580645161 3.903225806 10.000000000 10.688605148 13.303233716
+1.580645161 4.193548387 10.000000000 10.985194151 13.754553905
+1.580645161 4.483870968 10.000000000 11.368962007 14.431095437
+1.580645161 4.774193548 10.000000000 11.913195856 15.489093970
+1.580645161 5.064516129 10.000000000 12.682234786 17.023032304
+1.580645161 5.354838710 10.000000000 13.342744072 18.155449447
+1.580645161 5.645161290 10.000000000 13.792466240 18.754193916
+1.580645161 5.935483871 10.000000000 14.130816184 19.125588403
+1.580645161 6.225806452 10.000000000 14.413282130 19.412900315
+1.580645161 6.516129032 10.000000000 14.658795531 19.658787254
+1.580645161 6.806451613 10.000000000 14.873037538 19.873037533
+1.580645161 7.096774194 10.000000000 15.000000000 20.000000000
+1.580645161 7.387096774 10.000000000 15.000000000 20.000000000
+1.580645161 7.677419355 10.000000000 15.000000000 20.000000000
+1.580645161 7.967741935 10.000000000 15.000000000 20.000000000
+1.580645161 8.258064516 10.000000000 15.000000000 20.000000000
+1.580645161 8.548387097 10.000000000 15.000000000 20.000000000
+1.580645161 8.838709677 10.000000000 15.000000000 20.000000000
+1.580645161 9.129032258 10.000000000 15.000000000 20.000000000
+1.580645161 9.419354839 10.000000000 15.000000000 20.000000000
+1.580645161 9.709677419 10.000000000 15.000000000 20.000000000
+1.580645161 10.000000000 10.000000000 15.000000000 20.000000000
+1.870967742 1.000000000 10.000000000 10.000000000 12.500000000
+1.870967742 1.290322581 10.000000000 10.000000000 12.500000000
+1.870967742 1.580645161 10.000000000 10.000000000 12.500000000
+1.870967742 1.870967742 10.000000000 10.000000000 12.500000000
+1.870967742 2.161290323 10.000000000 10.000000000 12.500000000
+1.870967742 2.451612903 10.000000000 10.000000000 12.500000000
+1.870967742 2.741935484 10.000000000 10.000000000 12.500000000
+1.870967742 3.032258065 10.000000000 10.020323221 12.520404599
+1.870967742 3.322580645 10.000000000 10.217239082 12.726188365
+1.870967742 3.612903226 10.000000000 10.438541426 12.978595315
+1.870967742 3.903225806 10.000000000 10.688605148 13.303233716
+1.870967742 4.193548387 10.000000000 10.985194151 13.754553905
+1.870967742 4.483870968 10.000000000 11.368962007 14.431095437
+1.870967742 4.774193548 10.000000000 11.913195856 15.489093970
+1.870967742 5.064516129 10.000000000 12.682234786 17.023032304
+1.870967742 5.354838710 10.000000000 13.342744072 18.155449447
+1.870967742 5.645161290 10.000000000 13.792466240 18.754193916
+1.870967742 5.935483871 10.000000000 14.130816184 19.125588403
+1.870967742 6.225806452 10.000000000 14.413282130 19.412900315
+1.870967742 6.516129032 10.000000000 14.658795531 19.658787254
+1.870967742 6.806451613 10.000000000 14.873037538 19.873037533
+1.870967742 7.096774194 10.000000000 15.000000000 20.000000000
+1.870967742 7.387096774 10.000000000 15.000000000 20.000000000
+1.870967742 7.677419355 10.000000000 15.000000000 20.000000000
+1.870967742 7.967741935 10.000000000 15.000000000 20.000000000
+1.870967742 8.258064516 10.000000000 15.000000000 20.000000000
+1.870967742 8.548387097 10.000000000 15.000000000 20.000000000
+1.870967742 8.838709677 10.000000000 15.000000000 20.000000000
+1.870967742 9.129032258 10.000000000 15.000000000 20.000000000
+1.870967742 9.419354839 10.000000000 15.000000000 20.000000000
+1.870967742 9.709677419 10.000000000 15.000000000 20.000000000
+1.870967742 10.000000000 10.000000000 15.000000000 20.000000000
+2.161290323 1.000000000 10.000000000 10.000000000 12.500000000
+2.161290323 1.290322581 10.000000000 10.000000000 12.500000000
+2.161290323 1.580645161 10.000000000 10.000000000 12.500000000
+2.161290323 1.870967742 10.000000000 10.000000000 12.500000000
+2.161290323 2.161290323 10.000000000 10.000000000 12.500000000
+2.161290323 2.451612903 10.000000000 10.000000000 12.500000000
+2.161290323 2.741935484 10.000000000 10.000000000 12.500000000
+2.161290323 3.032258065 10.000000000 10.020323221 12.520404599
+2.161290323 3.322580645 10.000000000 10.217239082 12.726188365
+2.161290323 3.612903226 10.000000000 10.438541426 12.978595315
+2.161290323 3.903225806 10.000000000 10.688605148 13.303233716
+2.161290323 4.193548387 10.000000000 10.985194151 13.754553905
+2.161290323 4.483870968 10.000000000 11.368962007 14.431095437
+2.161290323 4.774193548 10.000000000 11.913195856 15.489093970
+2.161290323 5.064516129 10.000000000 12.682234786 17.023032304
+2.161290323 5.354838710 10.000000000 13.342744072 18.155449447
+2.161290323 5.645161290 10.000000000 13.792466240 18.754193916
+2.161290323 5.935483871 10.000000000 14.130816184 19.125588403
+2.161290323 6.225806452 10.000000000 14.413282130 19.412900315
+2.161290323 6.516129032 10.000000000 14.658795531 19.658787254
+2.161290323 6.806451613 10.000000000 14.873037538 19.873037533
+2.161290323 7.096774194 10.000000000 15.000000000 20.000000000
+2.161290323 7.387096774 10.000000000 15.000000000 20.000000000
+2.161290323 7.677419355 10.000000000 15.000000000 20.000000000
+2.161290323 7.967741935 10.000000000 15.000000000 20.000000000
+2.161290323 8.258064516 10.000000000 15.000000000 20.000000000
+2.161290323 8.548387097 10.000000000 15.000000000 20.000000000
+2.161290323 8.838709677 10.000000000 15.000000000 20.000000000
+2.161290323 9.129032258 10.000000000 15.000000000 20.000000000
+2.161290323 9.419354839 10.000000000 15.000000000 20.000000000
+2.161290323 9.709677419 10.000000000 15.000000000 20.000000000
+2.161290323 10.000000000 10.000000000 15.000000000 20.000000000
+2.451612903 1.000000000 10.000000000 10.000000000 12.500000000
+2.451612903 1.290322581 10.000000000 10.000000000 12.500000000
+2.451612903 1.580645161 10.000000000 10.000000000 12.500000000
+2.451612903 1.870967742 10.000000000 10.000000000 12.500000000
+2.451612903 2.161290323 10.000000000 10.000000000 12.500000000
+2.451612903 2.451612903 10.000000000 10.000000000 12.500000000
+2.451612903 2.741935484 10.000000000 10.000000000 12.500000000
+2.451612903 3.032258065 10.000000000 10.020323221 12.520404599
+2.451612903 3.322580645 10.000000000 10.217239082 12.726188365
+2.451612903 3.612903226 10.000000000 10.438541426 12.978595315
+2.451612903 3.903225806 10.000000000 10.688605148 13.303233716
+2.451612903 4.193548387 10.000000000 10.985194151 13.754553905
+2.451612903 4.483870968 10.000000000 11.368962007 14.431095437
+2.451612903 4.774193548 10.000000000 11.913195856 15.489093970
+2.451612903 5.064516129 10.000000000 12.682234786 17.023032304
+2.451612903 5.354838710 10.000000000 13.342744072 18.155449447
+2.451612903 5.645161290 10.000000000 13.792466240 18.754193916
+2.451612903 5.935483871 10.000000000 14.130816184 19.125588403
+2.451612903 6.225806452 10.000000000 14.413282130 19.412900315
+2.451612903 6.516129032 10.000000000 14.658795531 19.658787254
+2.451612903 6.806451613 10.000000000 14.873037538 19.873037533
+2.451612903 7.096774194 10.000000000 15.000000000 20.000000000
+2.451612903 7.387096774 10.000000000 15.000000000 20.000000000
+2.451612903 7.677419355 10.000000000 15.000000000 20.000000000
+2.451612903 7.967741935 10.000000000 15.000000000 20.000000000
+2.451612903 8.258064516 10.000000000 15.000000000 20.000000000
+2.451612903 8.548387097 10.000000000 15.000000000 20.000000000
+2.451612903 8.838709677 10.000000000 15.000000000 20.000000000
+2.451612903 9.129032258 10.000000000 15.000000000 20.000000000
+2.451612903 9.419354839 10.000000000 15.000000000 20.000000000
+2.451612903 9.709677419 10.000000000 15.000000000 20.000000000
+2.451612903 10.000000000 10.000000000 15.000000000 20.000000000
+2.741935484 1.000000000 10.000000000 10.000000000 12.500000000
+2.741935484 1.290322581 10.000000000 10.000000000 12.500000000
+2.741935484 1.580645161 10.000000000 10.000000000 12.500000000
+2.741935484 1.870967742 10.000000000 10.000000000 12.500000000
+2.741935484 2.161290323 10.000000000 10.000000000 12.500000000
+2.741935484 2.451612903 10.000000000 10.000000000 12.500000000
+2.741935484 2.741935484 10.000000000 10.000000000 12.500000000
+2.741935484 3.032258065 10.000000000 10.020323221 12.520404599
+2.741935484 3.322580645 10.000000000 10.217239082 12.726188365
+2.741935484 3.612903226 10.000000000 10.438541426 12.978595315
+2.741935484 3.903225806 10.000000000 10.688605148 13.303233716
+2.741935484 4.193548387 10.000000000 10.985194151 13.754553905
+2.741935484 4.483870968 10.000000000 11.368962007 14.431095437
+2.741935484 4.774193548 10.000000000 11.913195856 15.489093970
+2.741935484 5.064516129 10.000000000 12.682234786 17.023032304
+2.741935484 5.354838710 10.000000000 13.342744072 18.155449447
+2.741935484 5.645161290 10.000000000 13.792466240 18.754193916
+2.741935484 5.935483871 10.000000000 14.130816184 19.125588403
+2.741935484 6.225806452 10.000000000 14.413282130 19.412900315
+2.741935484 6.516129032 10.000000000 14.658795531 19.658787254
+2.741935484 6.806451613 10.000000000 14.873037538 19.873037533
+2.741935484 7.096774194 10.000000000 15.000000000 20.000000000
+2.741935484 7.387096774 10.000000000 15.000000000 20.000000000
+2.741935484 7.677419355 10.000000000 15.000000000 20.000000000
+2.741935484 7.967741935 10.000000000 15.000000000 20.000000000
+2.741935484 8.258064516 10.000000000 15.000000000 20.000000000
+2.741935484 8.548387097 10.000000000 15.000000000 20.000000000
+2.741935484 8.838709677 10.000000000 15.000000000 20.000000000
+2.741935484 9.129032258 10.000000000 15.000000000 20.000000000
+2.741935484 9.419354839 10.000000000 15.000000000 20.000000000
+2.741935484 9.709677419 10.000000000 15.000000000 20.000000000
+2.741935484 10.000000000 10.000000000 15.000000000 20.000000000
+3.032258065 1.000000000 10.000000000 10.020564138 12.530362554
+3.032258065 1.290322581 10.000000000 10.020564138 12.530362554
+3.032258065 1.580645161 10.000000000 10.020564138 12.530362554
+3.032258065 1.870967742 10.000000000 10.020564138 12.530362554
+3.032258065 2.161290323 10.000000000 10.020564138 12.530362554
+3.032258065 2.451612903 10.000000000 10.020564138 12.530362554
+3.032258065 2.741935484 10.000000000 10.020564138 12.530362554
+3.032258065 3.032258065 10.000081623 10.040234008 12.549713610
+3.032258065 3.322580645 10.000845356 10.231330430 12.745817533
+3.032258065 3.612903226 10.001660504 10.447099078 12.988462480
+3.032258065 3.903225806 10.002536324 10.692131028 13.303660935
+3.032258065 4.193548387 10.003506957 10.984311315 13.746235339
+3.032258065 4.483870968 10.004651223 11.364421081 14.415312194
+3.032258065 4.774193548 10.006135391 11.906301747 15.468939718
+3.032258065 5.064516129 10.008304662 12.675977549 17.006125822
+3.032258065 5.354838710 10.010797104 13.339232540 18.145674121
+3.032258065 5.645161290 10.013072877 13.791275308 18.749121698
+3.032258065 5.935483871 10.014992751 14.131144375 19.123168222
+3.032258065 6.225806452 10.016597454 14.414457255 19.412112587
+3.032258065 6.516129032 10.018017808 14.660147444 19.658914932
+3.032258065 6.806451613 10.019388331 14.873835282 19.873347530
+3.032258065 7.096774194 10.020324537 15.000000000 20.000000000
+3.032258065 7.387096774 10.020324537 15.000000000 20.000000000
+3.032258065 7.677419355 10.020324537 15.000000000 20.000000000
+3.032258065 7.967741935 10.020324537 15.000000000 20.000000000
+3.032258065 8.258064516 10.020324537 15.000000000 20.000000000
+3.032258065 8.548387097 10.020324537 15.000000000 20.000000000
+3.032258065 8.838709677 10.020324537 15.000000000 20.000000000
+3.032258065 9.129032258 10.020324537 15.000000000 20.000000000
+3.032258065 9.419354839 10.020324537 15.000000000 20.000000000
+3.032258065 9.709677419 10.020324537 15.000000000 20.000000000
+3.032258065 10.000000000 10.020324537 15.000000000 20.000000000
+3.322580645 1.000000000 10.000000000 10.238526001 12.814657118
+3.322580645 1.290322581 10.000000000 10.238526001 12.814657118
+3.322580645 1.580645161 10.000000000 10.238526001 12.814657118
+3.322580645 1.870967742 10.000000000 10.238526001 12.814657118
+3.322580645 2.161290323 10.000000000 10.238526001 12.814657118
+3.322580645 2.451612903 10.000000000 10.238526001 12.814657118
+3.322580645 2.741935484 10.000000000 10.238526001 12.814657118
+3.322580645 3.032258065 10.000810912 10.252160009 12.825094452
+3.322580645 3.322580645 10.008475729 10.390248102 12.941315539
+3.322580645 3.612903226 10.016826559 10.556788308 13.106528324
+3.322580645 3.903225806 10.026007885 10.758435372 13.349926281
+3.322580645 4.193548387 10.036425250 11.014648689 13.729800083
+3.322580645 4.483870968 10.048985641 11.367796303 14.350555384
+3.322580645 4.774193548 10.065636239 11.895433538 15.382805064
+3.322580645 5.064516129 10.090431587 12.665305783 16.934330737
+3.322580645 5.354838710 10.119058291 13.330507836 18.087258535
+3.322580645 5.645161290 10.145318864 13.790875134 18.711237499
+3.322580645 5.935483871 10.167053939 14.138887104 19.103029349
+3.322580645 6.225806452 10.184333797 14.427106637 19.405311407
+3.322580645 6.516129032 10.198472326 14.672873177 19.660047640
+3.322580645 6.806451613 10.210901210 14.880935703 19.876073110
+3.322580645 7.096774194 10.218749520 15.000000005 20.000000000
+3.322580645 7.387096774 10.218749520 15.000000005 20.000000000
+3.322580645 7.677419355 10.218749520 15.000000005 20.000000000
+3.322580645 7.967741935 10.218749520 15.000000005 20.000000000
+3.322580645 8.258064516 10.218749520 15.000000005 20.000000000
+3.322580645 8.548387097 10.218749520 15.000000005 20.000000000
+3.322580645 8.838709677 10.218749520 15.000000005 20.000000000
+3.322580645 9.129032258 10.218749520 15.000000005 20.000000000
+3.322580645 9.419354839 10.218749520 15.000000005 20.000000000
+3.322580645 9.709677419 10.218749520 15.000000005 20.000000000
+3.322580645 10.000000000 10.218749520 15.000000005 20.000000000
+3.612903226 1.000000000 10.000000000 10.504908296 13.128455463
+3.612903226 1.290322581 10.000000000 10.504908296 13.128455463
+3.612903226 1.580645161 10.000000000 10.504908296 13.128455463
+3.612903226 1.870967742 10.000000000 10.504908296 13.128455463
+3.612903226 2.161290323 10.000000000 10.504908296 13.128455463
+3.612903226 2.451612903 10.000000000 10.504908296 13.128455463
+3.612903226 2.741935484 10.000000000 10.504908296 13.128455463
+3.612903226 3.032258065 10.001516539 10.512626733 13.130885405
+3.612903226 3.322580645 10.016001683 10.599926822 13.179304000
+3.612903226 3.612903226 10.032129555 10.721202126 13.285286198
+3.612903226 3.903225806 10.050319022 10.885336976 13.480541261
+3.612903226 4.193548387 10.071543600 11.114258924 13.827219367
+3.612903226 4.483870968 10.097850290 11.452875842 14.435424511
+3.612903226 4.774193548 10.133668269 11.980021902 15.481437354
+3.612903226 5.064516129 10.187198497 12.733746068 17.004065185
+3.612903226 5.354838710 10.247964197 13.361747553 18.081408199
+3.612903226 5.645161290 10.304036539 13.808753893 18.687360629
+3.612903226 5.935483871 10.350251618 14.155213729 19.086063787
+3.612903226 6.225806452 10.386088635 14.443553815 19.399366077
+3.612903226 6.516129032 10.413832571 14.686735031 19.661496202
+3.612903226 6.806451613 10.436235155 14.888005490 19.878875276
+3.612903226 7.096774194 10.449261329 15.000000885 20.000000000
+3.612903226 7.387096774 10.449261329 15.000000885 20.000000000
+3.612903226 7.677419355 10.449261329 15.000000885 20.000000000
+3.612903226 7.967741935 10.449261329 15.000000885 20.000000000
+3.612903226 8.258064516 10.449261329 15.000000885 20.000000000
+3.612903226 8.548387097 10.449261329 15.000000885 20.000000000
+3.612903226 8.838709677 10.449261329 15.000000885 20.000000000
+3.612903226 9.129032258 10.449261329 15.000000885 20.000000000
+3.612903226 9.419354839 10.449261329 15.000000885 20.000000000
+3.612903226 9.709677419 10.449261329 15.000000885 20.000000000
+3.612903226 10.000000000 10.449261329 15.000000885 20.000000000
+3.903225806 1.000000000 10.000000000 10.810170511 13.504826188
+3.903225806 1.290322581 10.000000000 10.810170511 13.504826188
+3.903225806 1.580645161 10.000000000 10.810170511 13.504826188
+3.903225806 1.870967742 10.000000000 10.810170511 13.504826188
+3.903225806 2.161290323 10.000000000 10.810170511 13.504826188
+3.903225806 2.451612903 10.000000000 10.810170511 13.504826188
+3.903225806 2.741935484 10.000000000 10.810170511 13.504826188
+3.903225806 3.032258065 10.002191475 10.812567996 13.499944985
+3.903225806 3.322580645 10.023341607 10.855521242 13.491036767
+3.903225806 3.612903226 10.047419391 10.939710572 13.555284598
+3.903225806 3.903225806 10.075341637 11.076302955 13.726499490
+3.903225806 4.193548387 10.108936013 11.290254243 14.070909786
+3.903225806 4.483870968 10.151939277 11.629038311 14.703300699
+3.903225806 4.774193548 10.212336488 12.166773063 15.791280803
+3.903225806 5.064516129 10.300093175 12.865867633 17.184787504
+3.903225806 5.354838710 10.397549799 13.425616094 18.115533442
+3.903225806 5.645161290 10.488260676 13.842905617 18.675012612
+3.903225806 5.935483871 10.563899084 14.179759717 19.072515315
+3.903225806 6.225806452 10.622764862 14.463818768 19.394943387
+3.903225806 6.516129032 10.667486100 14.701882692 19.663850989
+3.903225806 6.806451613 10.701911006 14.895189653 19.882050715
+3.903225806 7.096774194 10.721003908 15.000021130 20.000000000
+3.903225806 7.387096774 10.721003908 15.000021130 20.000000000
+3.903225806 7.677419355 10.721003908 15.000021130 20.000000000
+3.903225806 7.967741935 10.721003908 15.000021130 20.000000000
+3.903225806 8.258064516 10.721003908 15.000021130 20.000000000
+3.903225806 8.548387097 10.721003908 15.000021130 20.000000000
+3.903225806 8.838709677 10.721003908 15.000021130 20.000000000
+3.903225806 9.129032258 10.721003908 15.000021130 20.000000000
+3.903225806 9.419354839 10.721003908 15.000021130 20.000000000
+3.903225806 9.709677419 10.721003908 15.000021130 20.000000000
+3.903225806 10.000000000 10.721003908 15.000021130 20.000000000
+4.193548387 1.000000000 10.000000000 11.157523904 14.002629729
+4.193548387 1.290322581 10.000000000 11.157523904 14.002629729
+4.193548387 1.580645161 10.000000000 11.157523904 14.002629729
+4.193548387 1.870967742 10.000000000 11.157523904 14.002629729
+4.193548387 2.161290323 10.000000000 11.157523904 14.002629729
+4.193548387 2.451612903 10.000000000 11.157523904 14.002629729
+4.193548387 2.741935484 10.000000000 11.157523904 14.002629729
+4.193548387 3.032258065 10.002847967 11.155500895 13.991050173
+4.193548387 3.322580645 10.030611301 11.163431904 13.934544815
+4.193548387 3.612903226 10.062937365 11.222007768 13.974464175
+4.193548387 3.903225806 10.101503669 11.344539784 14.146530424
+4.193548387 4.193548387 10.149476613 11.558492423 14.519820638
+4.193548387 4.483870968 10.213067693 11.910494416 15.206102473
+4.193548387 4.774193548 10.304552071 12.447025439 16.305510232
+4.193548387 5.064516129 10.428253360 13.034623096 17.419899680
+4.193548387 5.354838710 10.564830507 13.510543286 18.168936315
+4.193548387 5.645161290 10.693996106 13.890105622 18.670596691
+4.193548387 5.935483871 10.804889687 14.211826878 19.062949046
+4.193548387 6.225806452 10.893985831 14.487804439 19.393012538
+4.193548387 6.516129032 10.963155502 14.718426145 19.667836719
+4.193548387 6.806451613 11.016887401 14.902672746 19.885926843
+4.193548387 7.096774194 11.047340520 15.000210546 20.000000000
+4.193548387 7.387096774 11.047340520 15.000210546 20.000000000
+4.193548387 7.677419355 11.047340520 15.000210546 20.000000000
+4.193548387 7.967741935 11.047340520 15.000210546 20.000000000
+4.193548387 8.258064516 11.047340520 15.000210546 20.000000000
+4.193548387 8.548387097 11.047340520 15.000210546 20.000000000
+4.193548387 8.838709677 11.047340520 15.000210546 20.000000000
+4.193548387 9.129032258 11.047340520 15.000210546 20.000000000
+4.193548387 9.419354839 11.047340520 15.000210546 20.000000000
+4.193548387 9.709677419 11.047340520 15.000210546 20.000000000
+4.193548387 10.000000000 11.047340520 15.000210546 20.000000000
+4.483870968 1.000000000 10.000000000 11.565284816 14.705763295
+4.483870968 1.290322581 10.000000000 11.565284816 14.705763295
+4.483870968 1.580645161 10.000000000 11.565284816 14.705763295
+4.483870968 1.870967742 10.000000000 11.565284816 14.705763295
+4.483870968 2.161290323 10.000000000 11.565284816 14.705763295
+4.483870968 2.451612903 10.000000000 11.565284816 14.705763295
+4.483870968 2.741935484 10.000000000 11.565284816 14.705763295
+4.483870968 3.032258065 10.003518332 11.559971097 14.688531488
+4.483870968 3.322580645 10.038148789 11.544067577 14.596697135
+4.483870968 3.612903226 10.079373052 11.590123754 14.630573226
+4.483870968 3.903225806 10.129999142 11.712651674 14.826642427
+4.483870968 4.193548387 10.195142637 11.937986529 15.249393001
+4.483870968 4.483870968 10.284538090 12.299658730 15.978123106
+4.483870968 4.774193548 10.407288688 12.751308571 16.856785744
+4.483870968 5.064516129 10.566265451 13.210391988 17.648137186
+4.483870968 5.354838710 10.742013612 13.605608156 18.224568495
+4.483870968 5.645161290 10.912944832 13.947123303 18.672577283
+4.483870968 5.935483871 11.066669588 14.250519401 19.058798213
+4.483870968 6.225806452 11.197095817 14.515307747 19.394892563
+4.483870968 6.516129032 11.303930141 14.736513059 19.674293402
+4.483870968 6.806451613 11.391719855 14.910904783 19.890847813
+4.483870968 7.096774194 11.445068797 15.001284580 20.000000000
+4.483870968 7.387096774 11.445068797 15.001284580 20.000000000
+4.483870968 7.677419355 11.445068797 15.001284580 20.000000000
+4.483870968 7.967741935 11.445068797 15.001284580 20.000000000
+4.483870968 8.258064516 11.445068797 15.001284580 20.000000000
+4.483870968 8.548387097 11.445068797 15.001284580 20.000000000
+4.483870968 8.838709677 11.445068797 15.001284580 20.000000000
+4.483870968 9.129032258 11.445068797 15.001284580 20.000000000
+4.483870968 9.419354839 11.445068797 15.001284580 20.000000000
+4.483870968 9.709677419 11.445068797 15.001284580 20.000000000
+4.483870968 10.000000000 11.445068797 15.001284580 20.000000000
+4.774193548 1.000000000 10.000000000 12.058980464 15.701021693
+4.774193548 1.290322581 10.000000000 12.058980464 15.701021693
+4.774193548 1.580645161 10.000000000 12.058980464 15.701021693
+4.774193548 1.870967742 10.000000000 12.058980464 15.701021693
+4.774193548 2.161290323 10.000000000 12.058980464 15.701021693
+4.774193548 2.451612903 10.000000000 12.058980464 15.701021693
+4.774193548 2.741935484 10.000000000 12.058980464 15.701021693
+4.774193548 3.032258065 10.004257800 12.051831158 15.680761274
+4.774193548 3.322580645 10.046560497 12.024384078 15.574111451
+4.774193548 3.612903226 10.098020591 12.068331239 15.617253641
+4.774193548 3.903225806 10.163026519 12.195621174 15.840037790
+4.774193548 4.193548387 10.248842025 12.415213380 16.258998150
+4.774193548 4.483870968 10.362811901 12.699044498 16.776643149
+4.774193548 4.774193548 10.512690124 13.024422676 17.317616013
+4.774193548 5.064516129 10.703263743 13.373149036 17.833118921
+4.774193548 5.354838710 10.916444195 13.703982825 18.277985683
+4.774193548 5.645161290 11.132588599 14.011409556 18.683389813
+4.774193548 5.935483871 11.338852711 14.294853866 19.062628031
+4.774193548 6.225806452 11.526117376 14.546111577 19.402210670
+4.774193548 6.516129032 11.690681294 14.756568825 19.684098329
+4.774193548 6.806451613 11.836523788 14.921219044 19.897134924
+4.774193548 7.096774194 11.931844472 15.005712815 20.000000000
+4.774193548 7.387096774 11.931844472 15.005712815 20.000000000
+4.774193548 7.677419355 11.931844472 15.005712815 20.000000000
+4.774193548 7.967741935 11.931844472 15.005712815 20.000000000
+4.774193548 8.258064516 11.931844472 15.005712815 20.000000000
+4.774193548 8.548387097 11.931844472 15.005712815 20.000000000
+4.774193548 8.838709677 11.931844472 15.005712815 20.000000000
+4.774193548 9.129032258 11.931844472 15.005712815 20.000000000
+4.774193548 9.419354839 11.931844472 15.005712815 20.000000000
+4.774193548 9.709677419 11.931844472 15.005712815 20.000000000
+4.774193548 10.000000000 11.931844472 15.005712815 20.000000000
+5.064516129 1.000000000 10.000000000 12.621619769 16.933368673
+5.064516129 1.290322581 10.000000000 12.621619769 16.933368673
+5.064516129 1.580645161 10.000000000 12.621619769 16.933368673
+5.064516129 1.870967742 10.000000000 12.621619769 16.933368673
+5.064516129 2.161290323 10.000000000 12.621619769 16.933368673
+5.064516129 2.451612903 10.000000000 12.621619769 16.933368673
+5.064516129 2.741935484 10.000000000 12.621619769 16.933368673
+5.064516129 3.032258065 10.005146712 12.614366006 16.914980770
+5.064516129 3.322580645 10.056698295 12.581893441 16.810593662
+5.064516129 3.612903226 10.120169544 12.609005731 16.817436387
+5.064516129 3.903225806 10.200300484 12.693292869 16.924650571
+5.064516129 4.193548387 10.303330308 12.829792446 17.110642790
+5.064516129 4.483870968 10.436761057 13.013559654 17.353140381
+5.064516129 4.774193548 10.608584137 13.242465682 17.640746773
+5.064516129 5.064516129 10.825065934 13.517238305 17.978395774
+5.064516129 5.354838710 11.073354364 13.802678770 18.337797480
+5.064516129 5.645161290 11.338339319 14.080820782 18.709018123
+5.064516129 5.935483871 11.608136235 14.343723093 19.077915408
+5.064516129 6.225806452 11.871234576 14.580152615 19.416716601
+5.064516129 6.516129032 12.120142764 14.779818162 19.698008481
+5.064516129 6.806451613 12.357520482 14.937194312 19.905017104
+5.064516129 7.096774194 12.521102945 15.020319196 20.000000000
+5.064516129 7.387096774 12.521102945 15.020319196 20.000000000
+5.064516129 7.677419355 12.521102945 15.020319196 20.000000000
+5.064516129 7.967741935 12.521102945 15.020319196 20.000000000
+5.064516129 8.258064516 12.521102945 15.020319196 20.000000000
+5.064516129 8.548387097 12.521102945 15.020319196 20.000000000
+5.064516129 8.838709677 12.521102945 15.020319196 20.000000000
+5.064516129 9.129032258 12.521102945 15.020319196 20.000000000
+5.064516129 9.419354839 12.521102945 15.020319196 20.000000000
+5.064516129 9.709677419 12.521102945 15.020319196 20.000000000
+5.064516129 10.000000000 12.521102945 15.020319196 20.000000000
+5.354838710 1.000000000 10.000000000 13.013861899 17.722526667
+5.354838710 1.290322581 10.000000000 13.013861899 17.722526667
+5.354838710 1.580645161 10.000000000 13.013861899 17.722526667
+5.354838710 1.870967742 10.000000000 13.013861899 17.722526667
+5.354838710 2.161290323 10.000000000 13.013861899 17.722526667
+5.354838710 2.451612903 10.000000000 13.013861899 17.722526667
+5.354838710 2.741935484 10.000000000 13.013861899 17.722526667
+5.354838710 3.032258065 10.006014949 13.006869691 17.706851286
+5.354838710 3.322580645 10.066342933 12.965471340 17.593850801
+5.354838710 3.612903226 10.140231454 12.964403129 17.534521084
+5.354838710 3.903225806 10.232270564 13.004888418 17.529033919
+5.354838710 4.193548387 10.348580620 13.088107989 17.575956320
+5.354838710 4.483870968 10.496818921 13.216786998 17.677894459
+5.354838710 4.774193548 10.686051524 13.396186129 17.845882749
+5.354838710 5.064516129 10.925829268 13.632559211 18.099001135
+5.354838710 5.354838710 11.209919760 13.890101018 18.408558307
+5.354838710 5.645161290 11.528570742 14.146225018 18.751087862
+5.354838710 5.935483871 11.872594688 14.391880702 19.105790086
+5.354838710 6.225806452 12.230155222 14.615966067 19.439094903
+5.354838710 6.516129032 12.591079681 14.808684323 19.716275926
+5.354838710 6.806451613 12.955941737 14.967165018 19.914536590
+5.354838710 7.096774194 13.214762751 15.060950730 20.000000000
+5.354838710 7.387096774 13.214762751 15.060950730 20.000000000
+5.354838710 7.677419355 13.214762751 15.060950730 20.000000000
+5.354838710 7.967741935 13.214762751 15.060950730 20.000000000
+5.354838710 8.258064516 13.214762751 15.060950730 20.000000000
+5.354838710 8.548387097 13.214762751 15.060950730 20.000000000
+5.354838710 8.838709677 13.214762751 15.060950730 20.000000000
+5.354838710 9.129032258 13.214762751 15.060950730 20.000000000
+5.354838710 9.419354839 13.214762751 15.060950730 20.000000000
+5.354838710 9.709677419 13.214762751 15.060950730 20.000000000
+5.354838710 10.000000000 13.214762751 15.060950730 20.000000000
+5.645161290 1.000000000 10.000000000 13.244783448 18.109489138
+5.645161290 1.290322581 10.000000000 13.244783448 18.109489138
+5.645161290 1.580645161 10.000000000 13.244783448 18.109489138
+5.645161290 1.870967742 10.000000000 13.244783448 18.109489138
+5.645161290 2.161290323 10.000000000 13.244783448 18.109489138
+5.645161290 2.451612903 10.000000000 13.244783448 18.109489138
+5.645161290 2.741935484 10.000000000 13.244783448 18.109489138
+5.645161290 3.032258065 10.006766298 13.237774154 18.095072669
+5.645161290 3.322580645 10.074459191 13.190872866 17.979911424
+5.645161290 3.612903226 10.156682138 13.175344657 17.894934931
+5.645161290 3.903225806 10.257906448 13.194481414 17.845569901
+5.645161290 4.193548387 10.384363399 13.252314383 17.838705930
+5.645161290 4.483870968 10.544408861 13.354390862 17.885141400
+5.645161290 4.774193548 10.749033088 13.508424871 18.001992097
+5.645161290 5.064516129 11.011983915 13.723146199 18.212857917
+5.645161290 5.354838710 11.333589940 13.962485123 18.489219169
+5.645161290 5.645161290 11.710068477 14.202955697 18.806280615
+5.645161290 5.935483871 12.136994407 14.436640443 19.144415713
+5.645161290 6.225806452 12.604720729 14.654339717 19.468510328
+5.645161290 6.516129032 13.101632560 14.849606989 19.738417145
+5.645161290 6.806451613 13.623727732 15.028577014 19.925489144
+5.645161290 7.096774194 13.996146922 15.158825640 20.000000000
+5.645161290 7.387096774 13.996146922 15.158825640 20.000000000
+5.645161290 7.677419355 13.996146922 15.158825640 20.000000000
+5.645161290 7.967741935 13.996146922 15.158825640 20.000000000
+5.645161290 8.258064516 13.996146922 15.158825640 20.000000000
+5.645161290 8.548387097 13.996146922 15.158825640 20.000000000
+5.645161290 8.838709677 13.996146922 15.158825640 20.000000000
+5.645161290 9.129032258 13.996146922 15.158825640 20.000000000
+5.645161290 9.419354839 13.996146922 15.158825640 20.000000000
+5.645161290 9.709677419 13.996146922 15.158825640 20.000000000
+5.645161290 10.000000000 13.996146922 15.158825640 20.000000000
+5.935483871 1.000000000 10.000000000 13.401208666 18.333970891
+5.935483871 1.290322581 10.000000000 13.401208666 18.333970891
+5.935483871 1.580645161 10.000000000 13.401208666 18.333970891
+5.935483871 1.870967742 10.000000000 13.401208666 18.333970891
+5.935483871 2.161290323 10.000000000 13.401208666 18.333970891
+5.935483871 2.451612903 10.000000000 13.401208666 18.333970891
+5.935483871 2.741935484 10.000000000 13.401208666 18.333970891
+5.935483871 3.032258065 10.007443801 13.394073286 18.320194702
+5.935483871 3.322580645 10.081521395 13.343529838 18.205985651
+5.935483871 3.612903226 10.170606472 13.320092774 18.113408216
+5.935483871 3.903225806 10.279237154 13.327710961 18.049128779
+5.935483871 4.193548387 10.414061629 13.371284478 18.021975049
+5.935483871 4.483870968 10.584551085 13.457309453 18.044566871
+5.935483871 4.774193548 10.804081039 13.594715896 18.135620170
+5.935483871 5.064516129 11.090993693 13.794308290 18.321130673
+5.935483871 5.354838710 11.452089024 14.020655377 18.573380719
+5.935483871 5.645161290 11.890263995 14.250754084 18.868697334
+5.935483871 5.935483871 12.407459638 14.478989354 19.190114288
+5.935483871 6.225806452 12.997671406 14.700310557 19.502878399
+5.935483871 6.516129032 13.647127791 14.916608672 19.763270216
+5.935483871 6.806451613 14.340979512 15.153493506 19.937484405
+5.935483871 7.096774194 14.827685905 15.364218694 20.000000000
+5.935483871 7.387096774 14.827685905 15.364218694 20.000000000
+5.935483871 7.677419355 14.827685905 15.364218694 20.000000000
+5.935483871 7.967741935 14.827685905 15.364218694 20.000000000
+5.935483871 8.258064516 14.827685905 15.364218694 20.000000000
+5.935483871 8.548387097 14.827685905 15.364218694 20.000000000
+5.935483871 8.838709677 14.827685905 15.364218694 20.000000000
+5.935483871 9.129032258 14.827685905 15.364218694 20.000000000
+5.935483871 9.419354839 14.827685905 15.364218694 20.000000000
+5.935483871 9.709677419 14.827685905 15.364218694 20.000000000
+5.935483871 10.000000000 14.827685905 15.364218694 20.000000000
+6.225806452 1.000000000 10.000000000 13.521407226 18.490281826
+6.225806452 1.290322581 10.000000000 13.521407226 18.490281826
+6.225806452 1.580645161 10.000000000 13.521407226 18.490281826
+6.225806452 1.870967742 10.000000000 13.521407226 18.490281826
+6.225806452 2.161290323 10.000000000 13.521407226 18.490281826
+6.225806452 2.451612903 10.000000000 13.521407226 18.490281826
+6.225806452 2.741935484 10.000000000 13.521407226 18.490281826
+6.225806452 3.032258065 10.008103023 13.514140641 18.476969515
+6.225806452 3.322580645 10.088153003 13.460835310 18.364877707
+6.225806452 3.612903226 10.183352044 13.431824922 18.270567249
+6.225806452 3.903225806 10.298530841 13.431203100 18.200721216
+6.225806452 4.193548387 10.441056619 13.464145973 18.164351799
+6.225806452 4.483870968 10.621870428 13.537643724 18.174340531
+6.225806452 4.774193548 10.857112400 13.661628176 18.249929499
+6.225806452 5.064516129 11.170105930 13.849038003 18.418640731
+6.225806452 5.354838710 11.574291401 14.066015685 18.653507307
+6.225806452 5.645161290 12.079699400 14.291251628 18.931644662
+6.225806452 5.935483871 12.694889781 14.523401908 19.238162865
+6.225806452 6.225806452 13.416217710 14.765821293 19.539326380
+6.225806452 6.516129032 14.222918735 15.036827937 19.789435643
+6.225806452 6.806451613 15.078771212 15.391913006 19.950218302
+6.225806452 7.096774194 15.657216132 15.735413612 20.000000000
+6.225806452 7.387096774 15.657216132 15.735413612 20.000000000
+6.225806452 7.677419355 15.657216132 15.735413612 20.000000000
+6.225806452 7.967741935 15.657216132 15.735413612 20.000000000
+6.225806452 8.258064516 15.657216132 15.735413612 20.000000000
+6.225806452 8.548387097 15.657216132 15.735413612 20.000000000
+6.225806452 8.838709677 15.657216132 15.735413612 20.000000000
+6.225806452 9.129032258 15.657216132 15.735413612 20.000000000
+6.225806452 9.419354839 15.657216132 15.735413612 20.000000000
+6.225806452 9.709677419 15.657216132 15.735413612 20.000000000
+6.225806452 10.000000000 15.657216132 15.735413612 20.000000000
+6.516129032 1.000000000 10.000000000 13.619720941 18.608806194
+6.516129032 1.290322581 10.000000000 13.619720941 18.608806194
+6.516129032 1.580645161 10.000000000 13.619720941 18.608806194
+6.516129032 1.870967742 10.000000000 13.619720941 18.608806194
+6.516129032 2.161290323 10.000000000 13.619720941 18.608806194
+6.516129032 2.451612903 10.000000000 13.619720941 18.608806194
+6.516129032 2.741935484 10.000000000 13.619720941 18.608806194
+6.516129032 3.032258065 10.008796065 13.612346679 18.595858277
+6.516129032 3.322580645 10.094914486 13.556805241 18.485913330
+6.516129032 3.612903226 10.196067943 13.523172782 18.391481322
+6.516129032 3.903225806 10.317633610 13.515503749 18.319021613
+6.516129032 4.193548387 10.468057112 13.539104368 18.277428362
+6.516129032 4.483870968 10.660217177 13.601388696 18.279576799
+6.516129032 4.774193548 10.913601861 13.713341965 18.344952152
+6.516129032 5.064516129 11.257202098 13.890353256 18.502068098
+6.516129032 5.354838710 11.711560991 14.101549313 18.724649911
+6.516129032 5.645161290 12.293650185 14.329635734 18.990008501
+6.516129032 5.935483871 13.016511933 14.581790143 19.284476712
+6.516129032 6.225806452 13.873035372 14.877229146 19.575567933
+6.516129032 6.516129032 14.825313064 15.258980220 19.816607913
+6.516129032 6.806451613 15.804467725 15.803140508 19.963873617
+6.516129032 7.096774194 16.431600988 16.299972993 20.000000000
+6.516129032 7.387096774 16.431600988 16.299972993 20.000000000
+6.516129032 7.677419355 16.431600988 16.299972993 20.000000000
+6.516129032 7.967741935 16.431600988 16.299972993 20.000000000
+6.516129032 8.258064516 16.431600988 16.299972993 20.000000000
+6.516129032 8.548387097 16.431600988 16.299972993 20.000000000
+6.516129032 8.838709677 16.431600988 16.299972993 20.000000000
+6.516129032 9.129032258 16.431600988 16.299972993 20.000000000
+6.516129032 9.419354839 16.431600988 16.299972993 20.000000000
+6.516129032 9.709677419 16.431600988 16.299972993 20.000000000
+6.516129032 10.000000000 16.431600988 16.299972993 20.000000000
+6.806451613 1.000000000 10.000000000 13.702140588 18.700568553
+6.806451613 1.290322581 10.000000000 13.702140588 18.700568553
+6.806451613 1.580645161 10.000000000 13.702140588 18.700568553
+6.806451613 1.870967742 10.000000000 13.702140588 18.700568553
+6.806451613 2.161290323 10.000000000 13.702140588 18.700568553
+6.806451613 2.451612903 10.000000000 13.702140588 18.700568553
+6.806451613 2.741935484 10.000000000 13.702140588 18.700568553
+6.806451613 3.032258065 10.009566877 13.694695654 18.687889031
+6.806451613 3.322580645 10.102239226 13.637457673 18.579757963
+6.806451613 3.612903226 10.209597091 13.599971487 18.485773947
+6.806451613 3.903225806 10.337931790 13.586088799 18.412087907
+6.806451613 4.193548387 10.497359572 13.601147106 18.367393881
+6.806451613 4.483870968 10.703550229 13.652988131 18.364466144
+6.806451613 4.774193548 10.980458810 13.753895322 18.422857042
+6.806451613 5.064516129 11.363992774 13.922588347 18.571664806
+6.806451613 5.354838710 11.882332702 14.133990028 18.785431300
+6.806451613 5.645161290 12.557491974 14.380014720 19.041563761
+6.806451613 5.935483871 13.400370731 14.684815949 19.327600979
+6.806451613 6.225806452 14.388065262 15.092179113 19.613100661
+6.806451613 6.516129032 15.452078155 15.660637661 19.848761837
+6.806451613 6.806451613 16.488227443 16.421596031 19.978526735
+6.806451613 7.096774194 17.110750392 17.007626023 20.000000000
+6.806451613 7.387096774 17.110750392 17.007626023 20.000000000
+6.806451613 7.677419355 17.110750392 17.007626023 20.000000000
+6.806451613 7.967741935 17.110750392 17.007626023 20.000000000
+6.806451613 8.258064516 17.110750392 17.007626023 20.000000000
+6.806451613 8.548387097 17.110750392 17.007626023 20.000000000
+6.806451613 8.838709677 17.110750392 17.007626023 20.000000000
+6.806451613 9.129032258 17.110750392 17.007626023 20.000000000
+6.806451613 9.419354839 17.110750392 17.007626023 20.000000000
+6.806451613 9.709677419 17.110750392 17.007626023 20.000000000
+6.806451613 10.000000000 17.110750392 17.007626023 20.000000000
+7.096774194 1.000000000 10.000000000 13.750000000 18.750000000
+7.096774194 1.290322581 10.000000000 13.750000000 18.750000000
+7.096774194 1.580645161 10.000000000 13.750000000 18.750000000
+7.096774194 1.870967742 10.000000000 13.750000000 18.750000000
+7.096774194 2.161290323 10.000000000 13.750000000 18.750000000
+7.096774194 2.451612903 10.000000000 13.750000000 18.750000000
+7.096774194 2.741935484 10.000000000 13.750000000 18.750000000
+7.096774194 3.032258065 10.010142154 13.742536520 18.737455859
+7.096774194 3.322580645 10.107593677 13.684557246 18.630423796
+7.096774194 3.612903226 10.219378581 13.645030600 18.537086952
+7.096774194 3.903225806 10.352768137 13.627557695 18.463319088
+7.096774194 4.193548387 10.519625429 13.637427439 18.417599484
+7.096774194 4.483870968 10.738408418 13.682818578 18.412535791
+7.096774194 4.774193548 11.037217342 13.777278068 18.467583744
+7.096774194 5.064516129 11.457663040 13.943032824 18.612009655
+7.096774194 5.354838710 12.032834518 14.162291151 18.821124666
+7.096774194 5.645161290 12.784673825 14.439131521 19.073000135
+7.096774194 5.935483871 13.714623381 14.815969959 19.357395690
+7.096774194 6.225806452 14.778744019 15.350155064 19.645850060
+7.096774194 6.516129032 15.883198672 16.075414380 19.878699414
+7.096774194 6.806451613 16.909538446 16.932414748 19.986611801
+7.096774194 7.096774194 17.500000000 17.500000000 20.000000000
+7.096774194 7.387096774 17.500000000 17.500000000 20.000000000
+7.096774194 7.677419355 17.500000000 17.500000000 20.000000000
+7.096774194 7.967741935 17.500000000 17.500000000 20.000000000
+7.096774194 8.258064516 17.500000000 17.500000000 20.000000000
+7.096774194 8.548387097 17.500000000 17.500000000 20.000000000
+7.096774194 8.838709677 17.500000000 17.500000000 20.000000000
+7.096774194 9.129032258 17.500000000 17.500000000 20.000000000
+7.096774194 9.419354839 17.500000000 17.500000000 20.000000000
+7.096774194 9.709677419 17.500000000 17.500000000 20.000000000
+7.096774194 10.000000000 17.500000000 17.500000000 20.000000000
+7.387096774 1.000000000 10.000000000 13.750000000 18.750000000
+7.387096774 1.290322581 10.000000000 13.750000000 18.750000000
+7.387096774 1.580645161 10.000000000 13.750000000 18.750000000
+7.387096774 1.870967742 10.000000000 13.750000000 18.750000000
+7.387096774 2.161290323 10.000000000 13.750000000 18.750000000
+7.387096774 2.451612903 10.000000000 13.750000000 18.750000000
+7.387096774 2.741935484 10.000000000 13.750000000 18.750000000
+7.387096774 3.032258065 10.010142154 13.742536520 18.737455859
+7.387096774 3.322580645 10.107593677 13.684557246 18.630423796
+7.387096774 3.612903226 10.219378581 13.645030600 18.537086952
+7.387096774 3.903225806 10.352768137 13.627557695 18.463319088
+7.387096774 4.193548387 10.519625429 13.637427439 18.417599484
+7.387096774 4.483870968 10.738408418 13.682818578 18.412535791
+7.387096774 4.774193548 11.037217342 13.777278068 18.467583744
+7.387096774 5.064516129 11.457663040 13.943032824 18.612009655
+7.387096774 5.354838710 12.032834518 14.162291151 18.821124666
+7.387096774 5.645161290 12.784673825 14.439131521 19.073000135
+7.387096774 5.935483871 13.714623381 14.815969959 19.357395690
+7.387096774 6.225806452 14.778744019 15.350155064 19.645850060
+7.387096774 6.516129032 15.883198672 16.075414380 19.878699414
+7.387096774 6.806451613 16.909538446 16.932414748 19.986611801
+7.387096774 7.096774194 17.500000000 17.500000000 20.000000000
+7.387096774 7.387096774 17.500000000 17.500000000 20.000000000
+7.387096774 7.677419355 17.500000000 17.500000000 20.000000000
+7.387096774 7.967741935 17.500000000 17.500000000 20.000000000
+7.387096774 8.258064516 17.500000000 17.500000000 20.000000000
+7.387096774 8.548387097 17.500000000 17.500000000 20.000000000
+7.387096774 8.838709677 17.500000000 17.500000000 20.000000000
+7.387096774 9.129032258 17.500000000 17.500000000 20.000000000
+7.387096774 9.419354839 17.500000000 17.500000000 20.000000000
+7.387096774 9.709677419 17.500000000 17.500000000 20.000000000
+7.387096774 10.000000000 17.500000000 17.500000000 20.000000000
+7.677419355 1.000000000 10.000000000 13.750000000 18.750000000
+7.677419355 1.290322581 10.000000000 13.750000000 18.750000000
+7.677419355 1.580645161 10.000000000 13.750000000 18.750000000
+7.677419355 1.870967742 10.000000000 13.750000000 18.750000000
+7.677419355 2.161290323 10.000000000 13.750000000 18.750000000
+7.677419355 2.451612903 10.000000000 13.750000000 18.750000000
+7.677419355 2.741935484 10.000000000 13.750000000 18.750000000
+7.677419355 3.032258065 10.010142154 13.742536520 18.737455859
+7.677419355 3.322580645 10.107593677 13.684557246 18.630423796
+7.677419355 3.612903226 10.219378581 13.645030600 18.537086952
+7.677419355 3.903225806 10.352768137 13.627557695 18.463319088
+7.677419355 4.193548387 10.519625429 13.637427439 18.417599484
+7.677419355 4.483870968 10.738408418 13.682818578 18.412535791
+7.677419355 4.774193548 11.037217342 13.777278068 18.467583744
+7.677419355 5.064516129 11.457663040 13.943032824 18.612009655
+7.677419355 5.354838710 12.032834518 14.162291151 18.821124666
+7.677419355 5.645161290 12.784673825 14.439131521 19.073000135
+7.677419355 5.935483871 13.714623381 14.815969959 19.357395690
+7.677419355 6.225806452 14.778744019 15.350155064 19.645850060
+7.677419355 6.516129032 15.883198672 16.075414380 19.878699414
+7.677419355 6.806451613 16.909538446 16.932414748 19.986611801
+7.677419355 7.096774194 17.500000000 17.500000000 20.000000000
+7.677419355 7.387096774 17.500000000 17.500000000 20.000000000
+7.677419355 7.677419355 17.500000000 17.500000000 20.000000000
+7.677419355 7.967741935 17.500000000 17.500000000 20.000000000
+7.677419355 8.258064516 17.500000000 17.500000000 20.000000000
+7.677419355 8.548387097 17.500000000 17.500000000 20.000000000
+7.677419355 8.838709677 17.500000000 17.500000000 20.000000000
+7.677419355 9.129032258 17.500000000 17.500000000 20.000000000
+7.677419355 9.419354839 17.500000000 17.500000000 20.000000000
+7.677419355 9.709677419 17.500000000 17.500000000 20.000000000
+7.677419355 10.000000000 17.500000000 17.500000000 20.000000000
+7.967741935 1.000000000 10.000000000 13.750000000 18.750000000
+7.967741935 1.290322581 10.000000000 13.750000000 18.750000000
+7.967741935 1.580645161 10.000000000 13.750000000 18.750000000
+7.967741935 1.870967742 10.000000000 13.750000000 18.750000000
+7.967741935 2.161290323 10.000000000 13.750000000 18.750000000
+7.967741935 2.451612903 10.000000000 13.750000000 18.750000000
+7.967741935 2.741935484 10.000000000 13.750000000 18.750000000
+7.967741935 3.032258065 10.010142154 13.742536520 18.737455859
+7.967741935 3.322580645 10.107593677 13.684557246 18.630423796
+7.967741935 3.612903226 10.219378581 13.645030600 18.537086952
+7.967741935 3.903225806 10.352768137 13.627557695 18.463319088
+7.967741935 4.193548387 10.519625429 13.637427439 18.417599484
+7.967741935 4.483870968 10.738408418 13.682818578 18.412535791
+7.967741935 4.774193548 11.037217342 13.777278068 18.467583744
+7.967741935 5.064516129 11.457663040 13.943032824 18.612009655
+7.967741935 5.354838710 12.032834518 14.162291151 18.821124666
+7.967741935 5.645161290 12.784673825 14.439131521 19.073000135
+7.967741935 5.935483871 13.714623381 14.815969959 19.357395690
+7.967741935 6.225806452 14.778744019 15.350155064 19.645850060
+7.967741935 6.516129032 15.883198672 16.075414380 19.878699414
+7.967741935 6.806451613 16.909538446 16.932414748 19.986611801
+7.967741935 7.096774194 17.500000000 17.500000000 20.000000000
+7.967741935 7.387096774 17.500000000 17.500000000 20.000000000
+7.967741935 7.677419355 17.500000000 17.500000000 20.000000000
+7.967741935 7.967741935 17.500000000 17.500000000 20.000000000
+7.967741935 8.258064516 17.500000000 17.500000000 20.000000000
+7.967741935 8.548387097 17.500000000 17.500000000 20.000000000
+7.967741935 8.838709677 17.500000000 17.500000000 20.000000000
+7.967741935 9.129032258 17.500000000 17.500000000 20.000000000
+7.967741935 9.419354839 17.500000000 17.500000000 20.000000000
+7.967741935 9.709677419 17.500000000 17.500000000 20.000000000
+7.967741935 10.000000000 17.500000000 17.500000000 20.000000000
+8.258064516 1.000000000 10.000000000 13.750000000 18.750000000
+8.258064516 1.290322581 10.000000000 13.750000000 18.750000000
+8.258064516 1.580645161 10.000000000 13.750000000 18.750000000
+8.258064516 1.870967742 10.000000000 13.750000000 18.750000000
+8.258064516 2.161290323 10.000000000 13.750000000 18.750000000
+8.258064516 2.451612903 10.000000000 13.750000000 18.750000000
+8.258064516 2.741935484 10.000000000 13.750000000 18.750000000
+8.258064516 3.032258065 10.010142154 13.742536520 18.737455859
+8.258064516 3.322580645 10.107593677 13.684557246 18.630423796
+8.258064516 3.612903226 10.219378581 13.645030600 18.537086952
+8.258064516 3.903225806 10.352768137 13.627557695 18.463319088
+8.258064516 4.193548387 10.519625429 13.637427439 18.417599484
+8.258064516 4.483870968 10.738408418 13.682818578 18.412535791
+8.258064516 4.774193548 11.037217342 13.777278068 18.467583744
+8.258064516 5.064516129 11.457663040 13.943032824 18.612009655
+8.258064516 5.354838710 12.032834518 14.162291151 18.821124666
+8.258064516 5.645161290 12.784673825 14.439131521 19.073000135
+8.258064516 5.935483871 13.714623381 14.815969959 19.357395690
+8.258064516 6.225806452 14.778744019 15.350155064 19.645850060
+8.258064516 6.516129032 15.883198672 16.075414380 19.878699414
+8.258064516 6.806451613 16.909538446 16.932414748 19.986611801
+8.258064516 7.096774194 17.500000000 17.500000000 20.000000000
+8.258064516 7.387096774 17.500000000 17.500000000 20.000000000
+8.258064516 7.677419355 17.500000000 17.500000000 20.000000000
+8.258064516 7.967741935 17.500000000 17.500000000 20.000000000
+8.258064516 8.258064516 17.500000000 17.500000000 20.000000000
+8.258064516 8.548387097 17.500000000 17.500000000 20.000000000
+8.258064516 8.838709677 17.500000000 17.500000000 20.000000000
+8.258064516 9.129032258 17.500000000 17.500000000 20.000000000
+8.258064516 9.419354839 17.500000000 17.500000000 20.000000000
+8.258064516 9.709677419 17.500000000 17.500000000 20.000000000
+8.258064516 10.000000000 17.500000000 17.500000000 20.000000000
+8.548387097 1.000000000 10.000000000 13.750000000 18.750000000
+8.548387097 1.290322581 10.000000000 13.750000000 18.750000000
+8.548387097 1.580645161 10.000000000 13.750000000 18.750000000
+8.548387097 1.870967742 10.000000000 13.750000000 18.750000000
+8.548387097 2.161290323 10.000000000 13.750000000 18.750000000
+8.548387097 2.451612903 10.000000000 13.750000000 18.750000000
+8.548387097 2.741935484 10.000000000 13.750000000 18.750000000
+8.548387097 3.032258065 10.010142154 13.742536520 18.737455859
+8.548387097 3.322580645 10.107593677 13.684557246 18.630423796
+8.548387097 3.612903226 10.219378581 13.645030600 18.537086952
+8.548387097 3.903225806 10.352768137 13.627557695 18.463319088
+8.548387097 4.193548387 10.519625429 13.637427439 18.417599484
+8.548387097 4.483870968 10.738408418 13.682818578 18.412535791
+8.548387097 4.774193548 11.037217342 13.777278068 18.467583744
+8.548387097 5.064516129 11.457663040 13.943032824 18.612009655
+8.548387097 5.354838710 12.032834518 14.162291151 18.821124666
+8.548387097 5.645161290 12.784673825 14.439131521 19.073000135
+8.548387097 5.935483871 13.714623381 14.815969959 19.357395690
+8.548387097 6.225806452 14.778744019 15.350155064 19.645850060
+8.548387097 6.516129032 15.883198672 16.075414380 19.878699414
+8.548387097 6.806451613 16.909538446 16.932414748 19.986611801
+8.548387097 7.096774194 17.500000000 17.500000000 20.000000000
+8.548387097 7.387096774 17.500000000 17.500000000 20.000000000
+8.548387097 7.677419355 17.500000000 17.500000000 20.000000000
+8.548387097 7.967741935 17.500000000 17.500000000 20.000000000
+8.548387097 8.258064516 17.500000000 17.500000000 20.000000000
+8.548387097 8.548387097 17.500000000 17.500000000 20.000000000
+8.548387097 8.838709677 17.500000000 17.500000000 20.000000000
+8.548387097 9.129032258 17.500000000 17.500000000 20.000000000
+8.548387097 9.419354839 17.500000000 17.500000000 20.000000000
+8.548387097 9.709677419 17.500000000 17.500000000 20.000000000
+8.548387097 10.000000000 17.500000000 17.500000000 20.000000000
+8.838709677 1.000000000 10.000000000 13.750000000 18.750000000
+8.838709677 1.290322581 10.000000000 13.750000000 18.750000000
+8.838709677 1.580645161 10.000000000 13.750000000 18.750000000
+8.838709677 1.870967742 10.000000000 13.750000000 18.750000000
+8.838709677 2.161290323 10.000000000 13.750000000 18.750000000
+8.838709677 2.451612903 10.000000000 13.750000000 18.750000000
+8.838709677 2.741935484 10.000000000 13.750000000 18.750000000
+8.838709677 3.032258065 10.010142154 13.742536520 18.737455859
+8.838709677 3.322580645 10.107593677 13.684557246 18.630423796
+8.838709677 3.612903226 10.219378581 13.645030600 18.537086952
+8.838709677 3.903225806 10.352768137 13.627557695 18.463319088
+8.838709677 4.193548387 10.519625429 13.637427439 18.417599484
+8.838709677 4.483870968 10.738408418 13.682818578 18.412535791
+8.838709677 4.774193548 11.037217342 13.777278068 18.467583744
+8.838709677 5.064516129 11.457663040 13.943032824 18.612009655
+8.838709677 5.354838710 12.032834518 14.162291151 18.821124666
+8.838709677 5.645161290 12.784673825 14.439131521 19.073000135
+8.838709677 5.935483871 13.714623381 14.815969959 19.357395690
+8.838709677 6.225806452 14.778744019 15.350155064 19.645850060
+8.838709677 6.516129032 15.883198672 16.075414380 19.878699414
+8.838709677 6.806451613 16.909538446 16.932414748 19.986611801
+8.838709677 7.096774194 17.500000000 17.500000000 20.000000000
+8.838709677 7.387096774 17.500000000 17.500000000 20.000000000
+8.838709677 7.677419355 17.500000000 17.500000000 20.000000000
+8.838709677 7.967741935 17.500000000 17.500000000 20.000000000
+8.838709677 8.258064516 17.500000000 17.500000000 20.000000000
+8.838709677 8.548387097 17.500000000 17.500000000 20.000000000
+8.838709677 8.838709677 17.500000000 17.500000000 20.000000000
+8.838709677 9.129032258 17.500000000 17.500000000 20.000000000
+8.838709677 9.419354839 17.500000000 17.500000000 20.000000000
+8.838709677 9.709677419 17.500000000 17.500000000 20.000000000
+8.838709677 10.000000000 17.500000000 17.500000000 20.000000000
+9.129032258 1.000000000 10.000000000 13.750000000 18.750000000
+9.129032258 1.290322581 10.000000000 13.750000000 18.750000000
+9.129032258 1.580645161 10.000000000 13.750000000 18.750000000
+9.129032258 1.870967742 10.000000000 13.750000000 18.750000000
+9.129032258 2.161290323 10.000000000 13.750000000 18.750000000
+9.129032258 2.451612903 10.000000000 13.750000000 18.750000000
+9.129032258 2.741935484 10.000000000 13.750000000 18.750000000
+9.129032258 3.032258065 10.010142154 13.742536520 18.737455859
+9.129032258 3.322580645 10.107593677 13.684557246 18.630423796
+9.129032258 3.612903226 10.219378581 13.645030600 18.537086952
+9.129032258 3.903225806 10.352768137 13.627557695 18.463319088
+9.129032258 4.193548387 10.519625429 13.637427439 18.417599484
+9.129032258 4.483870968 10.738408418 13.682818578 18.412535791
+9.129032258 4.774193548 11.037217342 13.777278068 18.467583744
+9.129032258 5.064516129 11.457663040 13.943032824 18.612009655
+9.129032258 5.354838710 12.032834518 14.162291151 18.821124666
+9.129032258 5.645161290 12.784673825 14.439131521 19.073000135
+9.129032258 5.935483871 13.714623381 14.815969959 19.357395690
+9.129032258 6.225806452 14.778744019 15.350155064 19.645850060
+9.129032258 6.516129032 15.883198672 16.075414380 19.878699414
+9.129032258 6.806451613 16.909538446 16.932414748 19.986611801
+9.129032258 7.096774194 17.500000000 17.500000000 20.000000000
+9.129032258 7.387096774 17.500000000 17.500000000 20.000000000
+9.129032258 7.677419355 17.500000000 17.500000000 20.000000000
+9.129032258 7.967741935 17.500000000 17.500000000 20.000000000
+9.129032258 8.258064516 17.500000000 17.500000000 20.000000000
+9.129032258 8.548387097 17.500000000 17.500000000 20.000000000
+9.129032258 8.838709677 17.500000000 17.500000000 20.000000000
+9.129032258 9.129032258 17.500000000 17.500000000 20.000000000
+9.129032258 9.419354839 17.500000000 17.500000000 20.000000000
+9.129032258 9.709677419 17.500000000 17.500000000 20.000000000
+9.129032258 10.000000000 17.500000000 17.500000000 20.000000000
+9.419354839 1.000000000 10.000000000 13.750000000 18.750000000
+9.419354839 1.290322581 10.000000000 13.750000000 18.750000000
+9.419354839 1.580645161 10.000000000 13.750000000 18.750000000
+9.419354839 1.870967742 10.000000000 13.750000000 18.750000000
+9.419354839 2.161290323 10.000000000 13.750000000 18.750000000
+9.419354839 2.451612903 10.000000000 13.750000000 18.750000000
+9.419354839 2.741935484 10.000000000 13.750000000 18.750000000
+9.419354839 3.032258065 10.010142154 13.742536520 18.737455859
+9.419354839 3.322580645 10.107593677 13.684557246 18.630423796
+9.419354839 3.612903226 10.219378581 13.645030600 18.537086952
+9.419354839 3.903225806 10.352768137 13.627557695 18.463319088
+9.419354839 4.193548387 10.519625429 13.637427439 18.417599484
+9.419354839 4.483870968 10.738408418 13.682818578 18.412535791
+9.419354839 4.774193548 11.037217342 13.777278068 18.467583744
+9.419354839 5.064516129 11.457663040 13.943032824 18.612009655
+9.419354839 5.354838710 12.032834518 14.162291151 18.821124666
+9.419354839 5.645161290 12.784673825 14.439131521 19.073000135
+9.419354839 5.935483871 13.714623381 14.815969959 19.357395690
+9.419354839 6.225806452 14.778744019 15.350155064 19.645850060
+9.419354839 6.516129032 15.883198672 16.075414380 19.878699414
+9.419354839 6.806451613 16.909538446 16.932414748 19.986611801
+9.419354839 7.096774194 17.500000000 17.500000000 20.000000000
+9.419354839 7.387096774 17.500000000 17.500000000 20.000000000
+9.419354839 7.677419355 17.500000000 17.500000000 20.000000000
+9.419354839 7.967741935 17.500000000 17.500000000 20.000000000
+9.419354839 8.258064516 17.500000000 17.500000000 20.000000000
+9.419354839 8.548387097 17.500000000 17.500000000 20.000000000
+9.419354839 8.838709677 17.500000000 17.500000000 20.000000000
+9.419354839 9.129032258 17.500000000 17.500000000 20.000000000
+9.419354839 9.419354839 17.500000000 17.500000000 20.000000000
+9.419354839 9.709677419 17.500000000 17.500000000 20.000000000
+9.419354839 10.000000000 17.500000000 17.500000000 20.000000000
+9.709677419 1.000000000 10.000000000 13.750000000 18.750000000
+9.709677419 1.290322581 10.000000000 13.750000000 18.750000000
+9.709677419 1.580645161 10.000000000 13.750000000 18.750000000
+9.709677419 1.870967742 10.000000000 13.750000000 18.750000000
+9.709677419 2.161290323 10.000000000 13.750000000 18.750000000
+9.709677419 2.451612903 10.000000000 13.750000000 18.750000000
+9.709677419 2.741935484 10.000000000 13.750000000 18.750000000
+9.709677419 3.032258065 10.010142154 13.742536520 18.737455859
+9.709677419 3.322580645 10.107593677 13.684557246 18.630423796
+9.709677419 3.612903226 10.219378581 13.645030600 18.537086952
+9.709677419 3.903225806 10.352768137 13.627557695 18.463319088
+9.709677419 4.193548387 10.519625429 13.637427439 18.417599484
+9.709677419 4.483870968 10.738408418 13.682818578 18.412535791
+9.709677419 4.774193548 11.037217342 13.777278068 18.467583744
+9.709677419 5.064516129 11.457663040 13.943032824 18.612009655
+9.709677419 5.354838710 12.032834518 14.162291151 18.821124666
+9.709677419 5.645161290 12.784673825 14.439131521 19.073000135
+9.709677419 5.935483871 13.714623381 14.815969959 19.357395690
+9.709677419 6.225806452 14.778744019 15.350155064 19.645850060
+9.709677419 6.516129032 15.883198672 16.075414380 19.878699414
+9.709677419 6.806451613 16.909538446 16.932414748 19.986611801
+9.709677419 7.096774194 17.500000000 17.500000000 20.000000000
+9.709677419 7.387096774 17.500000000 17.500000000 20.000000000
+9.709677419 7.677419355 17.500000000 17.500000000 20.000000000
+9.709677419 7.967741935 17.500000000 17.500000000 20.000000000
+9.709677419 8.258064516 17.500000000 17.500000000 20.000000000
+9.709677419 8.548387097 17.500000000 17.500000000 20.000000000
+9.709677419 8.838709677 17.500000000 17.500000000 20.000000000
+9.709677419 9.129032258 17.500000000 17.500000000 20.000000000
+9.709677419 9.419354839 17.500000000 17.500000000 20.000000000
+9.709677419 9.709677419 17.500000000 17.500000000 20.000000000
+9.709677419 10.000000000 17.500000000 17.500000000 20.000000000
+10.000000000 1.000000000 10.000000000 13.750000000 18.750000000
+10.000000000 1.290322581 10.000000000 13.750000000 18.750000000
+10.000000000 1.580645161 10.000000000 13.750000000 18.750000000
+10.000000000 1.870967742 10.000000000 13.750000000 18.750000000
+10.000000000 2.161290323 10.000000000 13.750000000 18.750000000
+10.000000000 2.451612903 10.000000000 13.750000000 18.750000000
+10.000000000 2.741935484 10.000000000 13.750000000 18.750000000
+10.000000000 3.032258065 10.010142154 13.742536520 18.737455859
+10.000000000 3.322580645 10.107593677 13.684557246 18.630423796
+10.000000000 3.612903226 10.219378581 13.645030600 18.537086952
+10.000000000 3.903225806 10.352768137 13.627557695 18.463319088
+10.000000000 4.193548387 10.519625429 13.637427439 18.417599484
+10.000000000 4.483870968 10.738408418 13.682818578 18.412535791
+10.000000000 4.774193548 11.037217342 13.777278068 18.467583744
+10.000000000 5.064516129 11.457663040 13.943032824 18.612009655
+10.000000000 5.354838710 12.032834518 14.162291151 18.821124666
+10.000000000 5.645161290 12.784673825 14.439131521 19.073000135
+10.000000000 5.935483871 13.714623381 14.815969959 19.357395690
+10.000000000 6.225806452 14.778744019 15.350155064 19.645850060
+10.000000000 6.516129032 15.883198672 16.075414380 19.878699414
+10.000000000 6.806451613 16.909538446 16.932414748 19.986611801
+10.000000000 7.096774194 17.500000000 17.500000000 20.000000000
+10.000000000 7.387096774 17.500000000 17.500000000 20.000000000
+10.000000000 7.677419355 17.500000000 17.500000000 20.000000000
+10.000000000 7.967741935 17.500000000 17.500000000 20.000000000
+10.000000000 8.258064516 17.500000000 17.500000000 20.000000000
+10.000000000 8.548387097 17.500000000 17.500000000 20.000000000
+10.000000000 8.838709677 17.500000000 17.500000000 20.000000000
+10.000000000 9.129032258 17.500000000 17.500000000 20.000000000
+10.000000000 9.419354839 17.500000000 17.500000000 20.000000000
+10.000000000 9.709677419 17.500000000 17.500000000 20.000000000
+10.000000000 10.000000000 17.500000000 17.500000000 20.000000000
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.fll b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fll
new file mode 100644
index 0000000..1b51806
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.fll
@@ -0,0 +1,62 @@
+Engine: sugeno_tip_calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: CheapTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: AverageTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: GenerousTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low
+ rule: if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High \ No newline at end of file
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.java b/examples/takagi-sugeno/octave/sugeno_tip_calculator.java
new file mode 100644
index 0000000..d64e722
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.java
@@ -0,0 +1,109 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class sugeno_tip_calculator{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("sugeno_tip_calculator");
+engine.setDescription("");
+
+InputVariable FoodQuality = new InputVariable();
+FoodQuality.setName("FoodQuality");
+FoodQuality.setDescription("");
+FoodQuality.setEnabled(true);
+FoodQuality.setRange(1.000, 10.000);
+FoodQuality.setLockValueInRange(false);
+FoodQuality.addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+FoodQuality.addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine.addInputVariable(FoodQuality);
+
+InputVariable Service = new InputVariable();
+Service.setName("Service");
+Service.setDescription("");
+Service.setEnabled(true);
+Service.setRange(1.000, 10.000);
+Service.setLockValueInRange(false);
+Service.addTerm(new Trapezoid("Bad", 0.000, 1.000, 3.000, 7.000));
+Service.addTerm(new Trapezoid("Good", 3.000, 7.000, 10.000, 11.000));
+engine.addInputVariable(Service);
+
+OutputVariable CheapTip = new OutputVariable();
+CheapTip.setName("CheapTip");
+CheapTip.setDescription("");
+CheapTip.setEnabled(true);
+CheapTip.setRange(5.000, 25.000);
+CheapTip.setLockValueInRange(false);
+CheapTip.setAggregation(null);
+CheapTip.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+CheapTip.setDefaultValue(Double.NaN);
+CheapTip.setLockPreviousValue(false);
+CheapTip.addTerm(new Constant("Low", 10.000));
+CheapTip.addTerm(new Constant("Medium", 15.000));
+CheapTip.addTerm(new Constant("High", 20.000));
+engine.addOutputVariable(CheapTip);
+
+OutputVariable AverageTip = new OutputVariable();
+AverageTip.setName("AverageTip");
+AverageTip.setDescription("");
+AverageTip.setEnabled(true);
+AverageTip.setRange(5.000, 25.000);
+AverageTip.setLockValueInRange(false);
+AverageTip.setAggregation(null);
+AverageTip.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+AverageTip.setDefaultValue(Double.NaN);
+AverageTip.setLockPreviousValue(false);
+AverageTip.addTerm(new Constant("Low", 10.000));
+AverageTip.addTerm(new Constant("Medium", 15.000));
+AverageTip.addTerm(new Constant("High", 20.000));
+engine.addOutputVariable(AverageTip);
+
+OutputVariable GenerousTip = new OutputVariable();
+GenerousTip.setName("GenerousTip");
+GenerousTip.setDescription("");
+GenerousTip.setEnabled(true);
+GenerousTip.setRange(5.000, 25.000);
+GenerousTip.setLockValueInRange(false);
+GenerousTip.setAggregation(null);
+GenerousTip.setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+GenerousTip.setDefaultValue(Double.NaN);
+GenerousTip.setLockPreviousValue(false);
+GenerousTip.addTerm(new Constant("Low", 10.000));
+GenerousTip.addTerm(new Constant("Medium", 15.000));
+GenerousTip.addTerm(new Constant("High", 20.000));
+engine.addOutputVariable(GenerousTip);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(new EinsteinProduct());
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High", engine));
+ruleBlock.addRule(Rule.parse("if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/takagi-sugeno/octave/sugeno_tip_calculator.pdf b/examples/takagi-sugeno/octave/sugeno_tip_calculator.pdf
new file mode 100644
index 0000000..f138223
--- /dev/null
+++ b/examples/takagi-sugeno/octave/sugeno_tip_calculator.pdf
Binary files differ
diff --git a/examples/tsukamoto/tsukamoto.R b/examples/tsukamoto/tsukamoto.R
new file mode 100644
index 0000000..51fbdd4
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.R
@@ -0,0 +1,126 @@
+#Code automatically generated with fuzzylite 6.0.
+
+library(ggplot2);
+
+engine.name = "tsukamoto"
+engine.fll = "Engine: tsukamoto
+InputVariable: X
+ enabled: true
+ range: -10.000 10.000
+ lock-range: false
+ term: small Bell -10.000 5.000 3.000
+ term: medium Bell 0.000 5.000 3.000
+ term: large Bell 10.000 5.000 3.000
+OutputVariable: Ramps
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b Ramp 0.600 0.400
+ term: a Ramp 0.000 0.250
+ term: c Ramp 0.700 1.000
+OutputVariable: Sigmoids
+ enabled: true
+ range: 0.020 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b Sigmoid 0.500 -30.000
+ term: a Sigmoid 0.130 30.000
+ term: c Sigmoid 0.830 30.000
+OutputVariable: ZSShapes
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b ZShape 0.300 0.600
+ term: a SShape 0.000 0.250
+ term: c SShape 0.700 1.000
+OutputVariable: Concaves
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b Concave 0.500 0.400
+ term: a Concave 0.240 0.250
+ term: c Concave 0.900 1.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if X is small then Ramps is a and Sigmoids is a and ZSShapes is a and Concaves is a
+ rule: if X is medium then Ramps is b and Sigmoids is b and ZSShapes is b and Concaves is b
+ rule: if X is large then Ramps is c and Sigmoids is c and ZSShapes is c and Concaves is c"
+
+engine.fldFile = "tsukamoto.fld"
+if (require(data.table)) {
+ engine.df = data.table::fread(engine.fldFile, sep="auto", header="auto")
+} else {
+ engine.df = read.table(engine.fldFile, header=TRUE)
+}
+
+engine.plot.i1_o1 = ggplot(engine.df, aes(X, Ramps)) +
+ geom_line(aes(color=Ramps), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("X vs Ramps")
+
+engine.plot.o1_i1 = ggplot(engine.df, aes(X, Ramps)) +
+ geom_line(aes(color=Ramps), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Ramps vs X")
+
+engine.plot.i1_o2 = ggplot(engine.df, aes(X, Sigmoids)) +
+ geom_line(aes(color=Sigmoids), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("X vs Sigmoids")
+
+engine.plot.o2_i1 = ggplot(engine.df, aes(X, Sigmoids)) +
+ geom_line(aes(color=Sigmoids), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Sigmoids vs X")
+
+engine.plot.i1_o3 = ggplot(engine.df, aes(X, ZSShapes)) +
+ geom_line(aes(color=ZSShapes), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("X vs ZSShapes")
+
+engine.plot.o3_i1 = ggplot(engine.df, aes(X, ZSShapes)) +
+ geom_line(aes(color=ZSShapes), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("ZSShapes vs X")
+
+engine.plot.i1_o4 = ggplot(engine.df, aes(X, Concaves)) +
+ geom_line(aes(color=Concaves), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ ggtitle("X vs Concaves")
+
+engine.plot.o4_i1 = ggplot(engine.df, aes(X, Concaves)) +
+ geom_line(aes(color=Concaves), size=3, lineend="round", linejoin="mitre") +
+ scale_color_gradient(low="yellow", high="red") +
+ coord_flip() +
+ ggtitle("Concaves vs X")
+
+if (require(gridExtra)) {
+ engine.plots = arrangeGrob(engine.plot.i1_o1, engine.plot.o1_i1, engine.plot.i1_o2, engine.plot.o2_i1, engine.plot.i1_o3, engine.plot.o3_i1, engine.plot.i1_o4, engine.plot.o4_i1, ncol=2, top=engine.name)
+ ggsave(paste0(engine.name, ".pdf"), engine.plots)
+ if (require(grid)) {
+ grid.newpage()
+ grid.draw(engine.plots)
+ }
+}
diff --git a/examples/tsukamoto/tsukamoto.cpp b/examples/tsukamoto/tsukamoto.cpp
new file mode 100644
index 0000000..a50c53d
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.cpp
@@ -0,0 +1,97 @@
+#include <fl/Headers.h>
+
+int main(int argc, char** argv){
+//Code automatically generated with fuzzylite 6.0.
+
+using namespace fl;
+
+Engine* engine = new Engine;
+engine->setName("tsukamoto");
+engine->setDescription("");
+
+InputVariable* X = new InputVariable;
+X->setName("X");
+X->setDescription("");
+X->setEnabled(true);
+X->setRange(-10.000, 10.000);
+X->setLockValueInRange(false);
+X->addTerm(new Bell("small", -10.000, 5.000, 3.000));
+X->addTerm(new Bell("medium", 0.000, 5.000, 3.000));
+X->addTerm(new Bell("large", 10.000, 5.000, 3.000));
+engine->addInputVariable(X);
+
+OutputVariable* Ramps = new OutputVariable;
+Ramps->setName("Ramps");
+Ramps->setDescription("");
+Ramps->setEnabled(true);
+Ramps->setRange(0.000, 1.000);
+Ramps->setLockValueInRange(false);
+Ramps->setAggregation(fl::null);
+Ramps->setDefuzzifier(new WeightedAverage("Automatic"));
+Ramps->setDefaultValue(fl::nan);
+Ramps->setLockPreviousValue(false);
+Ramps->addTerm(new Ramp("b", 0.600, 0.400));
+Ramps->addTerm(new Ramp("a", 0.000, 0.250));
+Ramps->addTerm(new Ramp("c", 0.700, 1.000));
+engine->addOutputVariable(Ramps);
+
+OutputVariable* Sigmoids = new OutputVariable;
+Sigmoids->setName("Sigmoids");
+Sigmoids->setDescription("");
+Sigmoids->setEnabled(true);
+Sigmoids->setRange(0.020, 1.000);
+Sigmoids->setLockValueInRange(false);
+Sigmoids->setAggregation(fl::null);
+Sigmoids->setDefuzzifier(new WeightedAverage("Automatic"));
+Sigmoids->setDefaultValue(fl::nan);
+Sigmoids->setLockPreviousValue(false);
+Sigmoids->addTerm(new Sigmoid("b", 0.500, -30.000));
+Sigmoids->addTerm(new Sigmoid("a", 0.130, 30.000));
+Sigmoids->addTerm(new Sigmoid("c", 0.830, 30.000));
+engine->addOutputVariable(Sigmoids);
+
+OutputVariable* ZSShapes = new OutputVariable;
+ZSShapes->setName("ZSShapes");
+ZSShapes->setDescription("");
+ZSShapes->setEnabled(true);
+ZSShapes->setRange(0.000, 1.000);
+ZSShapes->setLockValueInRange(false);
+ZSShapes->setAggregation(fl::null);
+ZSShapes->setDefuzzifier(new WeightedAverage("Automatic"));
+ZSShapes->setDefaultValue(fl::nan);
+ZSShapes->setLockPreviousValue(false);
+ZSShapes->addTerm(new ZShape("b", 0.300, 0.600));
+ZSShapes->addTerm(new SShape("a", 0.000, 0.250));
+ZSShapes->addTerm(new SShape("c", 0.700, 1.000));
+engine->addOutputVariable(ZSShapes);
+
+OutputVariable* Concaves = new OutputVariable;
+Concaves->setName("Concaves");
+Concaves->setDescription("");
+Concaves->setEnabled(true);
+Concaves->setRange(0.000, 1.000);
+Concaves->setLockValueInRange(false);
+Concaves->setAggregation(fl::null);
+Concaves->setDefuzzifier(new WeightedAverage("Automatic"));
+Concaves->setDefaultValue(fl::nan);
+Concaves->setLockPreviousValue(false);
+Concaves->addTerm(new Concave("b", 0.500, 0.400));
+Concaves->addTerm(new Concave("a", 0.240, 0.250));
+Concaves->addTerm(new Concave("c", 0.900, 1.000));
+engine->addOutputVariable(Concaves);
+
+RuleBlock* ruleBlock = new RuleBlock;
+ruleBlock->setName("");
+ruleBlock->setDescription("");
+ruleBlock->setEnabled(true);
+ruleBlock->setConjunction(fl::null);
+ruleBlock->setDisjunction(fl::null);
+ruleBlock->setImplication(fl::null);
+ruleBlock->setActivation(new General);
+ruleBlock->addRule(Rule::parse("if X is small then Ramps is a and Sigmoids is a and ZSShapes is a and Concaves is a", engine));
+ruleBlock->addRule(Rule::parse("if X is medium then Ramps is b and Sigmoids is b and ZSShapes is b and Concaves is b", engine));
+ruleBlock->addRule(Rule::parse("if X is large then Ramps is c and Sigmoids is c and ZSShapes is c and Concaves is c", engine));
+engine->addRuleBlock(ruleBlock);
+
+
+}
diff --git a/examples/tsukamoto/tsukamoto.fcl b/examples/tsukamoto/tsukamoto.fcl
new file mode 100644
index 0000000..b26fc60
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.fcl
@@ -0,0 +1,65 @@
+//Code automatically generated with fuzzylite 6.0.
+
+FUNCTION_BLOCK tsukamoto
+
+VAR_INPUT
+ X: REAL;
+END_VAR
+
+VAR_OUTPUT
+ Ramps: REAL;
+ Sigmoids: REAL;
+ ZSShapes: REAL;
+ Concaves: REAL;
+END_VAR
+
+FUZZIFY X
+ RANGE := (-10.000 .. 10.000);
+ TERM small := Bell -10.000 5.000 3.000;
+ TERM medium := Bell 0.000 5.000 3.000;
+ TERM large := Bell 10.000 5.000 3.000;
+END_FUZZIFY
+
+DEFUZZIFY Ramps
+ RANGE := (0.000 .. 1.000);
+ TERM b := Ramp 0.600 0.400;
+ TERM a := Ramp 0.000 0.250;
+ TERM c := Ramp 0.700 1.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY Sigmoids
+ RANGE := (0.020 .. 1.000);
+ TERM b := Sigmoid 0.500 -30.000;
+ TERM a := Sigmoid 0.130 30.000;
+ TERM c := Sigmoid 0.830 30.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY ZSShapes
+ RANGE := (0.000 .. 1.000);
+ TERM b := ZShape 0.300 0.600;
+ TERM a := SShape 0.000 0.250;
+ TERM c := SShape 0.700 1.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+DEFUZZIFY Concaves
+ RANGE := (0.000 .. 1.000);
+ TERM b := Concave 0.500 0.400;
+ TERM a := Concave 0.240 0.250;
+ TERM c := Concave 0.900 1.000;
+ METHOD : COGS;
+ DEFAULT := nan;
+END_DEFUZZIFY
+
+RULEBLOCK
+ RULE 1 : if X is small then Ramps is a and Sigmoids is a and ZSShapes is a and Concaves is a
+ RULE 2 : if X is medium then Ramps is b and Sigmoids is b and ZSShapes is b and Concaves is b
+ RULE 3 : if X is large then Ramps is c and Sigmoids is c and ZSShapes is c and Concaves is c
+END_RULEBLOCK
+
+END_FUNCTION_BLOCK
diff --git a/examples/tsukamoto/tsukamoto.fis b/examples/tsukamoto/tsukamoto.fis
new file mode 100644
index 0000000..0127bdd
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.fis
@@ -0,0 +1,59 @@
+#Code automatically generated with fuzzylite 6.0.
+
+[System]
+Name='tsukamoto'
+Type='tsukamoto'
+Version=6.0
+NumInputs=1
+NumOutputs=4
+NumRules=3
+AndMethod='min'
+OrMethod='max'
+ImpMethod='min'
+AggMethod='max'
+DefuzzMethod='wtaver'
+
+[Input1]
+Name='X'
+Range=[-10.000 10.000]
+NumMFs=3
+MF1='small':'gbellmf',[5.000 3.000 -10.000]
+MF2='medium':'gbellmf',[5.000 3.000 0.000]
+MF3='large':'gbellmf',[5.000 3.000 10.000]
+
+[Output1]
+Name='Ramps'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='b':'rampmf',[0.600 0.400]
+MF2='a':'rampmf',[0.000 0.250]
+MF3='c':'rampmf',[0.700 1.000]
+
+[Output2]
+Name='Sigmoids'
+Range=[0.020 1.000]
+NumMFs=3
+MF1='b':'sigmf',[-30.000 0.500]
+MF2='a':'sigmf',[30.000 0.130]
+MF3='c':'sigmf',[30.000 0.830]
+
+[Output3]
+Name='ZSShapes'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='b':'zmf',[0.300 0.600]
+MF2='a':'smf',[0.000 0.250]
+MF3='c':'smf',[0.700 1.000]
+
+[Output4]
+Name='Concaves'
+Range=[0.000 1.000]
+NumMFs=3
+MF1='b':'concavemf',[0.500 0.400]
+MF2='a':'concavemf',[0.240 0.250]
+MF3='c':'concavemf',[0.900 1.000]
+
+[Rules]
+1.000 , 2.000 2.000 2.000 2.000 (1.000) : 1
+2.000 , 1.000 1.000 1.000 1.000 (1.000) : 1
+3.000 , 3.000 3.000 3.000 3.000 (1.000) : 1
diff --git a/examples/tsukamoto/tsukamoto.fld b/examples/tsukamoto/tsukamoto.fld
new file mode 100644
index 0000000..a62de71
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.fld
@@ -0,0 +1,1025 @@
+X Ramps Sigmoids ZSShapes Concaves
+-10.000000000 0.255363311 0.994418517 0.255809266 0.252212158
+-9.980449658 0.255423538 0.994349291 0.255877491 0.252237827
+-9.960899316 0.255484536 0.994279093 0.255946708 0.252263834
+-9.941348974 0.255546315 0.994207907 0.256016992 0.252290183
+-9.921798631 0.255608886 0.994135720 0.256088420 0.252316880
+-9.902248289 0.255672260 0.994062515 0.256161070 0.252343930
+-9.882697947 0.255736449 0.993988277 0.256235018 0.252371338
+-9.863147605 0.255801463 0.993912989 0.256310342 0.252399110
+-9.843597263 0.255867314 0.993836635 0.256387118 0.252427249
+-9.824046921 0.255934014 0.993759200 0.256465426 0.252455763
+-9.804496579 0.256001575 0.993680665 0.256545342 0.252484655
+-9.784946237 0.256070009 0.993601014 0.256626945 0.252513932
+-9.765395894 0.256139328 0.993520229 0.256710313 0.252543600
+-9.745845552 0.256209543 0.993438294 0.256795525 0.252573664
+-9.726295210 0.256280668 0.993355189 0.256882659 0.252604130
+-9.706744868 0.256352715 0.993270897 0.256971794 0.252635003
+-9.687194526 0.256425696 0.993185399 0.257063010 0.252666290
+-9.667644184 0.256499625 0.993098676 0.257156386 0.252697997
+-9.648093842 0.256574514 0.993010710 0.257252001 0.252730129
+-9.628543500 0.256650376 0.992921480 0.257349935 0.252762694
+-9.608993157 0.256727223 0.992830967 0.257450269 0.252795698
+-9.589442815 0.256805071 0.992739150 0.257553083 0.252829146
+-9.569892473 0.256883930 0.992646010 0.257658457 0.252863046
+-9.550342131 0.256963815 0.992551525 0.257766473 0.252897404
+-9.530791789 0.257044740 0.992455675 0.257877210 0.252932226
+-9.511241447 0.257126716 0.992358437 0.257990751 0.252967521
+-9.491691105 0.257209759 0.588052019 0.258107177 0.253003294
+-9.472140762 0.257293880 0.580664022 0.258226570 0.253039553
+-9.452590420 0.257379094 0.573548403 0.258349012 0.253076305
+-9.433040078 0.257465414 0.566686170 0.258474586 0.253113557
+-9.413489736 0.257552853 0.560060263 0.258603373 0.253151317
+-9.393939394 0.257641426 0.553655304 0.258735458 0.253189591
+-9.374389052 0.257731144 0.547457382 0.258870922 0.253228389
+-9.354838710 0.257822021 0.541453869 0.259009850 0.253267717
+-9.335288368 0.257914071 0.535633273 0.259152325 0.253307584
+-9.315738025 0.258007306 0.529985101 0.259298431 0.253347997
+-9.296187683 0.258101740 0.524499751 0.259448253 0.253388965
+-9.276637341 0.258197385 0.519168409 0.259601875 0.253430495
+-9.257086999 0.258294254 0.513982971 0.259759382 0.253472597
+-9.237536657 0.258392360 0.508935965 0.259920859 0.253515278
+-9.217986315 0.258491714 0.504020487 0.260086393 0.253558549
+-9.198435973 0.258592329 0.499230149 0.260256068 0.253602416
+-9.178885630 0.258694217 0.494559024 0.260429971 0.253646889
+-9.159335288 0.258797390 0.490001608 0.260608188 0.253691978
+-9.139784946 0.258901859 0.485552776 0.260790807 0.253737692
+-9.120234604 0.259007634 0.481207751 0.260977914 0.253784039
+-9.100684262 0.259114728 0.476962075 0.261169597 0.253831030
+-9.081133920 0.259223150 0.472811577 0.261365945 0.253878674
+-9.061583578 0.259332910 0.468752351 0.261567044 0.253926982
+-9.042033236 0.259444019 0.464780737 0.261772983 0.253975962
+-9.022482893 0.259556486 0.460893297 0.261983853 0.254025626
+-9.002932551 0.259670319 0.457086800 0.262199741 0.254075983
+-8.983382209 0.259785527 0.453358204 0.262420737 0.254127045
+-8.963831867 0.259902119 0.449704644 0.262646932 0.254178821
+-8.944281525 0.260020101 0.446123417 0.262878416 0.254231324
+-8.924731183 0.260139481 0.442611971 0.263115280 0.254284563
+-8.905180841 0.260260266 0.439167894 0.263357615 0.254338550
+-8.885630499 0.260382462 0.435788903 0.263605512 0.254393298
+-8.866080156 0.260506073 0.432472838 0.263859064 0.254448816
+-8.846529814 0.260631104 0.429217651 0.264118363 0.254505117
+-8.826979472 0.260757561 0.426021398 0.264383501 0.254562214
+-8.807429130 0.260885446 0.422882236 0.264654573 0.254620118
+-8.787878788 0.261014762 0.419798412 0.264931671 0.254678842
+-8.768328446 0.261145511 0.416768259 0.265214890 0.254738398
+-8.748778104 0.261277695 0.413790193 0.265504324 0.254798800
+-8.729227761 0.261411313 0.410862703 0.265800069 0.254860061
+-8.709677419 0.261546367 0.407984352 0.266102219 0.254922193
+-8.690127077 0.261682855 0.405153768 0.266410871 0.254985212
+-8.670576735 0.261820774 0.402369643 0.266726120 0.255049129
+-8.651026393 0.261960123 0.399630729 0.267048064 0.255113960
+-8.631476051 0.262100897 0.396935833 0.267376801 0.255179719
+-8.611925709 0.262243093 0.394283815 0.267712426 0.255246420
+-8.592375367 0.262386704 0.391673585 0.268055040 0.255314078
+-8.572825024 0.262531724 0.389104103 0.268404740 0.255382709
+-8.553274682 0.262678146 0.386574370 0.268761626 0.255452328
+-8.533724340 0.262825961 0.384083432 0.269125797 0.255522950
+-8.514173998 0.262975160 0.381630374 0.269497353 0.255594592
+-8.494623656 0.263125731 0.379214319 0.269876396 0.255667269
+-8.475073314 0.263277664 0.376834428 0.270263026 0.255740998
+-8.455522972 0.263430945 0.374489895 0.270657345 0.255815797
+-8.435972630 0.263585560 0.372179948 0.271059456 0.255891682
+-8.416422287 0.263741495 0.369903845 0.271469460 0.255968670
+-8.396871945 0.263898732 0.367660875 0.271887462 0.256046780
+-8.377321603 0.264057254 0.365450354 0.272313565 0.256126030
+-8.357771261 0.264217043 0.363271626 0.272747873 0.256206439
+-8.338220919 0.264378078 0.361124062 0.273190492 0.256288024
+-8.318670577 0.264540339 0.359007055 0.273641526 0.256370806
+-8.299120235 0.264703801 0.356920024 0.274101082 0.256454804
+-8.279569892 0.264868442 0.354862409 0.274569267 0.256540038
+-8.260019550 0.265034236 0.352833675 0.275046187 0.256626528
+-8.240469208 0.265201156 0.350833302 0.275531949 0.256714295
+-8.220918866 0.265369175 0.348860796 0.276026663 0.256803360
+-8.201368524 0.265538263 0.346915677 0.276530437 0.256893746
+-8.181818182 0.265708390 0.344997488 0.277043381 0.256985473
+-8.162267840 0.265879523 0.343105787 0.277565603 0.257078564
+-8.142717498 0.266051628 0.341240148 0.278097216 0.257173043
+-8.123167155 0.266224672 0.339400163 0.278638329 0.257268931
+-8.103616813 0.266398617 0.337585441 0.279189055 0.257366255
+-8.084066471 0.266573427 0.335795604 0.279749506 0.257465037
+-8.064516129 0.266749060 0.334030289 0.280319794 0.257565302
+-8.044965787 0.266925479 0.332289147 0.280900034 0.257667076
+-8.025415445 0.267102639 0.330571844 0.281490338 0.257770384
+-8.005865103 0.267280498 0.328878058 0.282090823 0.257875253
+-7.986314761 0.267459012 0.327207479 0.282701602 0.257981710
+-7.966764418 0.267638134 0.325559813 0.283322792 0.258089781
+-7.947214076 0.267817816 0.323934772 0.283954510 0.258199496
+-7.927663734 0.267998010 0.322332086 0.284596871 0.258310882
+-7.908113392 0.268178666 0.320751491 0.285249995 0.258423969
+-7.888563050 0.268359732 0.319192738 0.285913998 0.258538786
+-7.869012708 0.268541155 0.317655585 0.286589000 0.258655364
+-7.849462366 0.268722883 0.316139803 0.287275119 0.258773734
+-7.829912023 0.268904858 0.314645172 0.287972477 0.258893927
+-7.810361681 0.269087026 0.313171482 0.288681194 0.259015976
+-7.790811339 0.269269328 0.311718532 0.289401390 0.259139914
+-7.771260997 0.269451706 0.310286130 0.290133187 0.259265774
+-7.751710655 0.269634101 0.308874096 0.290876708 0.259393591
+-7.732160313 0.269816452 0.307482254 0.291632076 0.259523400
+-7.712609971 0.269998697 0.306110441 0.292399413 0.259655237
+-7.693059629 0.270180774 0.304758500 0.293178844 0.259789138
+-7.673509286 0.270362620 0.303426284 0.293970494 0.259925141
+-7.653958944 0.270544172 0.302113652 0.294774488 0.260063283
+-7.634408602 0.270725364 0.300820472 0.295590951 0.260203605
+-7.614858260 0.270906132 0.299546621 0.296420009 0.260346146
+-7.595307918 0.271086411 0.298291981 0.297261790 0.260490946
+-7.575757576 0.271266134 0.297056445 0.298116421 0.260638047
+-7.556207234 0.271445235 0.295839910 0.298984029 0.260787491
+-7.536656891 0.271623649 0.294642282 0.299864743 0.260939322
+-7.517106549 0.271801309 0.293463474 0.300758692 0.261093584
+-7.497556207 0.271978149 0.292303406 0.301666005 0.261250322
+-7.478005865 0.272154103 0.291162006 0.302586812 0.261409582
+-7.458455523 0.272329105 0.290039206 0.303521243 0.261571412
+-7.438905181 0.272503091 0.288934948 0.304469430 0.261735858
+-7.419354839 0.272675996 0.287849178 0.305431504 0.261902971
+-7.399804497 0.272847756 0.286781851 0.306407596 0.262072801
+-7.380254154 0.273018309 0.285732927 0.307397839 0.262245398
+-7.360703812 0.273187593 0.284702372 0.308402365 0.262420815
+-7.341153470 0.273355548 0.283690161 0.309421308 0.262599105
+-7.321603128 0.273522115 0.282696272 0.310454800 0.262780323
+-7.302052786 0.273687238 0.281720692 0.311502976 0.262964523
+-7.282502444 0.273850860 0.280763413 0.312565971 0.263151763
+-7.262952102 0.274012930 0.279824432 0.313643918 0.263342101
+-7.243401760 0.274173395 0.278903754 0.314736952 0.263535594
+-7.223851417 0.274332208 0.278001390 0.315845209 0.263732304
+-7.204301075 0.274489324 0.277117355 0.316968825 0.263932292
+-7.184750733 0.274644699 0.276251673 0.318107935 0.264135619
+-7.165200391 0.274798294 0.275404370 0.319262675 0.264342350
+-7.145650049 0.274950074 0.274575482 0.320433182 0.264552551
+-7.126099707 0.275100006 0.273765048 0.321619592 0.264766285
+-7.106549365 0.275248062 0.272973113 0.322822043 0.264983623
+-7.086999022 0.275394218 0.272199729 0.324040670 0.265204631
+-7.067448680 0.275538454 0.271444953 0.307535201 0.265429380
+-7.047898338 0.275680755 0.270708847 0.308450253 0.265657942
+-7.028347996 0.275821113 0.269991479 0.309374445 0.265890388
+-7.008797654 0.275959522 0.269292923 0.310307730 0.266126792
+-6.989247312 0.276095984 0.268613257 0.311250056 0.266367230
+-6.969696970 0.276230505 0.267952566 0.312201365 0.266611778
+-6.950146628 0.276363100 0.267310940 0.313161596 0.266860514
+-6.930596285 0.276493788 0.266688473 0.314130682 0.267113515
+-6.911045943 0.276622596 0.266085265 0.315108551 0.267370864
+-6.891495601 0.276749557 0.265501422 0.316095125 0.267632640
+-6.871945259 0.276874713 0.264937052 0.317090322 0.267898927
+-6.852394917 0.276998112 0.264392272 0.318094054 0.268169809
+-6.832844575 0.277119810 0.263867201 0.319106226 0.268445370
+-6.813294233 0.277239873 0.263361963 0.320126738 0.268725698
+-6.793743891 0.277358374 0.262876688 0.321155486 0.269010879
+-6.774193548 0.277475395 0.262411508 0.322192355 0.269301002
+-6.754643206 0.277591028 0.261966562 0.323237230 0.269596157
+-6.735092864 0.277705372 0.261541991 0.324289983 0.269896435
+-6.715542522 0.277818538 0.261137942 0.325350486 0.270201928
+-6.695992180 0.277930645 0.260754565 0.326418598 0.270512728
+-6.676441838 0.278041824 0.260392013 0.327494177 0.270828929
+-6.656891496 0.278152214 0.260050443 0.328577070 0.271150626
+-6.637341153 0.278261967 0.259730017 0.329667118 0.271477914
+-6.617790811 0.278371242 0.259430897 0.330764156 0.271810890
+-6.598240469 0.278480211 0.259153251 0.331868010 0.272149651
+-6.578690127 0.278589058 0.258897247 0.332978499 0.272494294
+-6.559139785 0.278697976 0.258663058 0.334095435 0.272844918
+-6.539589443 0.278807169 0.258450858 0.335218622 0.273201620
+-6.520039101 0.278916853 0.258260822 0.336347856 0.273564501
+-6.500488759 0.279027256 0.258093128 0.337482925 0.273933658
+-6.480938416 0.279138616 0.257947954 0.338623608 0.274309192
+-6.461388074 0.279251182 0.257825481 0.221051999 0.274691202
+-6.441837732 0.279365214 0.257725889 0.221590933 0.275079788
+-6.422287390 0.279480984 0.257649358 0.222137883 0.275475048
+-6.402737048 0.279598775 0.257596069 0.222693019 0.275877081
+-6.383186706 0.279718880 0.257566201 0.223256511 0.276285986
+-6.363636364 0.279841602 0.257559934 0.223828528 0.276701860
+-6.344086022 0.279967255 0.257577444 0.224409243 0.277124800
+-6.324535679 0.280096164 0.257618909 0.224998829 0.277554903
+-6.304985337 0.280228662 0.257684501 0.225597457 0.277992263
+-6.285434995 0.280365093 0.257774389 0.226205300 0.278436973
+-6.265884653 0.280505807 0.257888742 0.226822530 0.278889126
+-6.246334311 0.280651166 0.258027723 0.227449317 0.279348812
+-6.226783969 0.280801538 0.258191489 0.228085831 0.279816119
+-6.207233627 0.280957297 0.258380194 0.228732239 0.280291134
+-6.187683284 0.281118828 0.258593987 0.229388706 0.280773941
+-6.168132942 0.281286517 0.258833007 0.230055394 0.281264621
+-6.148582600 0.281460758 0.259097390 0.230732461 0.281763253
+-6.129032258 0.281641951 0.259387263 0.231420063 0.282269913
+-6.109481916 0.281830496 0.259702743 0.232118350 0.282784672
+-6.089931574 0.282026799 0.260043940 0.232827466 0.283307600
+-6.070381232 0.282231267 0.260410954 0.233547551 0.283838762
+-6.050830890 0.282444309 0.260803873 0.234278737 0.284378218
+-6.031280547 0.282666331 0.261222776 0.235021150 0.284926025
+-6.011730205 0.282897743 0.261667729 0.235774908 0.285482236
+-5.992179863 0.283138948 0.262138784 0.236540120 0.286046897
+-5.972629521 0.283390349 0.262635982 0.237316886 0.286620050
+-5.953079179 0.283652343 0.263159348 0.238105297 0.287201731
+-5.933528837 0.283925323 0.263708892 0.238905431 0.287791972
+-5.913978495 0.284209675 0.264284609 0.239717357 0.288390797
+-5.894428152 0.284505775 0.264886477 0.240541130 0.288998224
+-5.874877810 0.284813992 0.265514457 0.241376794 0.289614265
+-5.855327468 0.285134684 0.266168491 0.242224377 0.290238925
+-5.835777126 0.285468197 0.266848503 0.243083895 0.290872201
+-5.816226784 0.285814864 0.267554397 0.243955347 0.291514085
+-5.796676442 0.286175003 0.268286057 0.244838717 0.292164558
+-5.777126100 0.286548917 0.269043344 0.245733970 0.292823594
+-5.757575758 0.286936891 0.269826101 0.246641058 0.293491162
+-5.738025415 0.287339193 0.270634145 0.247559911 0.294167217
+-5.718475073 0.287756071 0.271467272 0.248490441 0.294851710
+-5.698924731 0.288187751 0.272325255 0.249432542 0.295544581
+-5.679374389 0.288634438 0.273207839 0.250386088 0.296245761
+-5.659824047 0.289096314 0.274114750 0.251350930 0.296955171
+-5.640273705 0.289573537 0.275045684 0.252326899 0.297672725
+-5.620723363 0.290066237 0.276000313 0.253313807 0.298398324
+-5.601173021 0.290574522 0.276978285 0.254311439 0.299131862
+-5.581622678 0.291098468 0.277979219 0.255319561 0.299873222
+-5.562072336 0.291638125 0.279002709 0.256337915 0.300622278
+-5.542521994 0.292193515 0.280048322 0.257366220 0.301378891
+-5.522971652 0.292764628 0.281115598 0.258404172 0.302142915
+-5.503421310 0.293351425 0.282204050 0.259451443 0.302914192
+-5.483870968 0.293953836 0.283313164 0.260507680 0.303692556
+-5.464320626 0.294571759 0.284442401 0.261572509 0.304477830
+-5.444770283 0.295205060 0.285591192 0.262645531 0.305269824
+-5.425219941 0.295853575 0.286758945 0.263726323 0.306068343
+-5.405669599 0.296517105 0.287945040 0.264814441 0.306873179
+-5.386119257 0.297195423 0.289148832 0.265909414 0.307684115
+-5.366568915 0.297888265 0.290369651 0.267010752 0.308500925
+-5.347018573 0.298595340 0.291606802 0.268117942 0.309596055
+-5.327468231 0.299316323 0.292859566 0.269230449 0.312559135
+-5.307917889 0.300050859 0.294127200 0.270347716 0.315603239
+-5.288367546 0.300798562 0.295408941 0.271469168 0.318728992
+-5.268817204 0.301559019 0.296704001 0.272594208 0.321936947
+-5.249266862 0.302331786 0.298011575 0.273722223 0.325227579
+-5.229716520 0.303116392 0.299330835 0.274852580 0.328601284
+-5.210166178 0.303912338 0.300660938 0.275984632 0.332058374
+-5.190615836 0.304719103 0.302001020 0.277117713 0.335599077
+-5.171065494 0.305536140 0.303350205 0.278251145 0.339223532
+-5.151515152 0.306362878 0.304707598 0.279384238 0.342931785
+-5.131964809 0.307198726 0.306072293 0.280516287 0.346723791
+-5.112414467 0.308043075 0.307443373 0.281646579 0.350599408
+-5.092864125 0.308895296 0.308819908 0.282774390 0.354558399
+-5.073313783 0.309754745 0.310200960 0.283898991 0.358600425
+-5.053763441 0.310620761 0.311585585 0.285019646 0.362725048
+-5.034213099 0.311492675 0.312972829 0.286135612 0.366931729
+-5.014662757 0.312369804 0.314361738 0.287246147 0.371219824
+-4.995112414 0.313251457 0.315751354 0.288350506 0.375588587
+-4.975562072 0.314136938 0.317140716 0.289447943 0.380037168
+-4.956011730 0.315025543 0.318528866 0.290537715 0.384564614
+-4.936461388 0.315916570 0.319914846 0.291619084 0.389169867
+-4.916911046 0.316809312 0.321297703 0.292691315 0.393851765
+-4.897360704 0.317703066 0.322676489 0.293753680 0.398609045
+-4.877810362 0.318597132 0.324050262 0.294805461 0.403440342
+-4.858260020 0.319490815 0.325418091 0.295845948 0.408344189
+-4.838709677 0.320383428 0.326779051 0.296874445 0.413319022
+-4.819159335 0.321274292 0.328132233 0.297890266 0.418363180
+-4.799608993 0.322162740 0.329476736 0.298892742 0.423474905
+-4.780058651 0.323048118 0.330811677 0.299881219 0.428652350
+-4.760508309 0.323929786 0.332136187 0.300855059 0.433893576
+-4.740957967 0.324807121 0.333449414 0.301813645 0.439196556
+-4.721407625 0.325679516 0.334750524 0.302756379 0.444559184
+-4.701857283 0.326546384 0.336038701 0.303682682 0.449979267
+-4.682306940 0.327407160 0.337313152 0.304592000 0.455454542
+-4.662756598 0.328261298 0.338573103 0.305483801 0.460982668
+-4.643206256 0.329108277 0.339817802 0.306357577 0.466561238
+-4.623655914 0.329947599 0.341046522 0.307212843 0.472187778
+-4.604105572 0.330778792 0.342258557 0.308049144 0.477859756
+-4.584555230 0.331601407 0.343453227 0.308866048 0.483574582
+-4.565004888 0.332415024 0.344629876 0.309663151 0.489329616
+-4.545454545 0.333219249 0.345787876 0.310440077 0.495122171
+-4.525904203 0.334013717 0.346926622 0.311196477 0.500949516
+-4.506353861 0.334798087 0.348045536 0.311932032 0.506808887
+-4.486803519 0.335572050 0.349144067 0.312646449 0.512697484
+-4.467253177 0.336335323 0.350221692 0.313339466 0.518612482
+-4.447702835 0.337087653 0.351277912 0.314010850 0.524551034
+-4.428152493 0.337828813 0.352312257 0.314660394 0.530510274
+-4.408602151 0.338558605 0.353324284 0.315287924 0.536487326
+-4.389051808 0.339276860 0.354313575 0.315893291 0.542479305
+-4.369501466 0.339983434 0.355279741 0.316476377 0.548483325
+-4.349951124 0.340678212 0.356222417 0.317037090 0.554496502
+-4.330400782 0.341361105 0.357141266 0.317575368 0.560515958
+-4.310850440 0.342032049 0.358035977 0.318091175 0.566538831
+-4.291300098 0.342691006 0.358906261 0.318584502 0.572562270
+-4.271749756 0.343337961 0.359751858 0.319055367 0.578583450
+-4.252199413 0.343972925 0.360572531 0.319503812 0.584599570
+-4.232649071 0.344595929 0.361368066 0.319929907 0.590607856
+-4.213098729 0.345207029 0.362138273 0.320333744 0.596605571
+-4.193548387 0.345806299 0.362882985 0.320715440 0.602590015
+-4.173998045 0.346393834 0.363602057 0.321075135 0.608558530
+-4.154447703 0.346969748 0.364295364 0.321412990 0.614508500
+-4.134897361 0.347534173 0.364962804 0.321729188 0.620437361
+-4.115347019 0.348087259 0.365604293 0.322023932 0.626342600
+-4.095796676 0.348629168 0.366219767 0.322297447 0.632221758
+-4.076246334 0.349160080 0.366809181 0.322549972 0.638072433
+-4.056695992 0.349680189 0.367372507 0.322781769 0.643892285
+-4.037145650 0.350189698 0.367909733 0.322993113 0.649679036
+-4.017595308 0.350688825 0.368420866 0.323184297 0.655430473
+-3.998044966 0.351177796 0.368905927 0.323355628 0.661144451
+-3.978494624 0.351656848 0.369364949 0.323507428 0.666079666
+-3.958944282 0.352126225 0.369797984 0.323640031 0.670888651
+-3.939393939 0.352586178 0.370205092 0.323753785 0.675690949
+-3.919843597 0.353036965 0.370586349 0.323849047 0.680483527
+-3.900293255 0.353478850 0.370941841 0.323926187 0.685263450
+-3.880742913 0.353912099 0.371271664 0.323985583 0.690027883
+-3.861192571 0.354336983 0.371575927 0.324027622 0.694774089
+-3.841642229 0.354753776 0.371854744 0.324052698 0.699499433
+-3.822091887 0.355162752 0.372108242 0.324061214 0.704201381
+-3.802541544 0.355564188 0.372336553 0.324053577 0.708877501
+-3.782991202 0.355958358 0.372539817 0.324030201 0.713525463
+-3.763440860 0.356345538 0.372718183 0.323991504 0.718143038
+-3.743890518 0.356726002 0.372871802 0.323937907 0.722728101
+-3.724340176 0.357100021 0.373000833 0.323869836 0.727278628
+-3.704789834 0.357467865 0.373105440 0.323787717 0.731792694
+-3.685239492 0.357829800 0.373185789 0.323691979 0.736268477
+-3.665689150 0.358186087 0.373242052 0.323583053 0.740704251
+-3.646138807 0.358536986 0.373274403 0.323461369 0.745098390
+-3.626588465 0.358882748 0.373283019 0.323327357 0.749449365
+-3.607038123 0.359223622 0.373268079 0.323181447 0.753755740
+-3.587487781 0.359559852 0.373229764 0.323024067 0.758016176
+-3.567937439 0.359891672 0.373168254 0.322855643 0.762229423
+-3.548387097 0.360219316 0.373083733 0.322676600 0.766394324
+-3.528836755 0.360543005 0.372976384 0.322487358 0.770509809
+-3.509286413 0.360862959 0.372846389 0.322288336 0.774574896
+-3.489736070 0.361179388 0.372693931 0.322079949 0.778588685
+-3.470185728 0.361492495 0.372519192 0.321862607 0.782550361
+-3.450635386 0.361802477 0.372322351 0.321636715 0.786459190
+-3.431085044 0.362109524 0.372103589 0.321402676 0.790314512
+-3.411534702 0.362413816 0.371863082 0.321160886 0.794115748
+-3.391984360 0.362715529 0.371601006 0.320911736 0.797862389
+-3.372434018 0.363014830 0.371317533 0.320655611 0.801553999
+-3.352883675 0.363311877 0.371012835 0.320392891 0.805190210
+-3.333333333 0.363606822 0.370687079 0.320123950 0.808770721
+-3.313782991 0.363899811 0.370340429 0.319849154 0.812295296
+-3.294232649 0.364190979 0.369973047 0.319568865 0.815763759
+-3.274682307 0.364480457 0.369585091 0.319283438 0.819175996
+-3.255131965 0.364768368 0.369176715 0.318993219 0.822531948
+-3.235581623 0.365054826 0.368748070 0.318698549 0.825831611
+-3.216031281 0.365339939 0.368299304 0.318399763 0.829075035
+-3.196480938 0.365623810 0.367830557 0.318097186 0.832262318
+-3.176930596 0.365906532 0.367341969 0.317791138 0.835393608
+-3.157380254 0.366188194 0.366833674 0.317481932 0.838469096
+-3.137829912 0.366468876 0.366305800 0.317169872 0.841489018
+-3.118279570 0.366748655 0.365758474 0.316855256 0.844453651
+-3.098729228 0.367027599 0.365191816 0.316538375 0.847363310
+-3.079178886 0.367305771 0.364605940 0.316219511 0.850218348
+-3.059628543 0.367583229 0.364000957 0.315898941 0.853019152
+-3.040078201 0.367860024 0.363376974 0.315576933 0.855766142
+-3.020527859 0.368136203 0.362734089 0.315253747 0.858459769
+-3.000977517 0.368411807 0.362072400 0.314929638 0.861100512
+-2.981427175 0.368686873 0.361391995 0.314604853 0.863688877
+-2.961876833 0.368961431 0.360692960 0.314279630 0.866225396
+-2.942326491 0.369235508 0.359975374 0.313954203 0.868710622
+-2.922776149 0.369509128 0.359239312 0.313628796 0.871145133
+-2.903225806 0.369782308 0.358484842 0.313303629 0.873529524
+-2.883675464 0.370055062 0.357712027 0.312978912 0.875864408
+-2.864125122 0.370327403 0.356920926 0.312654850 0.878150418
+-2.844574780 0.370599335 0.356111589 0.312331640 0.880388198
+-2.825024438 0.370870863 0.355284065 0.312009475 0.882578408
+-2.805474096 0.371141988 0.354438393 0.311688539 0.884721720
+-2.785923754 0.371412706 0.353574609 0.311369010 0.886818816
+-2.766373412 0.371683012 0.352692741 0.311051060 0.888870388
+-2.746823069 0.371952898 0.351792813 0.310734855 0.890877137
+-2.727272727 0.372222354 0.350874844 0.310420554 0.892839769
+-2.707722385 0.372491367 0.349938843 0.310108310 0.894758999
+-2.688172043 0.372759921 0.348984818 0.309798272 0.896635544
+-2.668621701 0.373027999 0.348012767 0.309490580 0.898470126
+-2.649071359 0.373295584 0.347022684 0.309185371 0.900263470
+-2.629521017 0.373562653 0.346014557 0.308882776 0.902016302
+-2.609970674 0.373829186 0.344988366 0.308582920 0.903729349
+-2.590420332 0.374095160 0.343944087 0.308285921 0.905403340
+-2.570869990 0.374360548 0.342881689 0.307991895 0.907039000
+-2.551319648 0.374625326 0.341801133 0.307700951 0.908637054
+-2.531769306 0.374889468 0.340702376 0.307413194 0.910198225
+-2.512218964 0.375152945 0.339585366 0.307128722 0.911723233
+-2.492668622 0.375415730 0.338450047 0.306847630 0.913212792
+-2.473118280 0.375677793 0.337296355 0.306570009 0.914667616
+-2.453567937 0.375939106 0.336124218 0.306295944 0.916088410
+-2.434017595 0.376199638 0.334933559 0.306025517 0.917475877
+-2.414467253 0.376459360 0.333724294 0.305758803 0.918830710
+-2.394916911 0.376718242 0.332496330 0.305495875 0.920153600
+-2.375366569 0.376976253 0.331249569 0.305236802 0.921445229
+-2.355816227 0.377233364 0.329983905 0.304981649 0.922706271
+-2.336265885 0.377489543 0.328699224 0.304730476 0.923937393
+-2.316715543 0.377744760 0.327395405 0.304483339 0.925139256
+-2.297165200 0.377998986 0.326072319 0.304240293 0.926312509
+-2.277614858 0.378252192 0.324729829 0.304001387 0.927457796
+-2.258064516 0.378504347 0.323367790 0.303766666 0.928575750
+-2.238514174 0.378755423 0.321986050 0.303536174 0.929666996
+-2.218963832 0.379005391 0.320584447 0.303309949 0.930732148
+-2.199413490 0.379254224 0.319162811 0.303088030 0.931771812
+-2.179863148 0.379501895 0.317720964 0.302870448 0.932786585
+-2.160312805 0.379748375 0.316258717 0.302657234 0.933777052
+-2.140762463 0.379993640 0.314775875 0.302448415 0.934743790
+-2.121212121 0.380237664 0.313272230 0.302244016 0.935687364
+-2.101661779 0.380480422 0.311747568 0.302044058 0.936608331
+-2.082111437 0.380721890 0.310201661 0.301848561 0.937507236
+-2.062561095 0.380962045 0.308634274 0.301657541 0.938384615
+-2.043010753 0.381200865 0.307045161 0.301471013 0.939240993
+-2.023460411 0.381438328 0.305434064 0.301288987 0.940076883
+-2.003910068 0.381674413 0.303800713 0.301111474 0.940892790
+-1.984359726 0.381909101 0.302144831 0.300938480 0.941689209
+-1.964809384 0.382142372 0.300466123 0.300770010 0.942466622
+-1.945259042 0.382374209 0.298764287 0.300606066 0.943225502
+-1.925708700 0.382604595 0.297039004 0.300446651 0.943966312
+-1.906158358 0.382833513 0.295289947 0.300291761 0.944689503
+-1.886608016 0.383060948 0.293516769 0.300141395 0.945395519
+-1.867057674 0.383286886 0.291719115 0.299995546 0.946084790
+-1.847507331 0.383511314 0.289896612 0.299854208 0.946757739
+-1.827956989 0.383734219 0.288048873 0.299717372 0.947414776
+-1.808406647 0.383955590 0.286175495 0.299585028 0.948056303
+-1.788856305 0.384175416 0.284276059 0.299457164 0.948682713
+-1.769305963 0.384393687 0.282350129 0.299333766 0.949294386
+-1.749755621 0.384610396 0.280397251 0.299214820 0.949891695
+-1.730205279 0.384825534 0.278416954 0.299100308 0.950475002
+-1.710654936 0.385039095 0.276408745 0.298990212 0.951044661
+-1.691104594 0.385251073 0.274372115 0.298884514 0.951601015
+-1.671554252 0.385461463 0.272306532 0.298783193 0.952144399
+-1.652003910 0.385670261 0.270211443 0.298686226 0.952675137
+-1.632453568 0.385877464 0.268086272 0.298593591 0.953193547
+-1.612903226 0.386083071 0.265930419 0.298505263 0.953699936
+-1.593352884 0.386287079 0.263743260 0.298421216 0.954194602
+-1.573802542 0.386489488 0.261524145 0.298341424 0.954677836
+-1.554252199 0.386690300 0.259272397 0.298265859 0.955149920
+-1.534701857 0.386889514 0.256987311 0.298194492 0.955611127
+-1.515151515 0.387087133 0.254668150 0.298127293 0.956061722
+-1.495601173 0.387283161 0.252314149 0.298064232 0.956501963
+-1.476050831 0.387477601 0.249924508 0.298005277 0.956932100
+-1.456500489 0.387670457 0.247498391 0.297950394 0.957352373
+-1.436950147 0.387861735 0.245034930 0.297899552 0.957763018
+-1.417399804 0.388051441 0.242533214 0.297852715 0.958164261
+-1.397849462 0.388239582 0.239992294 0.297809848 0.958556321
+-1.378299120 0.388426164 0.237411179 0.297770915 0.958939411
+-1.358748778 0.388611197 0.234788830 0.297735879 0.959313737
+-1.339198436 0.388794690 0.232124163 0.297704704 0.959679498
+-1.319648094 0.388976651 0.229416043 0.297677350 0.960036884
+-1.300097752 0.389157091 0.226663282 0.297653780 0.960386082
+-1.280547410 0.389336021 0.223864633 0.297633953 0.960727271
+-1.260997067 0.389513452 0.221018793 0.297617830 0.961060623
+-1.241446725 0.389689397 0.218124393 0.297605370 0.961386306
+-1.221896383 0.389863868 0.215179996 0.297596531 0.961704480
+-1.202346041 0.390036878 0.212184094 0.297591272 0.962015301
+-1.182795699 0.390208441 0.209135102 0.297589550 0.962318918
+-1.163245357 0.390378571 0.206031353 0.297591322 0.962615475
+-1.143695015 0.390547284 0.202871093 0.297596546 0.962905110
+-1.124144673 0.390714593 0.199652476 0.297605176 0.963187958
+-1.104594330 0.390880516 0.196373555 0.297617169 0.963464147
+-1.085043988 0.391045067 0.193032275 0.297632480 0.963733799
+-1.065493646 0.391208264 0.189626469 0.297651063 0.963997034
+-1.045943304 0.391370124 0.186153846 0.297672874 0.964253966
+-1.026392962 0.391530664 0.182611982 0.297697865 0.964504704
+-1.006842620 0.391689902 0.178998311 0.297725991 0.964749353
+-0.987292278 0.391847857 0.175310115 0.297757204 0.964988014
+-0.967741935 0.392004545 0.171544508 0.297791458 0.965220784
+-0.948191593 0.392159988 0.167698426 0.297828704 0.965447755
+-0.928641251 0.392314203 0.163768611 0.297868896 0.965669016
+-0.909090909 0.392467210 0.159751593 0.297911985 0.965884652
+-0.889540567 0.392619030 0.155643675 0.297957922 0.966094744
+-0.869990225 0.392769681 0.151440909 0.298006659 0.966299371
+-0.850439883 0.392919184 0.147139076 0.298058147 0.966498605
+-0.830889541 0.393067561 0.142733659 0.298112336 0.966692519
+-0.811339198 0.393214831 0.138219816 0.298169178 0.966881180
+-0.791788856 0.393361015 0.133592348 0.298228621 0.967064653
+-0.772238514 0.393506135 0.128845663 0.298290618 0.967243000
+-0.752688172 0.393650212 0.123973734 0.298355116 0.967416279
+-0.733137830 0.393793268 0.118970057 0.298422067 0.967584547
+-0.713587488 0.393935324 0.113827597 0.298491418 0.967747856
+-0.694037146 0.394076403 0.108538729 0.298563120 0.967906258
+-0.674486804 0.394216525 0.103095170 0.298637122 0.968059801
+-0.654936461 0.394355714 0.097487905 0.298713373 0.968208531
+-0.635386119 0.394493991 0.091707092 0.298791821 0.968352491
+-0.615835777 0.394631379 0.085741965 0.298872415 0.968491723
+-0.596285435 0.394767900 0.079580712 0.298955104 0.968626265
+-0.576735093 0.394903577 0.073210334 0.299039836 0.968756156
+-0.557184751 0.395038432 0.066616483 0.299126559 0.968881429
+-0.537634409 0.395172488 0.059783269 0.299215221 0.969002119
+-0.518084066 0.395305768 0.052693032 0.299305771 0.969118256
+-0.498533724 0.395438294 0.027022210 0.299398157 0.969229871
+-0.478983382 0.395570089 0.027105698 0.299492326 0.969336990
+-0.459433040 0.395701176 0.027190482 0.299588227 0.969439642
+-0.439882698 0.395831578 0.027276576 0.299685807 0.969537849
+-0.420332356 0.395961317 0.027363993 0.299785014 0.969631636
+-0.400782014 0.396090417 0.027452746 0.299885796 0.969721024
+-0.381231672 0.396218900 0.027542850 0.299988100 0.969806034
+-0.361681329 0.396346790 0.027634320 0.300091874 0.969886685
+-0.342130987 0.396474108 0.027727170 0.300197067 0.969962994
+-0.322580645 0.396600879 0.027821415 0.300303624 0.970034979
+-0.303030303 0.396727124 0.027917072 0.300411495 0.970102654
+-0.283479961 0.396852867 0.028014156 0.300520627 0.970166034
+-0.263929619 0.396978131 0.028112683 0.300630968 0.970225132
+-0.244379277 0.397102938 0.028212670 0.300742464 0.970279960
+-0.224828935 0.397227311 0.028314135 0.300855065 0.970330530
+-0.205278592 0.397351272 0.028417094 0.300968718 0.970376851
+-0.185728250 0.397474846 0.028521567 0.301083370 0.970418933
+-0.166177908 0.397598053 0.028627570 0.301198970 0.970456784
+-0.146627566 0.397720918 0.028735122 0.301315466 0.970490410
+-0.127077224 0.397843462 0.028844244 0.301432806 0.970519820
+-0.107526882 0.397965709 0.028954953 0.301550937 0.970545018
+-0.087976540 0.398087681 0.029067270 0.301669809 0.970566009
+-0.068426197 0.398209400 0.029181216 0.301789369 0.970582797
+-0.048875855 0.398330889 0.029296811 0.301909567 0.970595386
+-0.029325513 0.398452171 0.029414076 0.302030350 0.970603777
+-0.009775171 0.398573268 0.029533032 0.302151666 0.970607972
+0.009775171 0.398694203 0.029653702 0.302273469 0.970607972
+0.029325513 0.398814999 0.029776108 0.302395784 0.970603777
+0.048875855 0.398935677 0.029900272 0.302518700 0.970595386
+0.068426197 0.399056261 0.030026219 0.302642316 0.970582797
+0.087976540 0.399176774 0.030153971 0.302766728 0.970566009
+0.107526882 0.399297237 0.030283554 0.302892036 0.970545018
+0.127077224 0.399417674 0.030414991 0.303018334 0.970519820
+0.146627566 0.399538106 0.030548308 0.303145722 0.970490410
+0.166177908 0.399658558 0.030683531 0.303274297 0.970456784
+0.185728250 0.399779052 0.030820685 0.303404158 0.970418933
+0.205278592 0.399899611 0.030959797 0.303535401 0.970376851
+0.224828935 0.400020257 0.031100894 0.303668126 0.970330530
+0.244379277 0.400141014 0.031244004 0.303802430 0.970279960
+0.263929619 0.400261905 0.031389154 0.303938413 0.970225132
+0.283479961 0.400382953 0.031536374 0.304076173 0.970166034
+0.303030303 0.400504181 0.031685692 0.304215810 0.970102654
+0.322580645 0.400625614 0.031837138 0.304357422 0.970034979
+0.342130987 0.400747274 0.031990743 0.304501109 0.969962994
+0.361681329 0.400869186 0.032146536 0.304646971 0.969886685
+0.381231672 0.400991373 0.032304550 0.304795106 0.969806034
+0.400782014 0.401113861 0.032464815 0.304945616 0.969721024
+0.420332356 0.401236673 0.032627365 0.305098601 0.969631636
+0.439882698 0.401359833 0.032792232 0.305254160 0.969537849
+0.459433040 0.401483368 0.032959451 0.305412395 0.969439642
+0.478983382 0.401607302 0.033129054 0.305573406 0.969336990
+0.498533724 0.401731660 0.033301077 0.305737294 0.969229871
+0.518084066 0.401856469 0.059228582 0.305904161 0.969118256
+0.537634409 0.401981754 0.066576722 0.306074108 0.969002119
+0.557184751 0.402107541 0.073669107 0.306247236 0.968881429
+0.576735093 0.402233859 0.080523447 0.306423648 0.968756156
+0.596285435 0.402360733 0.087155681 0.306603447 0.968626265
+0.615835777 0.402488191 0.093580208 0.306786733 0.968491723
+0.635386119 0.402616261 0.099810074 0.306973611 0.968352491
+0.654936461 0.402744973 0.105857144 0.307164182 0.968208531
+0.674486804 0.402874354 0.111732235 0.307358550 0.968059801
+0.694037146 0.403004434 0.117445237 0.307556820 0.967906258
+0.713587488 0.403135242 0.123005220 0.307759093 0.967747856
+0.733137830 0.403266811 0.128420516 0.307965475 0.967584547
+0.752688172 0.403399170 0.133698805 0.308176069 0.967416279
+0.772238514 0.403532350 0.138847172 0.308390980 0.967243000
+0.791788856 0.403666386 0.143872177 0.308610313 0.967064653
+0.811339198 0.403801308 0.148779899 0.308834173 0.966881180
+0.830889541 0.403937152 0.153575984 0.309062665 0.966692519
+0.850439883 0.404073951 0.158265687 0.309295896 0.966498605
+0.869990225 0.404211740 0.162853905 0.309533970 0.966299371
+0.889540567 0.404350555 0.167345209 0.309776995 0.966094744
+0.909090909 0.404490433 0.171743876 0.310025076 0.965884652
+0.928641251 0.404631412 0.176053910 0.310278321 0.965669016
+0.948191593 0.404773529 0.180279066 0.310536838 0.965447755
+0.967741935 0.404916824 0.184422872 0.310800733 0.965220784
+0.987292278 0.405061338 0.188488644 0.311070115 0.964988014
+1.006842620 0.405207110 0.192479506 0.311345091 0.964749353
+1.026392962 0.405354184 0.196398403 0.311625771 0.964504704
+1.045943304 0.405502603 0.200248115 0.311912263 0.964253966
+1.065493646 0.405652411 0.204031268 0.312204677 0.963997034
+1.085043988 0.405803653 0.207750348 0.312503122 0.963733799
+1.104594330 0.405956376 0.211407710 0.312807708 0.963464147
+1.124144673 0.406110628 0.215005583 0.313118546 0.963187958
+1.143695015 0.406266458 0.218546087 0.313435746 0.962905110
+1.163245357 0.406423915 0.222031233 0.313759420 0.962615475
+1.182795699 0.406583053 0.225462935 0.314089679 0.962318918
+1.202346041 0.406743922 0.228843012 0.314426634 0.962015301
+1.221896383 0.406906579 0.232173199 0.314770399 0.961704480
+1.241446725 0.407071078 0.235455149 0.315121086 0.961386306
+1.260997067 0.407237476 0.238690441 0.315478807 0.961060623
+1.280547410 0.407405833 0.241880579 0.315843677 0.960727271
+1.300097752 0.407576209 0.245027006 0.316215809 0.960386082
+1.319648094 0.407748666 0.248131097 0.316595318 0.960036884
+1.339198436 0.407923267 0.251194171 0.316982319 0.959679498
+1.358748778 0.408100078 0.254217491 0.317376926 0.959313737
+1.378299120 0.408279166 0.257202267 0.317779255 0.958939411
+1.397849462 0.408460599 0.260149660 0.318189423 0.958556321
+1.417399804 0.408644448 0.263060786 0.318607545 0.958164261
+1.436950147 0.408830786 0.265936714 0.319033739 0.957763018
+1.456500489 0.409019687 0.268778475 0.319468122 0.957352373
+1.476050831 0.409211228 0.271587059 0.319910813 0.956932100
+1.495601173 0.409405488 0.274363417 0.320361928 0.956501963
+1.515151515 0.409602546 0.277108469 0.320821587 0.956061722
+1.534701857 0.409802487 0.279823099 0.321289910 0.955611127
+1.554252199 0.410005394 0.282508160 0.321767015 0.955149920
+1.573802542 0.410211355 0.285164474 0.322253024 0.954677836
+1.593352884 0.410420460 0.287792837 0.322748056 0.954194602
+1.612903226 0.410632801 0.290394016 0.323252234 0.953699936
+1.632453568 0.410848471 0.292968754 0.323765677 0.953193547
+1.652003910 0.411067568 0.295517767 0.324288509 0.952675137
+1.671554252 0.411290190 0.298041750 0.324820852 0.952144399
+1.691104594 0.411516441 0.300541377 0.325362830 0.951601015
+1.710654936 0.411746423 0.303017299 0.325914565 0.951044661
+1.730205279 0.411980245 0.305470146 0.326476181 0.950475002
+1.749755621 0.412218016 0.307900533 0.327047804 0.949891695
+1.769305963 0.412459849 0.310309053 0.327629558 0.949294386
+1.788856305 0.412705859 0.312696285 0.328221569 0.948682713
+1.808406647 0.412956165 0.315062788 0.328823962 0.948056303
+1.827956989 0.413210888 0.317409108 0.329436865 0.947414776
+1.847507331 0.413470153 0.319735776 0.330060404 0.946757739
+1.867057674 0.413734086 0.322043307 0.330694706 0.946084790
+1.886608016 0.414002820 0.324332205 0.331339900 0.945395519
+1.906158358 0.414276486 0.326602958 0.331996114 0.944689503
+1.925708700 0.414555223 0.328856044 0.332663476 0.943966312
+1.945259042 0.414839170 0.331091928 0.333342117 0.943225502
+1.964809384 0.415128472 0.333311065 0.334032167 0.942466622
+1.984359726 0.415423274 0.335513898 0.334733755 0.941689209
+2.003910068 0.415723728 0.337700860 0.335447012 0.940892790
+2.023460411 0.416029987 0.339872375 0.336172070 0.940076883
+2.043010753 0.416342210 0.342028856 0.336909060 0.939240993
+2.062561095 0.416660556 0.344170709 0.337658115 0.938384615
+2.082111437 0.416985191 0.346298330 0.338419368 0.937507236
+2.101661779 0.417316283 0.348412108 0.339192951 0.936608331
+2.121212121 0.417654004 0.350512425 0.339978998 0.935687364
+2.140762463 0.417998530 0.352599653 0.340777643 0.934743790
+2.160312805 0.418350041 0.354674158 0.341589020 0.933777052
+2.179863148 0.418708720 0.356736302 0.342413266 0.932786585
+2.199413490 0.419074756 0.358786437 0.343250513 0.931771812
+2.218963832 0.419448339 0.360824911 0.344100899 0.930732148
+2.238514174 0.419829666 0.362852066 0.344964560 0.929666996
+2.258064516 0.420218934 0.364868237 0.345841631 0.928575750
+2.277614858 0.420616350 0.366873757 0.346732250 0.927457796
+2.297165200 0.421022118 0.368868951 0.347636554 0.926312509
+2.316715543 0.421436453 0.370854140 0.348554680 0.925139256
+2.336265885 0.421859569 0.372829643 0.349486766 0.923937393
+2.355816227 0.422291687 0.374795771 0.350432950 0.922706271
+2.375366569 0.422733031 0.376752835 0.351393371 0.921445229
+2.394916911 0.423183830 0.378701139 0.352368168 0.920153600
+2.414467253 0.423644316 0.380640986 0.353357479 0.918830710
+2.434017595 0.424114726 0.382572673 0.354361444 0.917475877
+2.453567937 0.424595302 0.384496496 0.355380202 0.916088410
+2.473118280 0.425086289 0.386412749 0.356413894 0.914667616
+2.492668622 0.425587937 0.388321721 0.357462658 0.913212792
+2.512218964 0.426100499 0.390223699 0.358526635 0.911723233
+2.531769306 0.426624235 0.392118970 0.359605966 0.910198225
+2.551319648 0.427159405 0.394007815 0.360700791 0.908637054
+2.570869990 0.427706278 0.395890515 0.361811249 0.907039000
+2.590420332 0.428265123 0.397767351 0.362937483 0.905403340
+2.609970674 0.428836216 0.399638600 0.364079633 0.903729349
+2.629521017 0.429419836 0.401504537 0.365237839 0.902016302
+2.649071359 0.430016265 0.403365439 0.366412243 0.900263470
+2.668621701 0.430625792 0.405221577 0.367602984 0.898470126
+2.688172043 0.431248706 0.407073225 0.368810204 0.896635544
+2.707722385 0.431885303 0.408920655 0.370034044 0.894758999
+2.727272727 0.432535882 0.410764137 0.371274644 0.892839769
+2.746823069 0.433200746 0.412603942 0.372532144 0.890877137
+2.766373412 0.433880201 0.414440339 0.373806686 0.888870388
+2.785923754 0.434574556 0.416273598 0.375098408 0.886818816
+2.805474096 0.435284126 0.418103987 0.376407451 0.884721720
+2.825024438 0.436009227 0.419931775 0.377733955 0.882578408
+2.844574780 0.436750180 0.421757232 0.379078059 0.880388198
+2.864125122 0.437507308 0.423580626 0.380439902 0.878150418
+2.883675464 0.438280938 0.425402225 0.381819623 0.875864408
+2.903225806 0.439071398 0.427222300 0.383217359 0.873529524
+2.922776149 0.439879023 0.429041118 0.384633250 0.871145133
+2.942326491 0.440704145 0.430858952 0.386067432 0.868710622
+2.961876833 0.441547104 0.432676069 0.387520041 0.866225396
+2.981427175 0.442408239 0.434492743 0.388991215 0.863688877
+3.000977517 0.443287892 0.436309243 0.390481089 0.861100512
+3.020527859 0.444186407 0.438125842 0.391989797 0.858459769
+3.040078201 0.445104130 0.439942814 0.393517475 0.855766142
+3.059628543 0.446041409 0.441760430 0.395064254 0.853019152
+3.079178886 0.446998592 0.443578968 0.396630268 0.850218348
+3.098729228 0.447976030 0.445398700 0.398215648 0.847363310
+3.118279570 0.448974074 0.447219905 0.399820525 0.844453651
+3.137829912 0.449993075 0.449042858 0.401445028 0.841489018
+3.157380254 0.451033387 0.450867839 0.403089286 0.838469096
+3.176930596 0.452095362 0.452695126 0.404753425 0.835393608
+3.196480938 0.453179351 0.454524999 0.406437573 0.832262318
+3.216031281 0.454285709 0.456357739 0.408141854 0.829075035
+3.235581623 0.455414786 0.458193628 0.409866390 0.825831611
+3.255131965 0.456566933 0.460032949 0.411611303 0.822531948
+3.274682307 0.457742501 0.461875986 0.413376714 0.819175996
+3.294232649 0.458941837 0.463723023 0.415162741 0.815763759
+3.313782991 0.460165288 0.465574345 0.416969500 0.812295296
+3.333333333 0.461413199 0.467430239 0.418797106 0.808770721
+3.352883675 0.462685911 0.469290991 0.420645672 0.805190210
+3.372434018 0.463983765 0.471156887 0.422515308 0.801553999
+3.391984360 0.465307097 0.473028217 0.424406122 0.797862389
+3.411534702 0.466656239 0.474905267 0.426318219 0.794115748
+3.431085044 0.468031521 0.476788326 0.428251704 0.790314512
+3.450635386 0.469433268 0.478677682 0.430206676 0.786459190
+3.470185728 0.470861801 0.480573623 0.432183234 0.782550361
+3.489736070 0.472317434 0.482476438 0.434181471 0.778588685
+3.509286413 0.473800480 0.484386413 0.436201479 0.774574896
+3.528836755 0.475311241 0.486303836 0.438243346 0.770509809
+3.548387097 0.476850018 0.488228994 0.440307158 0.766394324
+3.567937439 0.478417103 0.490162170 0.442392993 0.762229423
+3.587487781 0.480012780 0.492103649 0.444500930 0.758016176
+3.607038123 0.481637330 0.494053714 0.446631040 0.753755740
+3.626588465 0.483291022 0.496012644 0.448783392 0.749449365
+3.646138807 0.484974119 0.497980719 0.450958049 0.745098390
+3.665689150 0.486686876 0.499958215 0.453155071 0.740704251
+3.685239492 0.488429538 0.501945405 0.455374509 0.736268477
+3.704789834 0.490202342 0.503942559 0.457616413 0.731792694
+3.724340176 0.492005515 0.505949945 0.459880823 0.727278628
+3.743890518 0.493839272 0.507967825 0.462167777 0.722728101
+3.763440860 0.495703820 0.509996460 0.464477305 0.718143038
+3.782991202 0.497599355 0.512036104 0.466809428 0.713525463
+3.802541544 0.499526060 0.514087007 0.469164163 0.708877501
+3.822091887 0.501484108 0.516149413 0.471541519 0.704201381
+3.841642229 0.503473659 0.518223561 0.473941496 0.699499433
+3.861192571 0.505494860 0.520309683 0.476364087 0.694774089
+3.880742913 0.507547847 0.522408005 0.478809276 0.690027883
+3.900293255 0.509632741 0.524518745 0.481277039 0.685263450
+3.919843597 0.511749649 0.526642114 0.483767340 0.680483527
+3.939393939 0.513898666 0.528778314 0.486280137 0.675690949
+3.958944282 0.516079869 0.530927538 0.488815375 0.670888651
+3.978494624 0.518293325 0.533089972 0.491372989 0.666079666
+3.998044966 0.520539081 0.535265788 0.493952902 0.661267120
+4.017595308 0.522817171 0.537455152 0.496555028 0.656454235
+4.037145650 0.525127612 0.539658217 0.499179267 0.651644322
+4.056695992 0.527470405 0.541875123 0.501825506 0.646840782
+4.076246334 0.529845534 0.544106000 0.504493619 0.642047101
+4.095796676 0.532252966 0.546350965 0.507183468 0.637266847
+4.115347019 0.534692652 0.548610121 0.509894901 0.632503669
+4.134897361 0.537164523 0.550883558 0.512627748 0.627761289
+4.154447703 0.539668492 0.553171352 0.515381829 0.623043500
+4.173998045 0.542204456 0.555473562 0.518156944 0.618354164
+4.193548387 0.544772290 0.557790233 0.520952880 0.613697201
+4.213098729 0.547371853 0.560121396 0.523769406 0.609076592
+4.232649071 0.550002983 0.562467062 0.526606275 0.604496365
+4.252199413 0.552665499 0.564827226 0.529463222 0.599960598
+4.271749756 0.555359199 0.567201868 0.532339963 0.595473405
+4.291300098 0.558083863 0.569590947 0.535236199 0.591038937
+4.310850440 0.560839249 0.571994406 0.538151608 0.586661369
+4.330400782 0.563625096 0.574412168 0.541085853 0.582344899
+4.349951124 0.566441120 0.576844136 0.544038576 0.578093735
+4.369501466 0.569287018 0.579290197 0.547009398 0.573912094
+4.389051808 0.572162465 0.581750215 0.549997921 0.569804190
+4.408602151 0.575067116 0.584224035 0.553003728 0.565774228
+4.428152493 0.578000602 0.586711483 0.556026379 0.561826396
+4.447702835 0.580962535 0.589212364 0.559065415 0.557964857
+4.467253177 0.583952505 0.591726462 0.562120355 0.554193739
+4.486803519 0.586970080 0.594253541 0.565190699 0.550517132
+4.506353861 0.590014805 0.596793345 0.568275924 0.546939073
+4.525904203 0.593086205 0.599345597 0.571375487 0.543463541
+4.545454545 0.596183783 0.601909999 0.574488824 0.540094448
+4.565004888 0.599307020 0.604486235 0.577615349 0.536835632
+4.584555230 0.602455376 0.607073967 0.580754457 0.533690844
+4.604105572 0.605628288 0.609672837 0.583905522 0.530663745
+4.623655914 0.608825173 0.612282470 0.587067897 0.527757894
+4.643206256 0.612045427 0.614902469 0.590240917 0.524976740
+4.662756598 0.615288423 0.617532422 0.593423894 0.522323618
+4.682306940 0.618553515 0.620171896 0.596616126 0.519801732
+4.701857283 0.621840036 0.622820441 0.599816889 0.517414159
+4.721407625 0.625147298 0.625477592 0.603025442 0.515163830
+4.740957967 0.628474594 0.628142866 0.606241027 0.513053531
+4.760508309 0.631821196 0.630815766 0.609462869 0.511085893
+4.780058651 0.635186360 0.633495779 0.612690179 0.509263383
+4.799608993 0.638569318 0.636182379 0.615922152 0.507588303
+4.819159335 0.641969289 0.638875028 0.619157968 0.506062780
+4.838709677 0.645385471 0.641573176 0.622396796 0.504688760
+4.858260020 0.648817045 0.644276261 0.625637791 0.503468006
+4.877810362 0.652263177 0.646983713 0.628880099 0.502402092
+4.897360704 0.655723015 0.649694950 0.632122854 0.501492397
+4.916911046 0.659195692 0.652409387 0.635365185 0.500740105
+4.936461388 0.662680328 0.655126430 0.638606208 0.500146198
+4.956011730 0.666176028 0.657845479 0.641845038 0.499711457
+4.975562072 0.669681882 0.660565932 0.645080783 0.499436455
+4.995112414 0.673196970 0.663287182 0.648312545 0.499321562
+5.014662757 0.676720360 0.666008622 0.651539426 0.499366939
+5.034213099 0.680251108 0.668729645 0.654760527 0.499572537
+5.053763441 0.683788262 0.671449643 0.657974949 0.499938103
+5.073313783 0.687330859 0.674168011 0.661181793 0.500463174
+5.092864125 0.690877929 0.676884147 0.664380165 0.501147082
+5.112414467 0.694428497 0.679597454 0.667569174 0.501988956
+5.131964809 0.697981578 0.682307340 0.670747935 0.502987722
+5.151515152 0.701536185 0.685013220 0.673915569 0.504142106
+5.171065494 0.705091325 0.687714518 0.677071207 0.505450642
+5.190615836 0.708646004 0.690410664 0.680213988 0.506911670
+5.210166178 0.712199225 0.693101102 0.683343063 0.508523343
+5.229716520 0.715749989 0.695785285 0.686457593 0.510283632
+5.249266862 0.719297300 0.698462678 0.689556754 0.512190333
+5.268817204 0.722840161 0.701132759 0.692639737 0.514241067
+5.288367546 0.726377577 0.703795021 0.695705746 0.516433293
+5.307917889 0.729908558 0.706448971 0.698754004 0.518764310
+5.327468231 0.733432118 0.709094133 0.701783750 0.521231265
+5.347018573 0.736947277 0.711730044 0.704794242 0.523831163
+5.366568915 0.740453059 0.714356261 0.707784757 0.528348490
+5.386119257 0.743948500 0.716972359 0.710754595 0.533191116
+5.405669599 0.747432640 0.719577928 0.713703072 0.538084034
+5.425219941 0.750904533 0.722172580 0.716629531 0.543024859
+5.444770283 0.754363240 0.724755944 0.719533334 0.548011143
+5.464320626 0.757807835 0.727327669 0.722413869 0.553040388
+5.483870968 0.761237407 0.729887424 0.725270545 0.558110043
+5.503421310 0.764651055 0.732434899 0.728102796 0.563217514
+5.522971652 0.768047895 0.734969801 0.730910082 0.568360169
+5.542521994 0.771427056 0.737491860 0.733691887 0.573535337
+5.562072336 0.774787686 0.740000828 0.736447718 0.578740320
+5.581622678 0.778128948 0.742496473 0.739177112 0.583972395
+5.601173021 0.781450023 0.744978587 0.741879629 0.589228817
+5.620723363 0.784750112 0.747446980 0.744554853 0.594506829
+5.640273705 0.788028433 0.749901485 0.747202397 0.599803661
+5.659824047 0.791284227 0.752341953 0.749821899 0.605116539
+5.679374389 0.794516752 0.754768254 0.752413022 0.610442691
+5.698924731 0.797725290 0.757180280 0.754975454 0.615779346
+5.718475073 0.800909145 0.759577940 0.757508910 0.621123745
+5.738025415 0.804067641 0.761961164 0.760013130 0.626473140
+5.757575758 0.807200126 0.764329899 0.762487877 0.631824806
+5.777126100 0.810305972 0.766684110 0.764932941 0.637176035
+5.796676442 0.813384574 0.769023782 0.767348137 0.642524151
+5.816226784 0.816435351 0.771348914 0.769733300 0.647866507
+5.835777126 0.819457745 0.773659524 0.772088292 0.653200489
+5.855327468 0.822451226 0.775955646 0.774412998 0.658523526
+5.874877810 0.825415285 0.778237329 0.776707323 0.663833086
+5.894428152 0.828349441 0.780504638 0.778971198 0.669126684
+5.913978495 0.831253236 0.782757652 0.781204571 0.674401884
+5.933528837 0.834126239 0.784996464 0.783407415 0.679656302
+5.953079179 0.836968044 0.787221183 0.785579722 0.684887610
+5.972629521 0.839778269 0.789431928 0.787721503 0.690093535
+5.992179863 0.842556558 0.791628832 0.789832789 0.695271867
+6.011730205 0.845302583 0.793812039 0.791913630 0.700420458
+6.031280547 0.848016037 0.795981706 0.793964094 0.705537222
+6.050830890 0.850696641 0.798137998 0.795984266 0.710620141
+6.070381232 0.853344140 0.800281095 0.797974247 0.715667266
+6.089931574 0.855958305 0.802411181 0.799934156 0.720676716
+6.109481916 0.858538928 0.804528452 0.801864127 0.725646682
+6.129032258 0.861085830 0.806633115 0.803764306 0.730575427
+6.148582600 0.863598854 0.808725380 0.805634858 0.735461284
+6.168132942 0.866077865 0.810805468 0.807475957 0.740302664
+6.187683284 0.868522753 0.812873607 0.809287792 0.745098049
+6.207233627 0.870933433 0.814930030 0.811070565 0.749845997
+6.226783969 0.873309839 0.816974977 0.812824489 0.754545140
+6.246334311 0.875651928 0.819008695 0.814549786 0.759194186
+6.265884653 0.877959681 0.821031434 0.816246692 0.763791917
+6.285434995 0.880233099 0.823043450 0.817915450 0.768337189
+6.304985337 0.882472202 0.825045003 0.819556313 0.772828933
+6.324535679 0.884677032 0.827036357 0.821169543 0.777266154
+6.344086022 0.886847652 0.829017781 0.822755409 0.781647928
+6.363636364 0.888984143 0.830989546 0.824314190 0.785973406
+6.383186706 0.891086603 0.832951925 0.825846168 0.790241807
+6.402737048 0.893155150 0.834905196 0.827351636 0.794452424
+6.422287390 0.895189920 0.836849638 0.828830889 0.798604616
+6.441837732 0.897191066 0.838785531 0.830284230 0.802697811
+6.461388074 0.899158755 0.840713158 0.831711965 0.806731506
+6.480938416 0.901093173 0.842632805 0.974837636 0.810705259
+6.500488759 0.902994519 0.844544755 0.975474355 0.814618695
+6.520039101 0.904863008 0.846449296 0.976084124 0.818471500
+6.539589443 0.906698868 0.848346715 0.976667723 0.822263423
+6.559139785 0.908502341 0.850237300 0.977225919 0.825994269
+6.578690127 0.910273681 0.852121339 0.977759471 0.829663902
+6.598240469 0.912013157 0.853999120 0.978269126 0.833272243
+6.617790811 0.913721045 0.855870932 0.978755621 0.836819264
+6.637341153 0.915397636 0.857737064 0.979219681 0.840304993
+6.656891496 0.917043229 0.859597803 0.979662018 0.843729506
+6.676441838 0.918658135 0.861453438 0.980083334 0.847092928
+6.695992180 0.920242672 0.863304256 0.980484317 0.850395431
+6.715542522 0.921797168 0.865150544 0.980865643 0.853637232
+6.735092864 0.923321958 0.866992589 0.981227976 0.856818591
+6.754643206 0.924817387 0.868830675 0.981571966 0.859939810
+6.774193548 0.926283803 0.870665088 0.981898253 0.863001228
+6.793743891 0.927721565 0.872496112 0.982207459 0.866003225
+6.813294233 0.929131034 0.874324031 0.982500198 0.868946215
+6.832844575 0.930512579 0.876149127 0.982777068 0.871830645
+6.852394917 0.931866572 0.877971680 0.983038655 0.874656996
+6.871945259 0.933193391 0.879791973 0.983285532 0.877425778
+6.891495601 0.934493417 0.881610285 0.983518258 0.880137530
+6.911045943 0.935767035 0.883426895 0.983737380 0.882792818
+6.930596285 0.937014632 0.885242080 0.983943431 0.885392235
+6.950146628 0.938236598 0.887056119 0.984136933 0.887936394
+6.969696970 0.939433326 0.888869286 0.984318393 0.890425933
+6.989247312 0.940605210 0.890681859 0.984488306 0.892861508
+7.008797654 0.941752645 0.892494111 0.984647156 0.895243797
+7.028347996 0.942876027 0.894306317 0.984795412 0.897573493
+7.047898338 0.943975752 0.896118751 0.984933532 0.899851304
+7.067448680 0.945052218 0.897931684 0.985061963 0.902077955
+7.086999022 0.946105820 0.899745389 1.002592474 0.904254182
+7.106549365 0.947136956 0.901560139 1.002380834 0.906380735
+7.126099707 0.948146019 0.903376205 1.002167690 0.908458371
+7.145650049 0.949133405 0.905193857 1.001953273 0.910487860
+7.165200391 0.950099506 0.907013367 1.001737809 0.912469977
+7.184750733 0.951044712 0.908835006 1.001521514 0.914405505
+7.204301075 0.951969413 0.910659044 1.001304598 0.916295232
+7.223851417 0.952873994 0.912485753 1.001087265 0.918139952
+7.243401760 0.953758841 0.914315403 1.000869711 0.919940461
+7.262952102 0.954624335 0.916148265 1.000652126 0.921697558
+7.282502444 0.955470853 0.917984613 1.000434693 0.923412044
+7.302052786 0.956298772 0.919824717 1.000217589 0.925084719
+7.321603128 0.957108463 0.921668851 1.000000985 0.926716386
+7.341153470 0.957900295 0.923517288 0.999785044 0.928307843
+7.360703812 0.958674632 0.925370304 0.999569925 0.929859890
+7.380254154 0.959431837 0.927228173 0.999355780 0.931373321
+7.399804497 0.960172265 0.929091173 0.999142754 0.932848928
+7.419354839 0.960896270 0.930959582 0.998930989 0.934287501
+7.438905181 0.961604200 0.932833679 0.998720619 0.935689822
+7.458455523 0.962296401 0.934713745 0.998511774 0.937056670
+7.478005865 0.962973211 0.936600065 0.998304577 0.938388818
+7.497556207 0.963634966 0.938492922 0.998099147 0.939687031
+7.517106549 0.964281998 0.940392605 0.997895597 0.940952069
+7.536656891 0.964914631 0.942299402 0.997694036 0.942184685
+7.556207234 0.965533188 0.944213605 0.997494567 0.943385622
+7.575757576 0.966137986 0.946135510 0.997297289 0.944555617
+7.595307918 0.966729334 0.948065413 0.997102296 0.945695397
+7.614858260 0.967307542 0.950003616 0.996909678 0.946805682
+7.634408602 0.967872909 0.951950421 0.996719519 0.947887182
+7.653958944 0.968425733 0.953906137 0.996531899 0.948940596
+7.673509286 0.968966306 0.955871074 0.996346896 0.949966615
+7.693059629 0.969494914 0.957845548 0.996164582 0.950965920
+7.712609971 0.970011839 0.959829876 0.995985025 0.951939181
+7.732160313 0.970517358 0.961824384 0.995808288 0.952887058
+7.751710655 0.971011741 0.963829399 0.995634434 0.953810202
+7.771260997 0.971495257 0.965845253 0.995463518 0.954709250
+7.790811339 0.971968165 0.967872286 0.995295594 0.955584830
+7.810361681 0.972430722 0.969910840 0.995130712 0.956437560
+7.829912023 0.972883181 0.971961266 0.994968918 0.957268046
+7.849462366 0.973325786 0.974023918 0.994810255 0.958076882
+7.869012708 0.973758780 0.976099158 0.994654763 0.958864652
+7.888563050 0.974182400 0.978187355 0.994502479 0.959631929
+7.908113392 0.974596876 0.980288884 0.994353435 0.960379274
+7.927663734 0.975002435 0.982404128 0.994207664 0.961107238
+7.947214076 0.975399300 0.984533476 0.994065193 0.961816357
+7.966764418 0.975787687 0.986677328 0.993926047 0.962507161
+7.986314761 0.976167809 0.988836091 0.993790249 0.963180165
+8.005865103 0.976539873 0.991010180 0.993657817 0.963835875
+8.025415445 0.976904083 0.993200021 0.993528771 0.964474784
+8.044965787 0.977260637 0.995406048 0.993403123 0.965097376
+8.064516129 0.977609728 0.997628707 0.993280887 0.965704121
+8.084066471 0.977951547 0.999868453 0.993162074 0.966295481
+8.103616813 0.978286278 1.002125754 0.993046689 0.966871906
+8.123167155 0.978614101 1.004401089 0.992934740 0.967433834
+8.142717498 0.978935194 1.006694948 0.992826230 0.967981696
+8.162267840 0.979249728 1.009007836 0.992721160 0.968515908
+8.181818182 0.979557870 1.011340271 0.992619530 0.969036877
+8.201368524 0.979859786 1.013692784 0.992521337 0.969545002
+8.220918866 0.980155633 1.016065922 0.992426578 0.970040668
+8.240469208 0.980445569 1.018460248 0.992335245 0.970524254
+8.260019550 0.980729744 1.020876341 0.992247331 0.970996125
+8.279569892 0.981008307 1.023314795 0.992162827 0.971456638
+8.299120235 0.981281401 1.025776226 0.992081721 0.971906142
+8.318670577 0.981549168 1.028261267 0.992004001 0.972344973
+8.338220919 0.981811743 1.030770569 0.991929651 0.972773460
+8.357771261 0.982069259 1.033304807 0.991858657 0.973191923
+8.377321603 0.982321847 1.035864677 0.991791000 0.973600671
+8.396871945 0.982569632 1.038450896 0.991726662 0.974000006
+8.416422287 0.982812738 1.041064207 0.991665623 0.974390219
+8.435972630 0.983051282 1.043705380 0.991607861 0.974771595
+8.455522972 0.983285382 1.046375209 0.991553354 0.975144408
+8.475073314 0.983515150 1.049074518 0.991502077 0.975508927
+8.494623656 0.983740696 1.051804159 0.991454006 0.975865408
+8.514173998 0.983962127 1.054565017 0.991409113 0.976214104
+8.533724340 0.984179547 1.057358011 0.991367372 0.976555258
+8.553274682 0.984393055 1.060184091 0.991328752 0.976889103
+8.572825024 0.984602750 1.063044249 0.991293226 0.977215870
+8.592375367 0.984808728 1.065939511 0.991260762 0.977535777
+8.611925709 0.985011080 1.068870948 0.991231327 0.977849039
+8.631476051 0.985209896 1.071839672 0.991204890 0.978155861
+8.651026393 0.985405263 1.074846843 0.991181417 0.978456444
+8.670576735 0.985597266 1.077893668 0.991160872 0.978750979
+8.690127077 0.985785986 1.080981408 0.991143221 0.979039655
+8.709677419 0.985971504 1.084111376 0.991128426 0.979322649
+8.729227761 0.986153896 1.087284946 0.991116451 0.979600136
+8.748778104 0.986333238 1.090503553 0.991107257 0.979872285
+8.768328446 0.986509602 1.093768697 0.991100805 0.980139256
+8.787878788 0.986683058 1.097081949 0.991097055 0.980401206
+8.807429130 0.986853675 1.100444956 0.991095968 0.980658285
+8.826979472 0.987021520 1.103859443 0.991097502 0.980910639
+8.846529814 0.987186656 1.107327221 0.991101614 0.981158407
+8.866080156 0.987349145 1.110850192 0.991108263 0.981401724
+8.885630499 0.987509049 1.114430354 0.991117404 0.981640720
+8.905180841 0.987666426 1.118069812 0.991128994 0.981875520
+8.924731183 0.987821332 1.121770781 0.991142989 0.982106245
+8.944281525 0.987973822 1.125535597 0.991159342 0.982333009
+8.963831867 0.988123950 1.129366725 0.991178008 0.982555924
+8.983382209 0.988271767 1.133266769 0.991198941 0.982775098
+9.002932551 0.988417324 1.137238482 0.991222093 0.982990633
+9.022482893 0.988560669 1.141284781 0.991247417 0.983202628
+9.042033236 0.988701848 1.145408755 0.991274865 0.983411179
+9.061583578 0.988840908 1.149613685 0.991304388 0.983616377
+9.081133920 0.988977892 1.153903056 0.991335936 0.983818309
+9.100684262 0.989112843 1.158280577 0.991369461 0.984017061
+9.120234604 0.989245803 1.162750199 0.991404910 0.984212713
+9.139784946 0.989376812 1.167316136 0.991442235 0.984405342
+9.159335288 0.989505909 1.171982895 0.991481384 0.984595024
+9.178885630 0.989633131 1.176755294 0.991522305 0.984781831
+9.198435973 0.989758516 1.181638503 0.991564945 0.984965831
+9.217986315 0.989882097 1.186638068 0.991609253 0.985147090
+9.237536657 0.990003911 1.191759957 0.991655175 0.985325671
+9.257086999 0.990123990 1.197010601 0.991702658 0.985501637
+9.276637341 0.990242367 1.202396944 0.991751648 0.985675044
+9.296187683 0.990359073 1.207926497 0.991802091 0.985845950
+9.315738025 0.990474139 1.213607404 0.991853933 0.986014408
+9.335288368 0.990587594 1.219448518 0.991907117 0.986180470
+9.354838710 0.990699467 1.225459479 0.991961589 0.986344185
+9.374389052 0.990809786 1.231650818 0.992017292 0.986505602
+9.393939394 0.990918578 1.238034064 0.992074172 0.986664767
+9.413489736 0.991025869 1.244621880 0.992132171 0.986821723
+9.433040078 0.991131686 1.251428214 0.992191233 0.986976513
+9.452590420 0.991236052 1.258468479 0.992251299 0.987129179
+9.472140762 0.991338993 1.265759770 0.992312314 0.987279759
+9.491691105 0.991440532 1.273321111 0.992374218 0.987428291
+9.511241447 0.991540692 0.992164312 0.992436955 0.987575668
+9.530791789 0.991639495 0.992262666 0.992500464 0.987720028
+9.550342131 0.991736963 0.992359625 0.992564688 0.987862482
+9.569892473 0.991833119 0.992455211 0.992629568 0.988003057
+9.589442815 0.991927981 0.992549446 0.992695043 0.988141779
+9.608993157 0.992021572 0.992642351 0.992761056 0.988278677
+9.628543500 0.992113910 0.992733945 0.992827544 0.988413775
+9.648093842 0.992205015 0.992824249 0.992894449 0.988547100
+9.667644184 0.992294906 0.992913284 0.992961710 0.988678678
+9.687194526 0.992383601 0.993001068 0.993029266 0.988808533
+9.706744868 0.992471119 0.993087620 0.993097056 0.988936690
+9.726295210 0.992557478 0.993172960 0.993165018 0.989063173
+9.745845552 0.992642695 0.993257106 0.993233092 0.989188007
+9.765395894 0.992726786 0.993340077 0.993301216 0.989311215
+9.784946237 0.992809769 0.993421890 0.993369327 0.989432820
+9.804496579 0.992891660 0.993502563 0.993437363 0.989552846
+9.824046921 0.992972476 0.993582113 0.993505262 0.989671314
+9.843597263 0.993052231 0.993660558 0.993572961 0.989788247
+9.863147605 0.993130943 0.993737915 0.993640397 0.989903667
+9.882697947 0.993208625 0.993814199 0.993707507 0.990017596
+9.902248289 0.993285293 0.993889428 0.993774227 0.990130054
+9.921798631 0.993360962 0.993963617 0.993840495 0.990241062
+9.941348974 0.993435646 0.994036782 0.993906246 0.990350642
+9.960899316 0.993509359 0.994108939 0.993971416 0.990458813
+9.980449658 0.993582116 0.994180103 0.994035940 0.990565596
+10.000000000 0.993653931 0.994250289 0.994099756 0.990671009
diff --git a/examples/tsukamoto/tsukamoto.fll b/examples/tsukamoto/tsukamoto.fll
new file mode 100644
index 0000000..0437d5d
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.fll
@@ -0,0 +1,61 @@
+Engine: tsukamoto
+InputVariable: X
+ enabled: true
+ range: -10.000 10.000
+ lock-range: false
+ term: small Bell -10.000 5.000 3.000
+ term: medium Bell 0.000 5.000 3.000
+ term: large Bell 10.000 5.000 3.000
+OutputVariable: Ramps
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b Ramp 0.600 0.400
+ term: a Ramp 0.000 0.250
+ term: c Ramp 0.700 1.000
+OutputVariable: Sigmoids
+ enabled: true
+ range: 0.020 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b Sigmoid 0.500 -30.000
+ term: a Sigmoid 0.130 30.000
+ term: c Sigmoid 0.830 30.000
+OutputVariable: ZSShapes
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b ZShape 0.300 0.600
+ term: a SShape 0.000 0.250
+ term: c SShape 0.700 1.000
+OutputVariable: Concaves
+ enabled: true
+ range: 0.000 1.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage Automatic
+ default: nan
+ lock-previous: false
+ term: b Concave 0.500 0.400
+ term: a Concave 0.240 0.250
+ term: c Concave 0.900 1.000
+RuleBlock:
+ enabled: true
+ conjunction: none
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if X is small then Ramps is a and Sigmoids is a and ZSShapes is a and Concaves is a
+ rule: if X is medium then Ramps is b and Sigmoids is b and ZSShapes is b and Concaves is b
+ rule: if X is large then Ramps is c and Sigmoids is c and ZSShapes is c and Concaves is c \ No newline at end of file
diff --git a/examples/tsukamoto/tsukamoto.java b/examples/tsukamoto/tsukamoto.java
new file mode 100644
index 0000000..f51d968
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.java
@@ -0,0 +1,108 @@
+import com.fuzzylite.*;
+import com.fuzzylite.activation.*
+import com.fuzzylite.defuzzifier.*;
+import com.fuzzylite.factory.*;
+import com.fuzzylite.hedge.*;
+import com.fuzzylite.imex.*;
+import com.fuzzylite.norm.*;
+import com.fuzzylite.norm.s.*;
+import com.fuzzylite.norm.t.*;
+import com.fuzzylite.rule.*;
+import com.fuzzylite.term.*;
+import com.fuzzylite.variable.*;
+
+public class tsukamoto{
+public static void main(String[] args){
+//Code automatically generated with fuzzylite 6.0.
+
+Engine engine = new Engine();
+engine.setName("tsukamoto");
+engine.setDescription("");
+
+InputVariable X = new InputVariable();
+X.setName("X");
+X.setDescription("");
+X.setEnabled(true);
+X.setRange(-10.000, 10.000);
+X.setLockValueInRange(false);
+X.addTerm(new Bell("small", -10.000, 5.000, 3.000));
+X.addTerm(new Bell("medium", 0.000, 5.000, 3.000));
+X.addTerm(new Bell("large", 10.000, 5.000, 3.000));
+engine.addInputVariable(X);
+
+OutputVariable Ramps = new OutputVariable();
+Ramps.setName("Ramps");
+Ramps.setDescription("");
+Ramps.setEnabled(true);
+Ramps.setRange(0.000, 1.000);
+Ramps.setLockValueInRange(false);
+Ramps.setAggregation(null);
+Ramps.setDefuzzifier(new WeightedAverage("Automatic"));
+Ramps.setDefaultValue(Double.NaN);
+Ramps.setLockPreviousValue(false);
+Ramps.addTerm(new Ramp("b", 0.600, 0.400));
+Ramps.addTerm(new Ramp("a", 0.000, 0.250));
+Ramps.addTerm(new Ramp("c", 0.700, 1.000));
+engine.addOutputVariable(Ramps);
+
+OutputVariable Sigmoids = new OutputVariable();
+Sigmoids.setName("Sigmoids");
+Sigmoids.setDescription("");
+Sigmoids.setEnabled(true);
+Sigmoids.setRange(0.020, 1.000);
+Sigmoids.setLockValueInRange(false);
+Sigmoids.setAggregation(null);
+Sigmoids.setDefuzzifier(new WeightedAverage("Automatic"));
+Sigmoids.setDefaultValue(Double.NaN);
+Sigmoids.setLockPreviousValue(false);
+Sigmoids.addTerm(new Sigmoid("b", 0.500, -30.000));
+Sigmoids.addTerm(new Sigmoid("a", 0.130, 30.000));
+Sigmoids.addTerm(new Sigmoid("c", 0.830, 30.000));
+engine.addOutputVariable(Sigmoids);
+
+OutputVariable ZSShapes = new OutputVariable();
+ZSShapes.setName("ZSShapes");
+ZSShapes.setDescription("");
+ZSShapes.setEnabled(true);
+ZSShapes.setRange(0.000, 1.000);
+ZSShapes.setLockValueInRange(false);
+ZSShapes.setAggregation(null);
+ZSShapes.setDefuzzifier(new WeightedAverage("Automatic"));
+ZSShapes.setDefaultValue(Double.NaN);
+ZSShapes.setLockPreviousValue(false);
+ZSShapes.addTerm(new ZShape("b", 0.300, 0.600));
+ZSShapes.addTerm(new SShape("a", 0.000, 0.250));
+ZSShapes.addTerm(new SShape("c", 0.700, 1.000));
+engine.addOutputVariable(ZSShapes);
+
+OutputVariable Concaves = new OutputVariable();
+Concaves.setName("Concaves");
+Concaves.setDescription("");
+Concaves.setEnabled(true);
+Concaves.setRange(0.000, 1.000);
+Concaves.setLockValueInRange(false);
+Concaves.setAggregation(null);
+Concaves.setDefuzzifier(new WeightedAverage("Automatic"));
+Concaves.setDefaultValue(Double.NaN);
+Concaves.setLockPreviousValue(false);
+Concaves.addTerm(new Concave("b", 0.500, 0.400));
+Concaves.addTerm(new Concave("a", 0.240, 0.250));
+Concaves.addTerm(new Concave("c", 0.900, 1.000));
+engine.addOutputVariable(Concaves);
+
+RuleBlock ruleBlock = new RuleBlock();
+ruleBlock.setName("");
+ruleBlock.setDescription("");
+ruleBlock.setEnabled(true);
+ruleBlock.setConjunction(null);
+ruleBlock.setDisjunction(null);
+ruleBlock.setImplication(null);
+ruleBlock.setActivation(new General());
+ruleBlock.addRule(Rule.parse("if X is small then Ramps is a and Sigmoids is a and ZSShapes is a and Concaves is a", engine));
+ruleBlock.addRule(Rule.parse("if X is medium then Ramps is b and Sigmoids is b and ZSShapes is b and Concaves is b", engine));
+ruleBlock.addRule(Rule.parse("if X is large then Ramps is c and Sigmoids is c and ZSShapes is c and Concaves is c", engine));
+engine.addRuleBlock(ruleBlock);
+
+
+}
+}
diff --git a/examples/tsukamoto/tsukamoto.pdf b/examples/tsukamoto/tsukamoto.pdf
new file mode 100644
index 0000000..9c4f375
--- /dev/null
+++ b/examples/tsukamoto/tsukamoto.pdf
Binary files differ
diff --git a/fuzzylite.png b/fuzzylite.png
new file mode 100644
index 0000000..52909ac
--- /dev/null
+++ b/fuzzylite.png
Binary files differ
diff --git a/fuzzylite.svg b/fuzzylite.svg
new file mode 100644
index 0000000..ec4e104
--- /dev/null
+++ b/fuzzylite.svg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2">
+<title>QtFuzzyLite</title>
+<desc>A fuzzy logic control library and application</desc>
+<defs>
+ <linearGradient
+ id="linearGradient3000"
+ x1="0%"
+ y1="0%"
+ x2="100%"
+ y2="100%">
+ <stop style="stop-color:#ffffAA;stop-opacity:1;" offset="0" />
+ <stop style="stop-color:#FF8A8A;stop-opacity:1;" offset="1" />
+ </linearGradient>
+
+ <linearGradient id="border-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
+ <stop offset="0%" style="stop-color:#808000;stop-opacity:1" />
+ <stop offset="100%" style="stop-color:#800000;stop-opacity:1" />
+ </linearGradient>
+
+ <rect id='background' width='100' height='100' x='0' y='0' rx='0' ry='0' style='fill:none;fill:url(#linearGradient3000); stroke:url(#border-gradient);stroke-width:5;stroke-linecap: round;stroke-linejoin: round '/>
+ <polygon id='low' points='0,0 25,100 50,0' />
+ <polygon id='medium' points='25,0 50,100 75,0' />
+ <polygon id='high' points='50,0 75,100 100,0' />
+ <polygon id='fuzzy' points='25,0 34,36 59,36 65.95,64 84.1,64 100,0' />
+
+ <g id='fl' style='stroke:black;stroke-width:3;stroke-linecap: round;stroke-linejoin: round ' >
+ <use xlink:href='#low' style='fill:#ffff00; stroke:#808000;'/>
+ <use xlink:href='#medium' style='fill:#ff8000; stroke:#803f00;'/>
+ <use xlink:href='#high' style='fill:#ff0000; stroke:#800000;'/>
+ <use xlink:href='#fuzzy' style='fill:#00d200; stroke:#008000;'/>
+ <!-- <rect width="100" height="100" style="stroke:black; fill: none"/> -->
+ </g>
+</defs>
+ <use xlink:href='#background' transform='scale(1.28,1.28)'/>
+ <use xlink:href='#fl' transform='translate(0, 100) scale(1,-.95)' x='14' y='-12'/>
+
+ <!-- <line x1="50%" y1="0%" x2="50%" y2="100%" style="stroke:black; stroke-width:2"/>
+ <line x1="0%" y1="50%" x2="100%" y2="50%" style="stroke:black; stroke-width:2"/> -->
+
+
+</svg>
diff --git a/fuzzylite/CMakeLists.txt b/fuzzylite/CMakeLists.txt
new file mode 100644
index 0000000..28435e2
--- /dev/null
+++ b/fuzzylite/CMakeLists.txt
@@ -0,0 +1,301 @@
+cmake_minimum_required(VERSION 2.8.8)
+
+if (APPLE)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
+endif()
+
+project(fuzzylite CXX)
+
+
+if (APPLE)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+if (MSVC)
+ cmake_policy(SET CMP0054 NEW)
+endif()
+
+
+###DEFINES SECTION
+if(NOT CMAKE_VERBOSE_MAKEFILE)
+ set(CMAKE_VERBOSE_MAKEFILE false)
+endif()
+
+if( NOT CMAKE_BUILD_TYPE )
+ set( CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE )
+endif()
+
+add_definitions(-DFL_BUILD_PATH="${CMAKE_SOURCE_DIR}") #used to determine FL__FILE__
+
+option(FL_BUILD_SHARED "Build shared library" ON)
+option(FL_BUILD_STATIC "Build static library" ON)
+if(FL_BUILD_SHARED)
+ option(FL_BUILD_BINARY "Build fuzzylite binary" ON)
+endif()
+
+option(FL_CPP98 "Builds utilizing C++98, i.e., passing -std=c++98" OFF)
+option(FL_USE_FLOAT "Use fl::scalar as float" OFF)
+option(FL_BACKTRACE "Provide backtrace information in case of errors" ON)
+
+option(FL_BUILD_TESTS "Builds the unit tests" ON)
+
+if(FL_USE_FLOAT)
+ add_definitions(-DFL_USE_FLOAT)
+endif(FL_USE_FLOAT)
+
+if(FL_BACKTRACE)
+ add_definitions(-DFL_BACKTRACE)
+endif()
+
+if (MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19)
+#C++11 not available before Visual Studio 2015
+ if (NOT FL_CPP98)
+ set(FL_CPP98 ON)
+ endif()
+endif()
+
+if(FL_CPP98)
+ add_definitions(-DFL_CPP98)
+ if(NOT MSVC)
+ #Set C++98 by default in Clang and others
+ add_definitions(-std=c++98)
+ endif()
+else()
+ if(NOT MSVC)
+ #Set C++11 by default in Clang and others
+ add_definitions(-std=c++11)
+ endif()
+endif(FL_CPP98)
+
+#Put all binaries in same location
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY bin)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
+
+if(NOT MSVC)
+#TODO: Remove -Werror before release.
+#Add Unix compilation flags
+ set(CMAKE_CXX_FLAGS "-pedantic -Wall -Wextra -Werror ${CMAKE_CXX_FLAGS}")
+
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+
+ if(NOT APPLE)
+ set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_SHARED_LINKER_FLAGS}") #To avoid undefined methods in library
+ endif()
+endif()
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+#Address fl::null errors of literal null conversion
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-non-literal-null-conversion")
+endif()
+
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 6)
+ #In GNU gcc v6, the default is C++11
+ if (FL_CPP98)
+ #set the default to C++98
+ #Fix error: 'template<class> class std::auto_ptr' is deprecated with gcc-6
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++98")
+ endif()
+ endif()
+ #In GNU gcc 4.7, Op::str(T, std::size_t(0)) raises a warning of type-limits
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-type-limits")
+ endif()
+endif()
+
+
+set(FL_LIBS)
+
+if(MSVC)
+#Set compilation flags in Windows
+ set(CMAKE_CXX_FLAGS "/W4 /EHsc")
+ #Wx: Treat warnings as errors. W4: All warnings
+ #http://msdn.microsoft.com/en-us/library/thxezb7y.aspx
+ #EHsc: call destructors on __try __catch, and to ignore C4530: C++ exception handler used. Note, unwind semantics are not enabled
+ #Add Backtrace library
+ if (FL_BACKTRACE)
+ set(FL_LIBS dbghelp)
+ endif()
+endif()
+
+
+if(APPLE)
+#Fix ld: symbol(s) not found for architecture x86_64 on mac
+ set(FL_LIBS stdc++)
+endif()
+
+
+###BUILD SECTION
+
+include_directories(.)
+
+file(STRINGS FL_HEADERS fl-headers)
+file(STRINGS FL_SOURCES fl-sources)
+file(STRINGS FL_TESTS fl-tests)
+
+string(REGEX REPLACE "\n" " " ${fl-headers} ${fl-headers})
+string(REGEX REPLACE "\n" " " ${fl-sources} ${fl-sources})
+string(REGEX REPLACE "\n" " " ${fl-tests} ${fl-tests})
+
+message("${exepath}")
+
+
+set(CMAKE_DEBUG_POSTFIX debug)
+
+if (MSVC OR CMAKE_GENERATOR STREQUAL Xcode)
+ if(FL_BUILD_SHARED)
+ add_library(fl-shared SHARED ${fl-headers} ${fl-sources})
+ endif()
+
+ if(FL_BUILD_STATIC)
+ add_library(fl-static STATIC ${fl-headers} ${fl-sources})
+ endif()
+else()
+ if(FL_BUILD_SHARED OR FL_BUILD_STATIC)
+ add_library(fl-obj OBJECT ${fl-headers} ${fl-sources})
+ if(NOT MINGW)
+ set_target_properties(fl-obj PROPERTIES COMPILE_FLAGS "-fPIC")
+ endif()
+ endif()
+
+ if(FL_BUILD_SHARED)
+ add_library(fl-shared SHARED $<TARGET_OBJECTS:fl-obj>)
+ endif(FL_BUILD_SHARED)
+
+ if(FL_BUILD_STATIC)
+ add_library(fl-static STATIC $<TARGET_OBJECTS:fl-obj>)
+ endif(FL_BUILD_STATIC)
+endif()
+
+if(FL_BUILD_SHARED)
+ set_target_properties(fl-shared PROPERTIES OUTPUT_NAME fuzzylite)
+ set_target_properties(fl-shared PROPERTIES DEBUG_POSTFIX -debug)
+ target_compile_definitions(fl-shared PRIVATE FL_EXPORT_LIBRARY)
+ set_target_properties(fl-shared PROPERTIES VERSION 6.0)
+ target_link_libraries(fl-shared ${FL_LIBS})
+endif()
+
+if(FL_BUILD_STATIC)
+ set_target_properties(fl-static PROPERTIES OUTPUT_NAME fuzzylite-static)
+ set_target_properties(fl-static PROPERTIES DEBUG_POSTFIX -debug)
+ set_target_properties(fl-static PROPERTIES VERSION 6.0)
+ target_link_libraries(fl-static ${FL_LIBS})
+endif()
+
+if(FL_BUILD_BINARY)
+ add_executable(fl-bin src/main.cpp)
+ set_target_properties(fl-bin PROPERTIES OUTPUT_NAME fuzzylite)
+ set_target_properties(fl-bin PROPERTIES OUTPUT_NAME fuzzylite IMPORT_PREFIX tmp-) #To prevent LNK1149 in Windows
+ set_target_properties(fl-bin PROPERTIES DEBUG_POSTFIX -debug)
+ target_compile_definitions(fl-bin PRIVATE FL_IMPORT_LIBRARY) #if building with fl-shared
+ target_link_libraries(fl-bin fl-shared ${FL_LIBS})
+endif(FL_BUILD_BINARY)
+
+if(FL_BUILD_TESTS)
+ add_executable(fl-test ${fl-headers} ${fl-tests})
+ set_target_properties(fl-test PROPERTIES OUTPUT_NAME fuzzylite-tests)
+ set_target_properties(fl-test PROPERTIES OUTPUT_NAME fuzzylite-tests IMPORT_PREFIX tmp-) #To prevent LNK1149 in Windows
+ set_target_properties(fl-test PROPERTIES DEBUG_POSTFIX -debug)
+
+ target_compile_definitions(fl-test PRIVATE FL_IMPORT_LIBRARY)
+ if (FL_CPP98)
+ target_compile_definitions(fl-test PRIVATE CATCH_CONFIG_NO_CPP11)
+ endif()
+
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ #Ignore QuickTest macro expansion comparison: CHECK(xstr(4+10) == "4+10")
+ target_compile_options(fl-test PRIVATE -Wno-address)
+ endif()
+ if (MSVC)
+ target_compile_options(fl-test PRIVATE /wd4130)
+ endif()
+
+ target_link_libraries(fl-test fl-shared ${FL_LIBS})
+
+ enable_testing()
+ add_test(NAME RunTests COMMAND fl-test)
+# add_test(NAME ListTests COMMAND fl-test --list-tests)
+# set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test case")
+# add_test(NAME ListTags COMMAND fl-test --list-tags)
+# set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tag")
+endif()
+
+###INSTALL SECTION
+if(NOT FL_INSTALL_BINDIR)
+ set(FL_INSTALL_BINDIR bin)
+endif()
+
+if(NOT FL_INSTALL_LIBDIR)
+ if(NOT CMAKE_INSTALL_LIBDIR)
+ set(FL_INSTALL_LIBDIR lib)
+ else()
+ set(FL_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR})
+ endif()
+endif()
+
+if(FL_BUILD_BINARY)
+ install(TARGETS fl-bin
+ RUNTIME DESTINATION ${FL_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${FL_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${FL_INSTALL_LIBDIR}
+ )
+endif()
+
+if(FL_BUILD_SHARED)
+ install(TARGETS fl-shared
+ RUNTIME DESTINATION ${FL_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${FL_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${FL_INSTALL_LIBDIR}
+ )
+endif()
+
+if(FL_BUILD_STATIC)
+ install(TARGETS fl-static
+ RUNTIME DESTINATION ${FL_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${FL_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${FL_INSTALL_LIBDIR}
+ )
+endif()
+
+install(DIRECTORY fl/ DESTINATION include/fl)
+
+#pkg-config
+configure_file(${CMAKE_SOURCE_DIR}/fuzzylite.pc.in ${CMAKE_BINARY_DIR}/fuzzylite.pc @ONLY)
+install(FILES ${CMAKE_BINARY_DIR}/fuzzylite.pc DESTINATION ${FL_INSTALL_LIBDIR}/pkgconfig)
+
+message("=====================================")
+message("fuzzylite v6.0\n")
+message("FL_CPP98=${FL_CPP98}")
+message("FL_USE_FLOAT=${FL_USE_FLOAT}")
+message("FL_BACKTRACE=${FL_BACKTRACE}")
+message("FL_LIBS=${FL_LIBS}")
+message("FL_INSTALL_BINDIR=${FL_INSTALL_BINDIR}")
+message("FL_INSTALL_LIBDIR=${FL_INSTALL_LIBDIR}")
+message("FL_BUILD_TESTS=${FL_BUILD_TESTS}")
+message("")
+message("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
+message("CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}")
+message("CMAKE_CXX_COMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION}")
+message("CMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}")
+message("CMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
+message("COMPILE_DEFINITIONS:")
+get_directory_property(fl-definitions DIRECTORY ${CMAKE_SOURCE_DIR} COMPILE_DEFINITIONS )
+foreach(d ${fl-definitions})
+ message( STATUS "Defined: " ${d} )
+endforeach()
+
+message("=====================================\n")
+
+###UNINSTALL SECTION
+#configure_file(
+ #"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ #"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ #IMMEDIATE @ONLY)
+
+#add_custom_target(uninstall
+ #COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake)
+
+#unix uninstall
+#xargs rm < install_manifest.txt
diff --git a/fuzzylite/FL_HEADERS b/fuzzylite/FL_HEADERS
new file mode 100644
index 0000000..b852ad8
--- /dev/null
+++ b/fuzzylite/FL_HEADERS
@@ -0,0 +1,111 @@
+fl/Benchmark.h
+fl/Complexity.h
+fl/Console.h
+fl/activation/Activation.h
+fl/activation/First.h
+fl/activation/General.h
+fl/activation/Highest.h
+fl/activation/Last.h
+fl/activation/Lowest.h
+fl/activation/Proportional.h
+fl/activation/Threshold.h
+fl/defuzzifier/Bisector.h
+fl/defuzzifier/Centroid.h
+fl/defuzzifier/Defuzzifier.h
+fl/defuzzifier/IntegralDefuzzifier.h
+fl/defuzzifier/LargestOfMaximum.h
+fl/defuzzifier/MeanOfMaximum.h
+fl/defuzzifier/SmallestOfMaximum.h
+fl/defuzzifier/WeightedAverage.h
+fl/defuzzifier/WeightedAverageCustom.h
+fl/defuzzifier/WeightedDefuzzifier.h
+fl/defuzzifier/WeightedSum.h
+fl/defuzzifier/WeightedSumCustom.h
+fl/Engine.h
+fl/Exception.h
+fl/factory/ActivationFactory.h
+fl/factory/CloningFactory.h
+fl/factory/ConstructionFactory.h
+fl/factory/DefuzzifierFactory.h
+fl/factory/FactoryManager.h
+fl/factory/FunctionFactory.h
+fl/factory/HedgeFactory.h
+fl/factory/SNormFactory.h
+fl/factory/TermFactory.h
+fl/factory/TNormFactory.h
+fl/fuzzylite.h
+fl/Headers.h
+fl/hedge/Any.h
+fl/hedge/Extremely.h
+fl/hedge/Hedge.h
+fl/hedge/HedgeFunction.h
+fl/hedge/Not.h
+fl/hedge/Seldom.h
+fl/hedge/Somewhat.h
+fl/hedge/Very.h
+fl/imex/CppExporter.h
+fl/imex/Exporter.h
+fl/imex/FclExporter.h
+fl/imex/FclImporter.h
+fl/imex/FisExporter.h
+fl/imex/FisImporter.h
+fl/imex/FldExporter.h
+fl/imex/FllExporter.h
+fl/imex/FllImporter.h
+fl/imex/Importer.h
+fl/imex/JavaExporter.h
+fl/imex/RScriptExporter.h
+fl/norm/Norm.h
+fl/norm/s/AlgebraicSum.h
+fl/norm/s/BoundedSum.h
+fl/norm/s/DrasticSum.h
+fl/norm/s/EinsteinSum.h
+fl/norm/s/HamacherSum.h
+fl/norm/s/Maximum.h
+fl/norm/s/NilpotentMaximum.h
+fl/norm/s/NormalizedSum.h
+fl/norm/s/SNormFunction.h
+fl/norm/s/UnboundedSum.h
+fl/norm/SNorm.h
+fl/norm/t/AlgebraicProduct.h
+fl/norm/t/BoundedDifference.h
+fl/norm/t/DrasticProduct.h
+fl/norm/t/EinsteinProduct.h
+fl/norm/t/HamacherProduct.h
+fl/norm/t/Minimum.h
+fl/norm/t/NilpotentMinimum.h
+fl/norm/t/TNormFunction.h
+fl/norm/TNorm.h
+fl/Operation.h
+fl/rule/Antecedent.h
+fl/rule/Consequent.h
+fl/rule/Expression.h
+fl/rule/RuleBlock.h
+fl/rule/Rule.h
+fl/term/Activated.h
+fl/term/Aggregated.h
+fl/term/Bell.h
+fl/term/Binary.h
+fl/term/Concave.h
+fl/term/Constant.h
+fl/term/Cosine.h
+fl/term/Discrete.h
+fl/term/Function.h
+fl/term/Gaussian.h
+fl/term/GaussianProduct.h
+fl/term/Linear.h
+fl/term/PiShape.h
+fl/term/Ramp.h
+fl/term/Rectangle.h
+fl/term/SigmoidDifference.h
+fl/term/Sigmoid.h
+fl/term/SigmoidProduct.h
+fl/term/Spike.h
+fl/term/SShape.h
+fl/term/Term.h
+fl/term/Trapezoid.h
+fl/term/Triangle.h
+fl/term/ZShape.h
+fl/variable/InputVariable.h
+fl/variable/OutputVariable.h
+fl/variable/Variable.h
diff --git a/fuzzylite/FL_SOURCES b/fuzzylite/FL_SOURCES
new file mode 100644
index 0000000..16d8ab4
--- /dev/null
+++ b/fuzzylite/FL_SOURCES
@@ -0,0 +1,102 @@
+src/Benchmark.cpp
+src/Complexity.cpp
+src/Console.cpp
+src/activation/First.cpp
+src/activation/General.cpp
+src/activation/Highest.cpp
+src/activation/Last.cpp
+src/activation/Lowest.cpp
+src/activation/Proportional.cpp
+src/activation/Threshold.cpp
+src/defuzzifier/Bisector.cpp
+src/defuzzifier/Centroid.cpp
+src/defuzzifier/IntegralDefuzzifier.cpp
+src/defuzzifier/LargestOfMaximum.cpp
+src/defuzzifier/MeanOfMaximum.cpp
+src/defuzzifier/SmallestOfMaximum.cpp
+src/defuzzifier/WeightedAverage.cpp
+src/defuzzifier/WeightedAverageCustom.cpp
+src/defuzzifier/WeightedDefuzzifier.cpp
+src/defuzzifier/WeightedSum.cpp
+src/defuzzifier/WeightedSumCustom.cpp
+src/Engine.cpp
+src/Exception.cpp
+src/factory/ActivationFactory.cpp
+src/factory/DefuzzifierFactory.cpp
+src/factory/FactoryManager.cpp
+src/factory/FunctionFactory.cpp
+src/factory/HedgeFactory.cpp
+src/factory/SNormFactory.cpp
+src/factory/TermFactory.cpp
+src/factory/TNormFactory.cpp
+src/fuzzylite.cpp
+src/hedge/Any.cpp
+src/hedge/Extremely.cpp
+src/hedge/HedgeFunction.cpp
+src/hedge/Not.cpp
+src/hedge/Seldom.cpp
+src/hedge/Somewhat.cpp
+src/hedge/Very.cpp
+src/imex/CppExporter.cpp
+src/imex/Exporter.cpp
+src/imex/FclExporter.cpp
+src/imex/FclImporter.cpp
+src/imex/FisExporter.cpp
+src/imex/FisImporter.cpp
+src/imex/FldExporter.cpp
+src/imex/FllExporter.cpp
+src/imex/FllImporter.cpp
+src/imex/Importer.cpp
+src/imex/JavaExporter.cpp
+src/imex/RScriptExporter.cpp
+src/main.cpp
+src/norm/s/AlgebraicSum.cpp
+src/norm/s/BoundedSum.cpp
+src/norm/s/DrasticSum.cpp
+src/norm/s/EinsteinSum.cpp
+src/norm/s/HamacherSum.cpp
+src/norm/s/Maximum.cpp
+src/norm/s/NilpotentMaximum.cpp
+src/norm/s/NormalizedSum.cpp
+src/norm/s/SNormFunction.cpp
+src/norm/s/UnboundedSum.cpp
+src/norm/t/AlgebraicProduct.cpp
+src/norm/t/BoundedDifference.cpp
+src/norm/t/DrasticProduct.cpp
+src/norm/t/EinsteinProduct.cpp
+src/norm/t/HamacherProduct.cpp
+src/norm/t/Minimum.cpp
+src/norm/t/NilpotentMinimum.cpp
+src/norm/t/TNormFunction.cpp
+src/rule/Antecedent.cpp
+src/rule/Consequent.cpp
+src/rule/Expression.cpp
+src/rule/RuleBlock.cpp
+src/rule/Rule.cpp
+src/term/Activated.cpp
+src/term/Aggregated.cpp
+src/term/Bell.cpp
+src/term/Binary.cpp
+src/term/Concave.cpp
+src/term/Constant.cpp
+src/term/Cosine.cpp
+src/term/Discrete.cpp
+src/term/Function.cpp
+src/term/Gaussian.cpp
+src/term/GaussianProduct.cpp
+src/term/Linear.cpp
+src/term/PiShape.cpp
+src/term/Ramp.cpp
+src/term/Rectangle.cpp
+src/term/Sigmoid.cpp
+src/term/SigmoidDifference.cpp
+src/term/SigmoidProduct.cpp
+src/term/Spike.cpp
+src/term/SShape.cpp
+src/term/Term.cpp
+src/term/Trapezoid.cpp
+src/term/Triangle.cpp
+src/term/ZShape.cpp
+src/variable/InputVariable.cpp
+src/variable/OutputVariable.cpp
+src/variable/Variable.cpp
diff --git a/fuzzylite/FL_TESTS b/fuzzylite/FL_TESTS
new file mode 100644
index 0000000..3897a77
--- /dev/null
+++ b/fuzzylite/FL_TESTS
@@ -0,0 +1,16 @@
+test/catch.hpp
+test/MainTest.cpp
+test/BenchmarkTest.cpp
+test/QuickTest.cpp
+test/activation/ThresholdTest.cpp
+test/hedge/HedgeFunctionTest.cpp
+test/imex/FldExporterTest.cpp
+test/imex/FllImporterTest.cpp
+test/imex/RScriptExporterTest.cpp
+test/norm/NormFunctionTest.cpp
+test/term/AggregatedTest.cpp
+test/term/DiscreteTest.cpp
+test/term/FunctionTest.cpp
+test/term/TrapezoidTest.cpp
+test/term/TriangleTest.cpp
+test/variable/VariableTest.cpp
diff --git a/fuzzylite/build.bat b/fuzzylite/build.bat
new file mode 100644
index 0000000..11f62f8
--- /dev/null
+++ b/fuzzylite/build.bat
@@ -0,0 +1,122 @@
+@echo off
+setlocal EnableDelayedExpansion
+set argc=0
+set valid="no"
+
+for %%a in (%*) do (
+ set /A argc+=1
+ if /I "%%a"=="help" (
+ call:usage
+ goto:eof
+ )
+ if /I "%%a"=="all" set valid="yes"
+ if /I "%%a"=="release" set valid="yes"
+ if /I "%%a"=="debug" set valid="yes"
+ if /I "%%a"=="clean" set valid="yes"
+ if /I "%%a"=="documentation" set valid="yes"
+
+ if !valid!=="no" (
+ echo Invalid option: %%a
+ call:usage
+ goto:eof
+ )
+)
+
+if %argc%==0 echo Building schedule: all
+if not %argc%==0 echo Building schedule: %*
+echo Starting in 3 seconds...
+ping 1.1.1.1 -n 1 -w 3000 > nul
+rem sleep 3 ::This function makes command line DOS-esque C:\Archiv~1
+
+if %argc%==0 (call:all)
+
+for %%a in (%*) do (call:%%a)
+
+goto:eof
+
+:debug
+ echo.
+ echo.
+ echo ****************************************
+ echo STARTING: debug
+
+ if not exist debug mkdir debug
+ cd debug
+ cmake .. -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Debug -DFL_BACKTRACE=ON -DFL_USE_FLOAT=OFF -DFL_CPP98=OFF -DFL_BUILD_TESTS=ON
+ nmake
+ cd ..
+
+ echo.
+ echo FINISHED: debug
+ echo ****************************************
+ goto:eof
+
+:release
+ echo.
+ echo.
+ echo ****************************************
+ echo STARTING: release
+
+ if not exist release mkdir release
+ cd release
+ cmake .. -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DFL_BACKTRACE=OFF -DFL_USE_FLOAT=OFF -DFL_CPP98=OFF -DFL_BUILD_TESTS=ON
+ nmake
+ cd ..
+
+ echo.
+ echo FINISHED: release
+ echo ****************************************
+ goto:eof
+
+:all
+ echo.
+ echo.
+ echo ****************************************
+ echo STARTING: all
+ call:release
+ call:debug
+ echo.
+ echo FINISHED: all
+ echo ****************************************
+ goto:eof
+
+:documentation
+ echo.
+ echo.
+ echo ****************************************
+ echo STARTING: documentation
+
+ cd ..
+ doxygen
+ rem TODO: cd back to previous directory. Maybe use: cd /D %~dp0
+ echo.
+ echo FINISHED: documentation
+ echo ****************************************
+ goto:eof
+:clean
+ echo.
+ echo.
+ echo ****************************************
+ echo STARTING: clean
+ @echo on
+ if exist debug rmdir /S /Q debug
+ if exist release rmdir /S /Q release
+ if exist CMakeFiles rmdir /S /Q CMakeFiles
+ if exist CMakeCache.txt del CMakeCache.txt
+ @echo off
+ echo.
+ echo FINISHED: clean
+ echo ****************************************
+ goto:eof
+
+:usage
+ echo Usage: build.bat [options]
+ echo where [options] can be any of the following:
+ echo ^ all builds fuzzylite in debug and release mode (default)
+ echo ^ debug builds fuzzylite in debug mode
+ echo ^ release builds fuzzylite in release mode
+ echo ^ clean erases previous builds
+ echo ^ help shows this information
+ echo.
+
+ENDLOCAL
diff --git a/fuzzylite/build.sh b/fuzzylite/build.sh
new file mode 100755
index 0000000..da39905
--- /dev/null
+++ b/fuzzylite/build.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+if [ -z "$FL_USE_FLOAT" ]; then
+ FL_USE_FLOAT="OFF"
+fi
+
+if [ -z "$FL_CPP98" ]; then
+ FL_CPP98="OFF"
+fi
+
+if [ -z "$FL_BUILD_TESTS" ]; then
+ FL_BUILD_TESTS="OFF"
+fi
+
+debug(){
+ set -e
+ mkdir -p debug
+ cd debug
+ cmake .. -G"Unix Makefiles" -DFL_USE_FLOAT=${FL_USE_FLOAT} -DFL_CPP98=${FL_CPP98} -DCMAKE_BUILD_TYPE=Debug -DFL_BACKTRACE=ON -DFL_BUILD_TESTS=${FL_BUILD_TESTS}
+ make all
+ if [ "${FL_BUILD_TESTS}" == "ON" ]; then
+ (export CTEST_OUTPUT_ON_FAILURE=TRUE; make test)
+ fi
+ cd ..
+}
+
+release(){
+ set -e
+ mkdir -p release
+ cd release
+ cmake .. -G"Unix Makefiles" -DFL_USE_FLOAT=${FL_USE_FLOAT} -DFL_CPP98=${FL_CPP98} -DCMAKE_BUILD_TYPE=Release -DFL_BACKTRACE=ON -DFL_BUILD_TESTS=${FL_BUILD_TESTS}
+ make all
+ if [ "${FL_BUILD_TESTS}" == "ON" ]; then
+ (export CTEST_OUTPUT_ON_FAILURE=TRUE; make test)
+ fi
+ cd ..
+}
+
+documentation(){
+ set -e
+ cd ..
+ doxygen Doxyfile
+ cd -
+}
+
+all(){
+ debug
+ release
+}
+
+clean(){
+ rm -rf release debug CMakeFiles
+}
+
+usage(){
+ printf 'Usage:\t[bash] ./build.sh [options]\n'
+ printf "where\t[options] can be any of the following:\n"
+ printf "\tall\t\t builds fuzzylite in debug and release mode (default)\n"
+ printf "\tdebug\t\t builds fuzzylite in debug mode\n"
+ printf "\trelease\t\t builds fuzzylite in release mode\n"
+ printf "\tclean\t\t erases previous builds\n"
+ printf "\thelp\t\t shows this information\n"
+ printf "\n"
+}
+
+#############################
+echo "Parameters: $@"
+
+OPTIONS=( "all" "release" "debug" "clean" "documentation" "help")
+BUILD=( )
+
+for arg in "$@"
+do
+ if [[ "$arg" == "help" ]]; then usage && exit 0; fi
+
+ if [[ "$arg" == "all" || "$arg" == "debug" || "$arg" == "release" || "$arg" == "clean" || "$arg" == "documentation" ]];
+ then BUILD+=( $arg ); else echo "Invalid option: $arg" && usage && exit 2;
+ fi
+done
+
+if [ ${#BUILD[@]} -eq 0 ]; then BUILD+=( "release" "debug" ); fi
+
+echo "Building schedule: ${BUILD[@]}"
+echo "Starting in 3 seconds..."
+sleep 3
+
+for option in "${BUILD[@]}"
+do
+ printf "\n\n"
+ printf "******************************\n"
+ printf "STARTING: $option\n"
+ eval ${option}
+ printf "\nFINISHED: $option\n"
+ printf "******************************\n\n"
+done
+
+
+
diff --git a/fuzzylite/fl/Benchmark.h b/fuzzylite/fl/Benchmark.h
new file mode 100644
index 0000000..9a212db
--- /dev/null
+++ b/fuzzylite/fl/Benchmark.h
@@ -0,0 +1,400 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_BENCHMARK_H
+#define FL_BENCHMARK_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+#include "fl/imex/FldExporter.h"
+
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ class Engine;
+
+ /**
+ The Benchmark class is designed to evaluate the performance of an Engine.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Engine
+ @since 6.0
+ */
+ class FL_API Benchmark {
+ private:
+ std::string _name;
+ Engine* _engine;
+ std::vector<std::vector<scalar> > _expected;
+ std::vector<std::vector<scalar> > _obtained;
+ std::vector<scalar> _times;
+ scalar _tolerance;
+
+ public:
+
+ /**
+ Unit of time to utilize in the results
+ */
+ enum TimeUnit {
+ NanoSeconds, MicroSeconds, MilliSeconds, Seconds, Minutes, Hours
+ };
+
+ /**
+ Shape of the table of results
+ */
+ enum TableShape {
+ Horizontal, Vertical
+ };
+
+ /**
+ Contents of the table of results
+ */
+ enum TableContents {
+ Header = 1, Body = 2, HeaderAndBody = (Header | Body)
+ };
+
+ /**
+ Type of error between expected and obtained values
+ */
+ enum ErrorType {
+ NonFinite, Accuracy, All
+ };
+
+ explicit Benchmark(const std::string& name = "", Engine* engine = fl::null,
+ scalar tolerance = fuzzylite::macheps());
+ virtual ~Benchmark();
+ FL_DEFAULT_COPY_AND_MOVE(Benchmark)
+
+ /**
+ Sets the name of the benchmark
+ @param name is the name of the benchmark
+ */
+ void setName(const std::string& name);
+ /**
+ Gets the name of the benchmark
+ @return name is the name of the benchmark
+ */
+ std::string getName() const;
+
+ /**
+ Sets the engine to benchmark
+ @param engine is the engine to benchmark
+ */
+ void setEngine(Engine* engine);
+ /**
+ Gets the engine to benchmark
+ @return the engine to benchmark
+ */
+ Engine* getEngine() const;
+
+ /**
+ Sets the set of expected values from the engine, where the inner vector
+ contains the input values and output values
+ @param expected is the set of expected values from the engine
+ */
+ void setExpected(const std::vector<std::vector<scalar> >& expected);
+ /**
+ Gets the set of expected values from the engine, where the inner vector
+ contains the input values and output values
+ @return the set of expected values from the engine
+ */
+ const std::vector<std::vector<scalar> >& getExpected() const;
+
+ /**
+ Sets the set of obtained values from the engine, where the inner vector
+ contains the input values and output values
+ @param obtained is the set of obtained values from the engine
+ */
+ void setObtained(const std::vector<std::vector<scalar> >& obtained);
+ /**
+ Gets the set of obtained values from the engine, where the inner vector
+ contains the input values and output values
+ @return the set of obtained values from the engine
+ */
+ const std::vector<std::vector<scalar> >& getObtained() const;
+
+ /**
+ Sets the vector of nanoseconds taken to produce the set of obtained values
+ from the set of expected input values
+ @param times is the vector of nanoseconds taken to produce the set of obtained values
+ from the set of expected input values
+ */
+ void setTimes(const std::vector<scalar> times);
+ /**
+ Gets the vector of nanoseconds taken to produce the set of obtained values
+ from the set of expected input values
+ @return the vector of nanoseconds taken to produce the set of obtained values
+ from the set of expected input values
+ */
+ const std::vector<scalar>& getTimes() const;
+
+ /**
+ Sets the tolerance above which the difference between an expected and
+ obtained value from the engine is considered an error
+ @param tolerance is the tolerance above which the difference between
+ an expected and obtained value from the engine is considered an error
+ */
+ void setTolerance(scalar tolerance);
+ /**
+ Gets the tolerance above which the difference between an expected and
+ obtained value from the engine is considered an error
+ @return the tolerance above which the difference between an expected
+ and obtained value from the engine is considered an error
+ */
+ scalar getTolerance() const;
+
+ /**
+ Produces and loads into memory the set of expected values from the
+ engine
+ @param values is the number of values to evaluate the engine upon
+ @param scope is the scope of the values to generate
+ @throws Exception if the engine is not set
+ */
+ virtual void prepare(int values, FldExporter::ScopeOfValues scope);
+ /**
+ Reads and loads into memory the set of expected values from the
+ engine
+ @param reader is the reader of a set of lines containing
+ space-separated values
+ @param numberOfLines is the maximum number of lines to read from the
+ reader, and a value $f@n=(\infty, -1]$f@ reads the entire file.
+ */
+ virtual void prepare(std::istream& reader, long numberOfLines = -1);
+
+ /**
+ Runs the benchmark on the engine only once
+ @return the time in nanoseconds required by the run, which is
+ also appended to the times stored in Benchmark::getTimes()
+ */
+ virtual scalar runOnce();
+ /**
+ Runs the benchmark on the engine multiple times
+ @param times is the number of times to run the benchmark on the engine
+ @return vector of the time in nanoseconds required by each run, which is
+ also appended to the times stored in Benchmark::getTimes()
+ */
+ virtual std::vector<scalar> run(int times);
+
+ /**
+ Resets the benchmark to be ready to run again
+ */
+ virtual void reset();
+
+ /**
+ Indicates whether errors can be computed based on the expected and
+ obtained values from the benchmark. If the benchmark was prepared from
+ a file reader and the file included columns of expected output values
+ and the benchmark has been run at least once, then the benchmark can
+ automatically compute the errors and will automatically include them in
+ the results.
+ @return whether errors can be computed based on the expected and
+ obtained values from the benchmark
+ */
+ virtual bool canComputeErrors() const;
+
+ /**
+ Computes the mean squared error over all output variables considering
+ only those cases where there is an accuracy error as defined in
+ Benchmark::accuracyErrors().
+ @return the mean squared error over all the output variables.
+ */
+ virtual scalar meanSquaredError() const;
+
+ /**
+ Computes the mean squared error of the given output variable
+ considering only those cases where there is an accuracy error
+ as defined in Benchmark::accuracyErrors().
+ @param outputVariable is the output variable to compute the errors for
+ @return the mean squared error over the given output variable.
+ */
+ virtual scalar meanSquaredError(const OutputVariable* outputVariable) const;
+
+ /**
+ Computes the number of errors over all the output variables caused by
+ non-finite differences or accuracy differences. An error is counted when
+ the difference between the expected and obtained values is not finite,
+ or the absolute difference between the expected and obtained values
+ is not smaller than the tolerance.
+ @return the number of errors over all the output variables caused by
+ non-finite differences or accuracy differences
+ */
+ virtual int allErrors() const;
+
+ /**
+ Computes the number of errors of the given output variable caused by
+ non-finite differences or accuracy differences. An error is counted when
+ the difference between the expected and obtained values is not finite,
+ or the absolute difference between the expected and obtained values
+ is not smaller than the tolerance.
+ @param outputVariable is the output variable to account the errors for
+ @return the number of errors of the given output variable caused by
+ non-finite differences or accuracy differences
+ */
+ virtual int allErrors(const OutputVariable* outputVariable) const;
+
+ /**
+ Computes the number of errors over all the output variables caused by
+ non-finite differences (ie, infinity and NaN). An error is counted when
+ the difference between the expected and obtained values is not finite.
+ @return the number of errors over all the output variables caused by
+ non-finite differences
+ */
+ virtual int nonFiniteErrors() const;
+
+ /**
+ Computes the number of errors of the given output variable caused by
+ non-finite differences (ie, infinity and NaN). An error is counted when
+ the difference between the expected and obtained values is not finite.
+ @param outputVariable is the output variable to account the errors for
+ @return the number of errors of the given output variable caused by
+ non-finite differences
+ */
+ virtual int nonFiniteErrors(const OutputVariable* outputVariable) const;
+
+ /**
+ Computes the number of errors over all the output variables caused by
+ a significant difference in accuracy. An error is counted when the
+ absolute difference between the expected and obtained values
+ is not smaller than the tolerance.
+
+ @f$\text{E} = \sum_y \sum_i \epsilon_i^y, \text{where } \epsilon_i^y =
+ \begin{cases}
+ 0 & \text{if} |e_i^y - o^y_i| < \theta\\
+ 1 & \text{otherwise}
+ \end{cases}
+ @f$,
+ @f$y@f$ is the set of output variables, @f$e@f$ is the set of
+ expected output values, @f$o@f$ is the set of obtained output values,
+ and @f$\theta@f$ is the tolerance
+
+ @return the number of errors over all the output variables caused by
+ a significant difference in accuracy
+ */
+ virtual int accuracyErrors() const;
+
+
+ /**
+ Computes the number of errors over the given output variable caused by
+ a significant difference in accuracy. An error is counted when the
+ absolute difference between the expected and obtained values
+ is not smaller than the tolerance.
+
+ @f$\text{E} = \sum_i \epsilon_i, \text{where } \epsilon_i =
+ \begin{cases}
+ 0 & \text{if} |e_i - o_i| < \theta\\
+ 1 & \text{otherwise}
+ \end{cases}
+ @f$,
+ @f$e@f$ is the set of expected output values,
+ @f$o@f$ is the set of obtained output values,
+ and @f$\theta@f$ is the tolerance
+
+ @param outputVariable is the output variable to account the errors for
+ @return the number of errors of the given output variable caused by
+ a significant difference in accuracy
+ */
+ virtual int accuracyErrors(const OutputVariable* outputVariable) const;
+
+ /**
+ Computes the number of errors of the given type over all the output
+ variables.
+ @param errorType is the type of error to account for
+ @return the number of errors over all the output variables
+ */
+ virtual int numberOfErrors(ErrorType errorType) const;
+
+ /**
+ Computes the number of errors of the given type over the given output
+ variable.
+ @param errorType is the type of error to account for
+ @param outputVariable is the output variable to account the errors for
+ @return the number of errors over the given output variable
+ */
+ virtual int numberOfErrors(ErrorType errorType,
+ const OutputVariable* outputVariable) const;
+
+ /**
+ Returns the name of the time unit
+ @param unit is the time unit
+ @return the name of the time unit
+ */
+ static std::string stringOf(TimeUnit unit);
+
+ /**
+ Returns the factor of the given unit from NanoSeconds
+ @param unit is the time unit
+ @return the factor of the given unit from NanoSeconds
+ */
+ static scalar factorOf(TimeUnit unit);
+ /**
+ Converts the time to different scales
+ @param time is the time to convert
+ @param from is the units of the time to convert from
+ @param to is the units of the time to convert to
+ @return the time in the units specified
+ */
+ static scalar convert(scalar time, TimeUnit from, TimeUnit to);
+
+ /**
+ Returns the header of a horizontal table of results
+ @param runs is the number of times the benchmark will be run, hence
+ producing the relevant number of columns for each run
+ @param includeErrors indicates whether to include columns for computing
+ the errors
+ @return the header of a horizontal table of results
+ */
+ virtual std::vector<std::string> header(int runs, bool includeErrors = true);
+
+ /**Result is a type definition for a pair of strings*/
+ typedef std::pair<std::string, std::string> Result;
+ /**
+ Computes and returns the results from the benchmark aggregating the
+ statistics of all the output variables
+ @param timeUnit is the unit of time of the results
+ @param includeTimes indicates whether to include the times of each run
+ @return the results from the benchmark
+ */
+ virtual std::vector<Result> results(TimeUnit timeUnit = NanoSeconds, bool includeTimes = true) const;
+
+ /**
+ Computes and returns the results from the benchmark for the given output
+ variable
+ @param outputVariable is the output variable to compute the statistics for
+ @param timeUnit is the unit of time of the results
+ @param includeTimes indicates whether to include the times of each run
+ @return the results from the benchmark
+ */
+ virtual std::vector<Result> results(const OutputVariable* outputVariable,
+ TimeUnit timeUnit = NanoSeconds, bool includeTimes = true) const;
+
+ /**
+ Formats the results
+ @param results is the vector of results
+ @param shape is the shape to present the table of results
+ @param contents indicates the information to include in the table of results
+ @param delimiter is the delimiter of the table of results
+ @return the formatted results from the benchmark
+ */
+ virtual std::string format(std::vector<Result> results, TableShape shape,
+ TableContents contents, const std::string& delimiter = "\t") const;
+ };
+
+}
+
+#endif /* FL_BENCHMARK_H */
+
diff --git a/fuzzylite/fl/Complexity.h b/fuzzylite/fl/Complexity.h
new file mode 100644
index 0000000..a63138f
--- /dev/null
+++ b/fuzzylite/fl/Complexity.h
@@ -0,0 +1,297 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_COMPLEXITY_H
+#define FL_COMPLEXITY_H
+
+#include "fl/fuzzylite.h"
+
+#include <vector>
+
+namespace fl {
+ class Engine;
+ class InputVariable;
+ class OutputVariable;
+ class Variable;
+ class RuleBlock;
+ class Rule;
+
+ /**
+ The Complexity class is used throughout the library to estimate the
+ computational cost of the different components of the library
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Engine
+ @see Variable
+ @see OutputVariable
+ @see RuleBlock
+ @see Activation
+ @see Rule
+ @see Antecedent
+ @see Consequent
+ @see Hedge
+ @see Norm
+ @since 6.0
+ */
+
+ class FL_API Complexity {
+ private:
+ scalar _comparison;
+ scalar _arithmetic;
+ scalar _function;
+
+ public:
+ explicit Complexity(scalar all = 0.0);
+ explicit Complexity(scalar comparison, scalar arithmetic, scalar function);
+ virtual ~Complexity();
+ FL_DEFAULT_COPY_AND_MOVE(Complexity)
+
+ Complexity& operator+=(const Complexity& other);
+ Complexity& operator-=(const Complexity& other);
+ Complexity& operator*=(const Complexity& other);
+ Complexity& operator/=(const Complexity& other);
+
+ Complexity operator+(const Complexity& rhs) const;
+ Complexity operator-(const Complexity& rhs) const;
+ Complexity operator*(const Complexity& rhs) const;
+ Complexity operator/(const Complexity& rhs) const;
+
+ bool operator==(const Complexity& rhs) const;
+ bool operator!=(const Complexity& rhs) const;
+ bool operator<(const Complexity& rhs) const;
+ bool operator<=(const Complexity& rhs) const;
+ bool operator>(const Complexity& rhs) const;
+ bool operator>=(const Complexity& rhs) const;
+
+ /**
+ Increases the comparison measure by the given amount
+ @param comparison is the amount to increase the comparison measure by
+ @return the reference to the Complexity object with the updated comparison
+ measure
+ */
+ virtual Complexity& comparison(scalar comparison);
+ virtual void setComparison(scalar comparison);
+ virtual scalar getComparison() const;
+
+ /**
+ Increases the arithmetic measure by the given amount
+ @param arithmetic is the amount to increase the comparison measure by
+ @return the reference to the Complexity object with the updated arithmetic
+ measure
+ */
+ virtual Complexity& arithmetic(scalar arithmetic);
+ virtual void setArithmetic(scalar arithmetic);
+ virtual scalar getArithmetic() const;
+
+ /**
+ Increases the function measure by the given amount
+ @param function is the amount to increase the function measure by
+ @return the reference to the Complexity object with the updated function
+ measure
+ */
+ virtual Complexity& function(scalar function);
+ virtual void setFunction(scalar function);
+ virtual scalar getFunction() const;
+
+ /**
+ Returns a vector containing the measures of complexity
+ @return a vector containing the measures of complexity
+ */
+ typedef std::pair<std::string, scalar> Measure;
+ virtual std::vector<Measure> measures() const;
+
+ /**
+ Increases the complexity by the given parameter
+ @param x is the addend
+ @return the reference to the updated complexity
+ */
+ virtual Complexity& plus(const Complexity& x);
+ /**
+ Reduces the complexity by the given parameter
+ @param x is the subtrahend
+ @return the reference to the updated complexity object
+ */
+ virtual Complexity& minus(const Complexity& x);
+ /**
+ Multiplies the complexity by the given parameter
+ @param x is the multiplicand
+ @return the reference to the updated complexity object
+ */
+ virtual Complexity& multiply(const Complexity& x);
+ /**
+ Divides the complexity by the given parameter
+ @param x is the divisor
+ @return the reference to the updated complexity object
+ */
+ virtual Complexity& divide(const Complexity& x);
+
+ /**
+ Increases each measure by the given parameter
+ @param x is the addend
+ @return the reference to the updated complexity
+ */
+ virtual Complexity& plus(scalar x);
+ /**
+ Reduces each measure by the given parameter
+ @param x is the subtrahend
+ @return the reference to the updated complexity
+ */
+ virtual Complexity& minus(scalar x);
+ /**
+ Multiplies each measure by the given parameter
+ @param x is the multiplicand
+ @return the reference to the updated complexity
+ */
+ virtual Complexity& multiply(scalar x);
+ /**
+ Divides each measure by the given parameter
+ @param x is the divisor
+ @return the reference to the updated complexity
+ */
+ virtual Complexity& divide(scalar x);
+
+ /**
+ Compares the complexity for equality to another with the given tolerance
+ @param x is the complexity to compare against
+ @param macheps is the tolerance to compare floating-point values
+ @return `true` if every measure in this satisfies Op::isEq(this, x, macheps),
+ and `false` otherwise
+ */
+ virtual bool equals(const Complexity& x, scalar macheps = fuzzylite::macheps()) const;
+ /**
+ Compares the complexity for strict inequality (less than) to another
+ with the given tolerance
+ @param x is the complexity to compare against
+ @param macheps is the tolerance to compare floating-point values
+ @return `true` if every measure in this satisfies Op::isLt(this, x, macheps),
+ and `false` otherwise
+ */
+ virtual bool lessThan(const Complexity& x, scalar macheps = fuzzylite::macheps()) const;
+ /**
+ Compares the complexity for inequality (less than or equal to) to another
+ with the given tolerance
+ @param x is the complexity to compare against
+ @param macheps is the tolerance to compare floating-point values
+ @return `true` if every measure in this satisfies Op::isLE(this, x, macheps),
+ and `false` otherwise
+ */
+ virtual bool lessThanOrEqualsTo(const Complexity& x, scalar macheps = fuzzylite::macheps()) const;
+ /**
+ Compares the complexity for strict inequality (greater than) to another
+ with the given tolerance
+ @param x is the complexity to compare against
+ @param macheps is the tolerance to compare floating-point values
+ @return `true` if every measure in this satisfies Op::isGt(this, x, macheps),
+ and `false` otherwise
+ */
+ virtual bool greaterThan(const Complexity& x, scalar macheps = fuzzylite::macheps()) const;
+ /**
+ Compares the complexity for inequality (greater than or equal to) to
+ another with the given tolerance
+ @param x is the complexity to compare against
+ @param macheps is the tolerance to compare floating-point values
+ @return `true` if every measure in this satisfies Op::isGE(this, x, macheps),
+ and `false` otherwise
+ */
+ virtual bool greaterThanOrEqualsTo(const Complexity& x, scalar macheps = fuzzylite::macheps()) const;
+
+ /**
+ Computes the sum of the measures
+ @return the sum of the measures
+ */
+ virtual scalar sum() const;
+
+ /**
+ Computes the norm of the complexity
+ @return the norm of the complexity
+ */
+ virtual scalar norm() const;
+
+ /**
+ Returns the measures of the complexity
+ @return the measures of the complexity
+ */
+ virtual std::string toString() const;
+
+ /**
+ Computes the complexity of the given engine as the sum of complexities
+ of the rule blocks
+ @param engine is the engine for which to compute the complexity
+ @return the complexity of the given engine as the sum of complexities
+ of the rule blocks
+ */
+ virtual Complexity compute(const Engine* engine) const;
+
+ /**
+ Computes the complexity of the given input variable
+ @param inputVariable is the input variable for which to compute the complexity
+ @return the complexity of the given input variable
+ */
+ virtual Complexity compute(const InputVariable* inputVariable) const;
+ /**
+ Computes the complexity of the given output variable
+ @param outputVariable is the output variable for which to compute the complexity
+ @return the complexity of the given output variable
+ */
+ virtual Complexity compute(const OutputVariable* outputVariable) const;
+
+ /**
+ Computes the complexity of the given input variables
+ @param inputVariables is the vector of input variables for which to
+ compute the complexity
+ @return the complexity of the given input variables
+ */
+ virtual Complexity compute(const std::vector<InputVariable*>& inputVariables) const;
+ /**
+ Computes the complexity of the given output variables
+ @param outputVariables is the vector of output variables for which to
+ compute the complexity
+ @param complexityOfDefuzzification indicates whether to compute the
+ complexity of the variable including the defuzzification process
+ @return the complexity of the given output variables
+ */
+ virtual Complexity compute(const std::vector<OutputVariable*>& outputVariables,
+ bool complexityOfDefuzzification = false) const;
+ /**
+ Computes the complexity of the given variables
+ @param variables is the vector of variables for which to compute the
+ complexity
+ @return the complexity of the given variables
+ */
+ virtual Complexity compute(const std::vector<Variable*>& variables) const;
+
+ /**
+ Computes the complexity of the given rule block
+ @param ruleBlock is the rule block for which to compute the complexity
+ @return the complexity of the given rule block
+ */
+ virtual Complexity compute(const RuleBlock* ruleBlock) const;
+
+ /**
+ Computes the complexity of the given rule blocks
+ @param ruleBlocks is the vector of rule blocks for which to compute the
+ complexity
+ @return Computes the complexity of the given rule blocks
+ */
+ virtual Complexity compute(const std::vector<RuleBlock*>& ruleBlocks) const;
+
+ };
+
+
+}
+
+#endif /* COMPLEXITY_H */
+
diff --git a/fuzzylite/fl/Console.h b/fuzzylite/fl/Console.h
new file mode 100644
index 0000000..b96d677
--- /dev/null
+++ b/fuzzylite/fl/Console.h
@@ -0,0 +1,155 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CONSOLE_H
+#define FL_CONSOLE_H
+
+#include "fl/fuzzylite.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace fl {
+ class Engine;
+
+ /**
+ The Console class is a command-line tool that helps to utilize the
+ `fuzzylite` library.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 4.0
+ */
+ class FL_API Console {
+ public:
+
+ /**
+ A command-line option given by key, value and description
+ */
+ struct Option {
+ std::string key, value, description;
+
+ explicit Option(const std::string& key = "",
+ const std::string& value = "",
+ const std::string& description = "");
+ };
+
+ /**Keyword for input file*/
+ static const std::string KW_INPUT_FILE;
+ /**Keyword for input file format*/
+ static const std::string KW_INPUT_FORMAT;
+ /**Keyword for output file*/
+ static const std::string KW_OUTPUT_FILE;
+ /**Keyword for output file format*/
+ static const std::string KW_OUTPUT_FORMAT;
+ /**Keyword for built-in example*/
+ static const std::string KW_EXAMPLE;
+ /**Keyword for number of decimals*/
+ static const std::string KW_DECIMALS;
+ /**Keyword for file containing input data*/
+ static const std::string KW_DATA_INPUT_FILE;
+ /**Keyword for number of values to generate*/
+ static const std::string KW_DATA_VALUES;
+ /**Keyword for the scope of the number of values to generate*/
+ static const std::string KW_DATA_VALUES_SCOPE;
+ /**Keyword for exporting headers in FLD*/
+ static const std::string KW_DATA_EXPORT_HEADER;
+ /**Keyword for exporting input values in FLD*/
+ static const std::string KW_DATA_EXPORT_INPUTS;
+
+ /**
+ Creates a new Mamdani Engine based on the SimpleDimmer example
+ @return a new Mamdani Engine based on the SimpleDimmer example
+ */
+ static Engine* mamdani();
+ /**
+ Creates a new TakagiSugeno Engine based on the Approximation example of @f$sin(x)/x@f$
+ @return a new TakagiSugeno Engine based on the Approximation example of @f$sin(x)/x@f$
+ */
+ static Engine* takagiSugeno();
+
+ /**
+ Creates a new Hybrid Engine based on the Tipper example using Mamdani
+ and TakagiSugeno outputs.
+ @return a new Hybrid Engine based on the Tipper example using Mamdani
+ and TakagiSugeno outputs.
+ */
+ static Engine* hybrid();
+
+
+ protected:
+ virtual std::map<std::string, std::string> parse(int argc, const char* argv[]);
+ virtual void process(const std::map<std::string, std::string>& options);
+
+ virtual void process(const std::string& input, std::ostream& writer,
+ const std::string& inputFormat, const std::string& outputFormat,
+ const std::map<std::string, std::string>& options);
+
+ virtual int readCharacter();
+ virtual void interactive(std::ostream& writer, Engine* engine);
+ virtual std::string interactiveHelp();
+
+ virtual void exportAllExamples(const std::string& from, const std::string& to);
+ virtual void exportAllExamples(const std::string& from, const std::string& to,
+ const std::string& examplesPath, const std::string& outputPath);
+
+ /**
+ Benchmarks the engine described in the FLL file against the dataset
+ contained in the FLD file.
+
+ @param fllFile is the file describing the engine in FLL format
+ @param fldFile is the file containing the dataset in FLD format
+ @param runs is the number of runs to evaluate the benchmarks
+ @param writer is the output where the results will be written to
+ @throws Exception if something goes wrong reading the files, importing the
+ engines or evaluating the benchmark
+ */
+
+ virtual void benchmark(const std::string& fllFile, const std::string& fldFile,
+ int runs, std::ofstream* writer = fl::null) const;
+ /**
+ Benchmarks the list of engines against the list of datasets, both described
+ as absolute or relative paths
+
+ @param fllFileList is the file containing the list of paths of engines in
+ FLL format
+ @param fldFileList is the file containing the list of paths of datasets in
+ FLD format
+ @param runs is the number of runs to evaluate the benchmarks
+ @param writer is the output where the results will be written to
+ @throws Exception if something goes wrong reading the files, importing the
+ engines or evaluating the benchmark
+ */
+ virtual void benchmarks(const std::string& fllFileList, const std::string& fldFileList,
+ int runs, std::ofstream* writer = fl::null) const;
+
+ public:
+ /**
+ Returns a string representation of the usage of the command-line tool
+ @return a string representation of the usage of the command-line tool
+ */
+ virtual std::string usage();
+
+ /**
+ Returns a vector of the options available from the command line
+ @return a vector of the options available from the command line
+ */
+ virtual std::vector<Option> availableOptions();
+
+ static int main(int argc, const char* argv[]);
+ };
+}
+#endif /* FL_CONSOLE_H */
+
diff --git a/fuzzylite/fl/Engine.h b/fuzzylite/fl/Engine.h
new file mode 100644
index 0000000..3a88478
--- /dev/null
+++ b/fuzzylite/fl/Engine.h
@@ -0,0 +1,478 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ENGINE_H
+#define FL_ENGINE_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ class InputVariable;
+ class OutputVariable;
+ class Variable;
+ class RuleBlock;
+ class Hedge;
+ class TNorm;
+ class SNorm;
+ class Defuzzifier;
+ class Activation;
+
+ /**
+ The Engine class is the core class of the library as it groups the
+ necessary components of a fuzzy logic controller.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see InputVariable
+ @see OutputVariable
+ @see RuleBlock
+ @since 4.0
+ */
+ class FL_API Engine {
+ private:
+ std::string _name;
+ std::string _description;
+ std::vector<InputVariable*> _inputVariables;
+ std::vector<OutputVariable*> _outputVariables;
+ std::vector<RuleBlock*> _ruleBlocks;
+
+ void copyFrom(const Engine& source);
+
+ protected:
+ void updateReferences() const;
+
+ public:
+ explicit Engine(const std::string& name = "");
+ Engine(const Engine& other);
+ Engine& operator=(const Engine& other);
+ virtual ~Engine();
+ FL_DEFAULT_MOVE(Engine)
+
+ /**
+ Configures the engine with the given operators
+ @param conjunction is a TNorm registered in the TNormFactory
+ @param disjunction is an SNorm registered in the SNormFactory
+ @param implication is an TNorm registered in the TNormFactory
+ @param aggregation is an SNorm registered in the SNormFactory
+ @param defuzzifier is a defuzzifier registered in the DefuzzifierFactory
+ @param activation is an activation method registered in the ActivationFactory
+ */
+ virtual void configure(const std::string& conjunction,
+ const std::string& disjunction,
+ const std::string& implication,
+ const std::string& aggregation,
+ const std::string& defuzzifier,
+ const std::string& activation);
+
+ /**
+ Configures the engine with clones of the given object operators, taking
+ ownership of the objects.
+
+ @param conjunction is the operator to process the propositions joined
+ by `and` in the antecedent of the rules
+ @param disjunction is the operator to process the propositions
+ joined by `or` in the antecedent of the rules
+ @param implication is the operator to modify the consequents of the
+ rules based on the activation degree of the antecedents of the rules
+ @param aggregation is the operator to aggregate the resulting
+ implications of the rules
+ @param defuzzifier is the operator to transform the aggregated
+ implications into a single scalar value
+ @param activation is the activation method to activate and fire the
+ rule blocks
+ */
+ virtual void configure(TNorm* conjunction, SNorm* disjunction,
+ TNorm* implication, SNorm* aggregation,
+ Defuzzifier* defuzzifier, Activation* activation);
+
+ /**
+ Indicates whether the engine has been configured correctly and is
+ ready for operation. In more advanced engines, the result of this
+ method should be taken as a suggestion and not as a prerequisite to
+ operate the engine.
+
+ @param status (if not null) contains the configuration errors of the engine
+ @return whether the engine is ready to operate
+ */
+ virtual bool isReady(std::string* status = fl::null) const;
+
+ /**
+ Computes the estimated complexity of operation of the engine
+ @return the estimated complexity of operation of the engine
+ */
+ virtual Complexity complexity() const;
+ /**
+ Processes the engine in its current state as follows: (a) Clears the
+ aggregated fuzzy output variables, (b) Activates the rule blocks, and
+ (c) Defuzzifies the output variables
+ @see Aggregated::clear()
+ @see RuleBlock::activate()
+ @see OutputVariable::defuzzify()
+ */
+ virtual void process();
+
+ /**
+ Restarts the engine by setting the values of the input variables to
+ fl::nan and clearing the output variables
+ @see Variable::setValue()
+ @see OutputVariable::clear()
+ */
+ virtual void restart();
+
+ /**
+ Sets the name of the engine
+ @param name is the name of the engine
+ */
+ virtual void setName(const std::string& name);
+ /**
+ Gets the name of the engine
+ @return the name of the engine
+ */
+ virtual std::string getName() const;
+
+ /**
+ Sets the description of the engine
+ @param description is the description of the engine
+ */
+ virtual void setDescription(const std::string& description);
+ /**
+ Gets the description of the engine
+ @return the description of the engine
+ */
+ virtual std::string getDescription() const;
+
+ /**
+ Sets the value of the given input variable.
+ The cost of this method is O(n), where n is the number of
+ input variables in the engine. For performance, please get the
+ variables by index.
+ @param name is the name of the input variable
+ @param value is the value for the input variable
+ */
+ virtual void setInputValue(const std::string& name, scalar value);
+ /**
+ Gets the value of the given output variable.
+ The cost of this method is O(n), where n is the number of
+ output variables in the engine. For performance, please get the
+ variables by index.
+ @param name is the name of the output variable
+ @return the value of the given output variable
+ */
+ virtual scalar getOutputValue(const std::string& name);
+
+ /**
+ Returns a string representation of the engine in the FuzzyLite
+ Language
+ @return a string representation of the engine in the FuzzyLite
+ Language
+ */
+ virtual std::string toString() const;
+
+ enum Type {
+ /**Mamdani: When the output variables have IntegralDefuzzifier%s*/
+ Mamdani,
+ /**Larsen: When Mamdani and AlgebraicProduct is the implication operator of
+ the rule blocks */
+ Larsen,
+ /**TakagiSugeno: When output variables have WeightedDefuzzifier%s of type
+ TakagiSugeno and the output variables have Constant, Linear, or
+ Function terms*/
+ TakagiSugeno,
+ /**Tsukamoto: When output variables have WeightedDefuzzifier%s of type
+ Tsukamoto and the output variables only have monotonic terms
+ (Concave, Ramp, Sigmoid, SShape, and ZShape)*/
+ Tsukamoto,
+ /**InverseTsukamoto: When output variables have WeightedDefuzzifier%s of type
+ TakagiSugeno and the output variables do not only have Constant,
+ Linear or Function terms*/
+ InverseTsukamoto,
+ /**Hybrid: When output variables have different defuzzifiers*/
+ Hybrid,
+ /**Unknown: When output variables have no defuzzifiers*/
+ Unknown
+ };
+ /**
+ Infers the type of the engine based on its current configuration
+
+ @param name stores a string representation of the engine type (if the
+ pointer passed is not `fl::null`)
+ @param reason stores a string representation explaining the reasons
+ for the inferred type (if the pointer passed is not `fl::null`)
+ @return the inferred type of the engine based on its current
+ configuration
+ */
+ virtual Type type(std::string* name = fl::null, std::string* reason = fl::null) const;
+
+ /**
+ Creates a clone of the engine
+ @return a clone of the engine
+ */
+ virtual Engine* clone() const;
+
+ /**
+ Returns a vector that contains the input variables followed by the
+ output variables in the order of insertion
+
+ @return a vector that contains the input variables followed by the
+ output variables in the order of insertion
+ */
+ virtual std::vector<Variable*> variables() const;
+
+ /**
+ Adds the input variable
+ @param inputVariable is the input variable
+ */
+ virtual void addInputVariable(InputVariable* inputVariable);
+ /**
+ Sets the input variable at the given index
+ @param inputVariable is the input variable to set
+ @param index is the index at which the input variable is to be stored
+ @return the input variable previously stored at the given index
+ */
+ virtual InputVariable* setInputVariable(InputVariable* inputVariable, std::size_t index);
+ /**
+ Inserts the input variable at the given index, shifting other
+ variables one position to the right
+ @param inputVariable is the input variable to insert
+ @param index is the index at which the input variable is to be
+ inserted
+ */
+ virtual void insertInputVariable(InputVariable* inputVariable, std::size_t index);
+ /**
+ Gets the input variable at the given index
+ @param index is the given index
+ @return the input variable at the given index
+ */
+ virtual InputVariable* getInputVariable(std::size_t index) const;
+ /**
+ Gets the input variable of the given name after iterating the input
+ variables. The cost of this method is O(n), where n is the number of
+ input variables in the engine. For performance, please get the
+ variables by index.
+ @param name is the name of the input variable
+ @return input variable of the given name
+ @throws fl::Exception if there is no variable with the given name
+ */
+ virtual InputVariable* getInputVariable(const std::string& name) const;
+ /**
+ Removes the input variable at the given index (without deleting it)
+ and shifts the remaining input variables one position to the left
+ @param index is the given index
+ @return the input variable at the given index
+ */
+ virtual InputVariable* removeInputVariable(std::size_t index);
+ /**
+ Removes the input variable of the given name (without deleting it) and
+ shifts the remaining input variables one position to the left
+ @param name is the name of the input variable
+ @return the input variable of the given name
+ @throws fl::Exception if there is no variable with the given name
+ */
+ virtual InputVariable* removeInputVariable(const std::string& name);
+ /**
+ Indicates whether an input variable of the given name is in the input
+ variables
+ @param name is the name of the input variable
+ @return whether an input variable is registered with the given name
+ */
+ virtual bool hasInputVariable(const std::string& name) const;
+ /**
+ Returns the number of input variables added to the engine
+ @return the number of input variables added to the engine
+ */
+ virtual std::size_t numberOfInputVariables() const;
+ /**
+ Returns an immutable vector of input variables
+ @return an immutable vector of input variables
+ */
+ virtual const std::vector<InputVariable*>& inputVariables() const;
+ /**
+ Sets the vector of input variables
+ @param inputVariables is the vector of input variables
+ */
+ virtual void setInputVariables(const std::vector<InputVariable*>& inputVariables);
+ /**
+ Returns a mutable vector of input variables
+ @return a mutable vector of input variables
+ */
+ virtual std::vector<InputVariable*>& inputVariables();
+
+ /**
+ Adds the output variable
+ @param outputVariable is the output variable
+ */
+ virtual void addOutputVariable(OutputVariable* outputVariable);
+ /**
+ Sets the output variable at the given index
+ @param outputVariable is the output variable to set
+ @param index is the index at which the output variable is to be stored
+ @return the output variable previously stored at the given index
+ */
+ virtual OutputVariable* setOutputVariable(OutputVariable* outputVariable, std::size_t index);
+ /**
+ Inserts the output variable at the given index, shifting other
+ variables one position to the right
+ @param outputVariable is the output variable to insert
+ @param index is the index at which the output variable is to be inserted
+ */
+ virtual void insertOutputVariable(OutputVariable* outputVariable, std::size_t index);
+ /**
+ Gets the output variable at the given index
+ @param index is the given index
+ @return the output variable at the given index
+ */
+ virtual OutputVariable* getOutputVariable(std::size_t index) const;
+ /**
+ Gets the output variable of the given name after iterating the output
+ variables. The cost of this method is O(n), where n is the number of
+ output variables in the engine. For performance, please get the
+ variables by index.
+ @param name is the name of the output variable
+ @return output variable of the given name
+ @throws fl::Exception if there is no variable with the given name
+ */
+ virtual OutputVariable* getOutputVariable(const std::string& name) const;
+
+ /**
+ Indicates whether an output variable of the given name is in the
+ output variables
+ @param name is the name of the output variable
+ @return whether an output variable is registered with the given name
+ */
+ virtual bool hasOutputVariable(const std::string& name) const;
+ /**
+ Removes the output variable at the given index (without deleting it)
+ and shifts the remaining output variables one position to the left
+ @param index is the given index
+ @return the output variable at the given index
+ */
+ virtual OutputVariable* removeOutputVariable(std::size_t index);
+ /**
+ Removes the output variable of the given name (without deleting it)
+ and shifts the remaining output variables one position to the left
+ @param name is the name of the output variable
+ @return the output variable of the given name
+ @throws fl::Exception if there is no variable with the given name
+ */
+ virtual OutputVariable* removeOutputVariable(const std::string& name);
+ /**
+ Returns the number of output variables added to the engine
+ @return the number of output variables added to the engine
+ */
+ virtual std::size_t numberOfOutputVariables() const;
+ /**
+ Returns an immutable vector of output variables
+ @return an immutable vector of output variables
+ */
+ virtual const std::vector<OutputVariable*>& outputVariables() const;
+ /**
+ Sets the vector of output variables
+ @param outputVariables is the vector of output variables
+ */
+ virtual void setOutputVariables(const std::vector<OutputVariable*>& outputVariables);
+ /**
+ Returns a mutable vector of output variables
+ @return a mutable vector of output variables
+ */
+ virtual std::vector<OutputVariable*>& outputVariables();
+
+ /**
+ Adds the rule block
+ @param ruleBlock is the rule block
+ */
+ virtual void addRuleBlock(RuleBlock* ruleBlock);
+ /**
+ Sets the rule block at the given index
+ @param ruleBlock is the rule block to set
+ @param index is the index at which the rule block is to be stored
+ @return the rule block previously stored at the given index
+ */
+ virtual RuleBlock* setRuleBlock(RuleBlock* ruleBlock, std::size_t index);
+ /**
+ Inserts the rule block at the given index, shifting other blocks one
+ position to the right
+ @param ruleBlock is the rule block to insert
+ @param index is the index at which the rule block is to be inserted
+ */
+ virtual void insertRuleBlock(RuleBlock* ruleBlock, std::size_t index);
+ /**
+ Gets the rule block at the given index
+ @param index is the given index
+ @return the rule block at the given index
+ */
+ virtual RuleBlock* getRuleBlock(std::size_t index) const;
+ /**
+ Gets the rule block of the given name after iterating the rule blocks.
+ The cost of this method is O(n), where n is the number of
+ rule blocks in the engine. For performance, please get the rule blocks
+ by index.
+ @param name is the name of the rule block
+ @return rule block of the given name
+ @throws fl::Exception if there is no block with the given name
+ */
+ virtual RuleBlock* getRuleBlock(const std::string& name) const;
+ /**
+ Indicates whether an rule block of the given name is in the rule
+ blocks
+ @param name is the name of the rule block
+ @return whether an rule block of the given name is in the rule blocks
+
+ */
+ virtual bool hasRuleBlock(const std::string& name) const;
+ /**
+ Removes the rule block at the given index (without deleting it) and
+ shifts the remaining rule blocks one position to the left
+ @param index is the given index
+ @return the rule block at the given index
+ */
+ virtual RuleBlock* removeRuleBlock(std::size_t index);
+ /**
+ Removes the rule block of the given name (without deleting it) and
+ shifts the remaining rule blocks one position to the left
+ @param name is the name of the rule block
+ @return the rule block of the given name
+ @throws fl::Exception if there is no rule block with the given name
+ */
+ virtual RuleBlock* removeRuleBlock(const std::string& name);
+ /**
+ Returns the number of rule blocks added to the engine
+ @return the number of rule blocks added to the engine
+ */
+ virtual std::size_t numberOfRuleBlocks() const;
+ /**
+ Returns an immutable vector of rule blocks
+ @return an immutable vector of rule blocks
+ */
+ virtual const std::vector<RuleBlock*>& ruleBlocks() const;
+ /**
+ Sets the vector of rule blocks
+ @param ruleBlocks is the vector of rule blocks
+ */
+ virtual void setRuleBlocks(const std::vector<RuleBlock*>& ruleBlocks);
+ /**
+ Returns a mutable vector of rule blocks
+ @return a mutable vector of rule blocks
+ */
+ virtual std::vector<RuleBlock*>& ruleBlocks();
+
+ };
+}
+#endif /* FL_ENGINE_H */
diff --git a/fuzzylite/fl/Exception.h b/fuzzylite/fl/Exception.h
new file mode 100644
index 0000000..60996f1
--- /dev/null
+++ b/fuzzylite/fl/Exception.h
@@ -0,0 +1,140 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_EXCEPTION_H
+#define FL_EXCEPTION_H
+
+#include "fl/fuzzylite.h"
+
+#include <exception>
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ /**
+
+ The Exception class is the only type of exception that is utilized
+ throughout the library. If the library is built with the compiling flag
+ `-DFL_BACKTRACE=ON`, the method Exception::btCallStack() will provide a
+ stack trace when an exception is thrown. Please, have in mind that
+ enabling the stack trace requires the external library `dbghelp` in
+ the Windows platform, which is generally available in the operating
+ system.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 4.0
+
+ */
+
+#ifdef FL_WINDOWS
+ //Disable warning for dllexport of std::exception in Windows
+#pragma warning (push)
+#pragma warning (disable:4275)
+#endif
+
+ class FL_API Exception : public std::exception {
+#ifdef FL_WINDOWS
+#pragma warning (pop)
+#endif
+ private:
+ std::string _what;
+ public:
+ explicit Exception(const std::string& what);
+ /**
+ Constructor to be used in conjunction with macro `FL_AT`
+ @param what is the message of the exception
+ @param file is the name of the file where the exception occurred
+ @param line is the line number in the file where the exception occurred
+ @param function is the name of the function where the exception occurred
+ */
+ explicit Exception(const std::string& what, const std::string& file, int line,
+ const std::string& function);
+ virtual ~Exception() FL_INOEXCEPT FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Exception)
+
+ /**
+ Sets the message of the `std::exception`
+ @param what is the message of the `std::exception`
+ */
+ virtual void setWhat(const std::string& what);
+ /**
+ Gets the message of the `std::exception`
+ @return the message of the `std::exception`
+ */
+ virtual std::string getWhat() const;
+ /**
+ Gets the message of the `std::exception`
+ @return the message of the `std::exception`
+ */
+ virtual const char* what() const FL_INOEXCEPT FL_IOVERRIDE;
+
+ /**
+ Appends a message to the exception
+ @param whatElse is a message to the exception
+ */
+ virtual void append(const std::string& whatElse);
+ /**
+ Appends an error trace to the exception. The method can be called
+ utilizing the macro `FL_AT`
+ @param file is the name of the file where the exception occurred
+ @param line is the line number in the file where the exception occurred
+ @param function is the name of the function where the exception occurred
+ */
+ virtual void append(const std::string& file, int line, const std::string& function);
+ /**
+ Appends an error trace with a message to the exception. The method can be called
+ utilizing the macro `FL_AT`
+ @param whatElse is further information about the exception
+ @param file is the name of the file where the exception occurred
+ @param line is the line number in the file where the exception occurred
+ @param function is the name of the function where the exception occurred
+ */
+ virtual void append(const std::string& whatElse,
+ const std::string& file, int line, const std::string& function);
+
+ /**
+ Returns the stack trace (if enabled)
+ @return the stack trace (if enabled)
+ */
+ static std::string btCallStack();
+
+ /**
+ Provides a signal handler to catch signals
+ @param signal is the code of the signal
+ */
+ static void signalHandler(int signal);
+
+ /**
+ Converts a given signal into an Exception (does not work very well on Windows)
+ @param signal is the code of the signal
+ */
+ static void convertToException(int signal);
+
+ /**
+ Provides a handler for `terminate` and `unexpected` signals
+ */
+ static void terminate();
+ /**
+ Logs the exception to console and proceeds the regular execution of the library
+ @param exception is the exception thrown
+ */
+ static void catchException(const std::exception& exception);
+
+
+ };
+}
+#endif /* FL_EXCEPTION_H */
diff --git a/fuzzylite/fl/Headers.h b/fuzzylite/fl/Headers.h
new file mode 100644
index 0000000..1c41002
--- /dev/null
+++ b/fuzzylite/fl/Headers.h
@@ -0,0 +1,148 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HEADERS_H
+#define FL_HEADERS_H
+
+/**
+ The Headers.h file contains the headers of all the classes in the
+ `fuzzylite` library, thereby encouraging the use of the directive `#include
+ "fl/Headers.h"` in projects using the library.
+ */
+
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Benchmark.h"
+#include "fl/Complexity.h"
+#include "fl/Console.h"
+#include "fl/Engine.h"
+#include "fl/Exception.h"
+
+#include "fl/activation/Activation.h"
+#include "fl/activation/First.h"
+#include "fl/activation/General.h"
+#include "fl/activation/Highest.h"
+#include "fl/activation/Last.h"
+#include "fl/activation/Lowest.h"
+#include "fl/activation/Proportional.h"
+#include "fl/activation/Threshold.h"
+
+#include "fl/defuzzifier/Bisector.h"
+#include "fl/defuzzifier/Centroid.h"
+#include "fl/defuzzifier/Defuzzifier.h"
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+#include "fl/defuzzifier/SmallestOfMaximum.h"
+#include "fl/defuzzifier/LargestOfMaximum.h"
+#include "fl/defuzzifier/MeanOfMaximum.h"
+#include "fl/defuzzifier/WeightedAverage.h"
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+#include "fl/defuzzifier/WeightedSum.h"
+
+#include "fl/factory/ActivationFactory.h"
+#include "fl/factory/CloningFactory.h"
+#include "fl/factory/ConstructionFactory.h"
+#include "fl/factory/FactoryManager.h"
+#include "fl/factory/FunctionFactory.h"
+#include "fl/factory/DefuzzifierFactory.h"
+#include "fl/factory/HedgeFactory.h"
+#include "fl/factory/SNormFactory.h"
+#include "fl/factory/TNormFactory.h"
+#include "fl/factory/TermFactory.h"
+
+#include "fl/imex/CppExporter.h"
+#include "fl/imex/FclImporter.h"
+#include "fl/imex/FclExporter.h"
+#include "fl/imex/FisImporter.h"
+#include "fl/imex/FisExporter.h"
+#include "fl/imex/FldExporter.h"
+#include "fl/imex/FllImporter.h"
+#include "fl/imex/FllExporter.h"
+#include "fl/imex/JavaExporter.h"
+#include "fl/imex/RScriptExporter.h"
+
+#include "fl/hedge/Any.h"
+#include "fl/hedge/Extremely.h"
+#include "fl/hedge/Hedge.h"
+#include "fl/hedge/HedgeFunction.h"
+#include "fl/hedge/Not.h"
+#include "fl/hedge/Seldom.h"
+#include "fl/hedge/Somewhat.h"
+#include "fl/hedge/Very.h"
+
+#include "fl/Operation.h"
+
+#include "fl/norm/Norm.h"
+#include "fl/norm/SNorm.h"
+#include "fl/norm/TNorm.h"
+
+#include "fl/norm/s/AlgebraicSum.h"
+#include "fl/norm/s/BoundedSum.h"
+#include "fl/norm/s/DrasticSum.h"
+#include "fl/norm/s/EinsteinSum.h"
+#include "fl/norm/s/HamacherSum.h"
+#include "fl/norm/s/Maximum.h"
+#include "fl/norm/s/NilpotentMaximum.h"
+#include "fl/norm/s/NormalizedSum.h"
+#include "fl/norm/s/SNormFunction.h"
+#include "fl/norm/s/UnboundedSum.h"
+
+#include "fl/norm/t/AlgebraicProduct.h"
+#include "fl/norm/t/BoundedDifference.h"
+#include "fl/norm/t/DrasticProduct.h"
+#include "fl/norm/t/EinsteinProduct.h"
+#include "fl/norm/t/HamacherProduct.h"
+#include "fl/norm/t/Minimum.h"
+#include "fl/norm/t/NilpotentMinimum.h"
+#include "fl/norm/t/TNormFunction.h"
+
+#include "fl/rule/Antecedent.h"
+#include "fl/rule/Consequent.h"
+#include "fl/rule/Rule.h"
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Expression.h"
+
+#include "fl/term/Aggregated.h"
+#include "fl/term/Bell.h"
+#include "fl/term/Binary.h"
+#include "fl/term/Concave.h"
+#include "fl/term/Constant.h"
+#include "fl/term/Cosine.h"
+#include "fl/term/Discrete.h"
+#include "fl/term/Function.h"
+#include "fl/term/Gaussian.h"
+#include "fl/term/GaussianProduct.h"
+#include "fl/term/Linear.h"
+#include "fl/term/PiShape.h"
+#include "fl/term/Ramp.h"
+#include "fl/term/Rectangle.h"
+#include "fl/term/SShape.h"
+#include "fl/term/Sigmoid.h"
+#include "fl/term/SigmoidDifference.h"
+#include "fl/term/SigmoidProduct.h"
+#include "fl/term/Spike.h"
+#include "fl/term/Term.h"
+#include "fl/term/Activated.h"
+#include "fl/term/Trapezoid.h"
+#include "fl/term/Triangle.h"
+#include "fl/term/ZShape.h"
+
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+#include "fl/variable/Variable.h"
+
+
+#endif /* FL_HEADERS_H */
diff --git a/fuzzylite/fl/Operation.h b/fuzzylite/fl/Operation.h
new file mode 100644
index 0000000..8070116
--- /dev/null
+++ b/fuzzylite/fl/Operation.h
@@ -0,0 +1,1069 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_OPERATION_H
+#define FL_OPERATION_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Exception.h"
+
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ /**
+ The Operation class contains methods for numeric operations, string
+ manipulation, and other functions, all of which are also accessible via
+ fl::Op.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 4.0
+ */
+ class Operation {
+ public:
+
+ /**
+ Returns the minimum between the two parameters
+ @param a
+ @param b
+ @return @f$\min(a,b)@f$
+ */
+ template <typename T>
+ static T min(T a, T b);
+
+ /**
+ Returns the maximum between the two parameters
+ @param a
+ @param b
+ @return @f$\max(a,b)@f$
+ */
+ template <typename T>
+ static T max(T a, T b);
+
+ /**
+ Returns @f$x@f$ bounded in @f$[\min,\max]@f$
+ @param x is the value to be bounded
+ @param min is the minimum value of the range
+ @param max is the maximum value of the range
+ @return @f$
+ \begin{cases}
+ \min & \mbox{if $x < \min$} \cr
+ \max & \mbox{if $x > \max$} \cr
+ x & \mbox{otherwise}
+ \end{cases}
+ @f$
+ */
+ template <typename T>
+ static T bound(T x, T min, T max);
+
+ /**
+ Indicates whether @f$x@f$ is within the boundaries (open or closed)
+ @param x is the value
+ @param min is the minimum of the range
+ @param max is the maximum of the range
+ @param geq determines whether the maximum is a closed interval
+ @param leq determines whether the minimum is a closed interval
+ @return @f$
+ \begin{cases}
+ x \in [\min,\max] & \mbox{if $geq \wedge leq$} \cr
+ x \in (\min,\max] & \mbox{if $geq \wedge \bar{leq}$} \cr
+ x \in [\min, \max) & \mbox{if $\bar{geq} \wedge leq$} \cr
+ x \in (\min, \max) & \mbox{if $\bar{geq} \wedge \bar{leq}$} \cr
+ \end{cases}
+ @f$
+ */
+ template <typename T>
+ static bool in(T x, T min, T max, bool geq = true, bool leq = true);
+
+ /**
+ Indicates whether @f$x@f$ is infinity
+ @param x is the value
+ @return whether @f$x@f$ is infinity
+ */
+ template <typename T>
+ static bool isInf(T x);
+
+ /**
+ Indicates whether @f$x@f$ is not-a-number (NaN)
+ @param x is the value
+ @return whether @f$x@f$ is not-a-number (NaN)
+ */
+ template <typename T>
+ static bool isNaN(T x);
+
+ /**
+ Indicates whether @f$x@f$ is finite, that is, @f$x \not\in
+ \{\pm\infty, \mathrm{NaN}\}@f$
+ @param x is the value
+ @return whether @f$x@f$ is finite
+ */
+ template <typename T>
+ static bool isFinite(T x);
+
+ /**
+ Returns whether @f$a@f$ is less than @f$b@f$ at the given tolerance
+ @param a
+ @param b
+ @param macheps is the minimum difference upon which two
+ floating-point values are considered equivalent
+ @return whether @f$a@f$ is less than @f$b@f$ at the given tolerance
+ */
+ static bool isLt(scalar a, scalar b, scalar macheps = fuzzylite::_macheps);
+ /**
+ Returns whether @f$a@f$ is less than or equal to @f$b@f$ at the given
+ tolerance
+ @param a
+ @param b
+ @param macheps is the minimum difference upon which two
+ floating-point values are considered equivalent
+ @return whether @f$a@f$ is less than or equal to @f$b@f$ at the given
+ tolerance
+ */
+ static bool isLE(scalar a, scalar b, scalar macheps = fuzzylite::_macheps);
+ /**
+ Returns whether @f$a@f$ is equal to @f$b@f$ at the given tolerance
+ @param a
+ @param b
+ @param macheps is the minimum difference upon which two
+ floating-point values are considered equivalent
+ @return whether @f$a@f$ is equal to @f$b@f$ at the given tolerance
+ */
+ static bool isEq(scalar a, scalar b, scalar macheps = fuzzylite::_macheps);
+ /**
+ Returns whether @f$a@f$ is greater than @f$b@f$ at the given tolerance
+ @param a
+ @param b
+ @param macheps is the minimum difference upon which two
+ floating-point values are considered equivalent
+ @return whether @f$a@f$ is greater than @f$b@f$ at the given tolerance
+ */
+ static bool isGt(scalar a, scalar b, scalar macheps = fuzzylite::_macheps);
+ /**
+ Returns whether @f$a@f$ is greater than or equal to @f$b@f$ at the
+ given tolerance
+ @param a
+ @param b
+ @param macheps is the minimum difference upon which two
+ floating-point values are considered equivalent
+ @return whether @f$a@f$ is greater than or equal to @f$b@f$ at the
+ given tolerance
+ */
+ static bool isGE(scalar a, scalar b, scalar macheps = fuzzylite::_macheps);
+
+ /**
+ Linearly interpolates the parameter @f$x@f$ in range
+ `[fromMin,fromMax]` to a new value in the range `[toMin,toMax]`
+ @param x is the source value to interpolate
+ @param fromMin is the minimum value of the source range
+ @param fromMax is the maximum value of the source range
+ @param toMin is the minimum value of the target range
+ @param toMax is the maximum value of the target range
+ @return the source value linearly interpolated to the target range:
+ @f$ y = y_a + (y_b - y_a) \dfrac{x-x_a}{x_b-x_a} @f$
+ */
+ static scalar scale(scalar x, scalar fromMin, scalar fromMax,
+ scalar toMin, scalar toMax);
+
+ /**
+ Linearly interpolates the parameter @f$x@f$ in range
+ `[fromMin,fromMax]` to a new value in the range `[toMin,toMax]`,
+ truncated to the range `[toMin,toMax]` if bounded is `true`.
+ @param x is the source value to interpolate
+ @param fromMin is the minimum value of the source range
+ @param fromMax is the maximum value of the source range
+ @param toMin is the minimum value of the target range
+ @param toMax is the maximum value of the target range
+ @param bounded determines whether the resulting value is bounded to
+ the range
+ @return the source value linearly interpolated to the target range:
+ @f$ y = y_a + (y_b - y_a) \dfrac{x-x_a}{x_b-x_a} @f$
+ */
+ static scalar scale(scalar x, scalar fromMin, scalar fromMax,
+ scalar toMin, scalar toMax, bool bounded);
+
+ /**
+ Adds two values
+ @param a
+ @param b
+ @return @f$a+b@f$
+ */
+ static scalar add(scalar a, scalar b);
+ /**
+ Subtracts two values
+ @param a
+ @param b
+ @return @f$a-b@f$
+ */
+ static scalar subtract(scalar a, scalar b);
+ /**
+ Multiplies two values
+ @param a
+ @param b
+ @return @f$a\times b@f$
+ */
+ static scalar multiply(scalar a, scalar b);
+ /**
+ Divides two values
+ @param a
+ @param b
+ @return @f$a/b@f$
+ */
+ static scalar divide(scalar a, scalar b);
+ /**
+ Computes the modulo
+ @param a
+ @param b
+ @return @f$a \mod b@f$
+ */
+ static scalar modulo(scalar a, scalar b);
+
+ /**
+ Computes the logical AND
+ @param a
+ @param b
+ @return @f$
+ \begin{cases}
+ 1.0 & \mbox{if $a=1 \wedge b=1$}\cr
+ 0.0 & \mbox{otherwise}
+ \end{cases}
+ @f$
+ */
+ static scalar logicalAnd(scalar a, scalar b);
+ /**
+ Computes the logical OR
+ @param a
+ @param b
+ @return @f$
+ \begin{cases}
+ 1.0 & \mbox{if $a=1 \vee b=1$}\cr
+ 0.0 & \mbox{otherwise}
+ \end{cases}
+ @f$
+ */
+ static scalar logicalOr(scalar a, scalar b);
+ /**
+ Returns the complement of the value
+ @param a
+ @return @f$
+ \begin{cases}
+ 0.0 & \mbox{if $a=1$}\cr
+ 1.0 & \mbox{otherwise}
+ \end{cases}
+ @f$
+ */
+ static scalar logicalNot(scalar a);
+ /**
+ Negates the value
+ @param a
+ @return -a
+ */
+ static scalar negate(scalar a);
+ /**
+ Rounds the value to the nearest integer
+ @param x
+ @return @f$
+ \begin{cases}
+ \lfloor x + 0.5 \rfloor & \mbox{if $x > 0$}\cr
+ \lceil x - 0.5 \rceil & \mbox{otherwise}
+ \end{cases}
+ @f$
+ */
+ static scalar round(scalar x);
+
+ /**
+ Returns whether @f$a@f$ is greater than or equal to @f$b@f$ at the
+ default tolerance
+ @param a
+ @param b
+ @return whether @f$a@f$ is greater than or equal to @f$b@f$ at the
+ default tolerance
+ */
+ static scalar gt(scalar a, scalar b);
+ /**
+ Returns whether @f$a@f$ is greater than or equal to @f$b@f$ at the
+ default tolerance
+ @param a
+ @param b
+ @return whether @f$a@f$ is greater than or equal to @f$b@f$ at the
+ default tolerance
+ */
+ static scalar ge(scalar a, scalar b);
+ /**
+ Returns whether @f$a@f$ is equal to @f$b@f$ at the default tolerance
+ @param a
+ @param b
+ @return whether @f$a@f$ is equal to @f$b@f$ at the default tolerance
+ */
+ static scalar eq(scalar a, scalar b);
+ /**
+ Returns whether @f$a@f$ is different from @f$b@f$ at the default
+ tolerance
+ @param a
+ @param b
+ @return whether @f$a@f$ is different from @f$b@f$ at the default
+ tolerance
+ */
+ static scalar neq(scalar a, scalar b);
+ /**
+ Returns whether @f$a@f$ is less than or equal to @f$b@f$ at the
+ default tolerance
+ @param a
+ @param b
+ @return whether @f$a@f$ is less than or equal to @f$b@f$ at the
+ default tolerance
+ */
+ static scalar le(scalar a, scalar b);
+ /**
+ Returns whether @f$a@f$ is less than @f$b@f$ at the default tolerance
+ @param a
+ @param b
+ @return whether @f$a@f$ is less than @f$b@f$ at the default tolerance
+ */
+ static scalar lt(scalar a, scalar b);
+
+ /**
+ Returns a random number
+ */
+ static int random();
+
+ /**
+ Increments @f$x@f$ by the unit, treating the entire vector as a
+ number. For example, incrementing a few times @f$x_0=\{0,0\}@f$
+ within boundaries @f$[0,1]@f$ results in: @f$x_1=\{0,1\}@f$,
+ @f$x_2=\{1,0\}@f$, @f$x_3=\{1,1\}@f$, @f$x_4=\{0,0\}@f$.
+ @param x is the vector to increment
+ @param min is the minimum value of the dimension
+ @param max is the maximum value of the dimension
+ @return `true` if @f$x@f$ was incremented, `false` otherwise (e.g.,
+ incrementing @f$x_3@f$ returns `false`). In earlier versions to 6.0, the
+ result was the inverse and indicated whether the counter had overflown
+ (most sincere apologies for this change).
+ */
+ static bool increment(std::vector<int>& x, std::vector<int>& min, std::vector<int>& max);
+ /**
+ Increments @f$x@f$ by the unit at the given position, treating the
+ entire vector as a number. For example, incrementing
+ @f$x_0=\{0,0,0\}@f$ within boundaries @f$[0,1]@f$ at the second
+ position results in: @f$x_1=\{0,1,0\}@f$, @f$x_2=\{1,0,0\}@f$,
+ @f$x_3=\{1,1,0\}@f$, @f$x_4=\{0,0,0\}@f$.
+ @param x is the vector to increment
+ @param position is the position of the vector to increment, where
+ smaller values lead to higher significance digits
+ @param min is the minimum value of the dimension
+ @param max is the maximum value of the dimension
+ @return `true` if @f$x@f$ was incremented, `false` otherwise (e.g.,
+ incrementing @f$x_3@f$ returns `false`). In earlier versions to 6.0, the
+ result was the inverse and indicated whether the counter had overflown
+ (most sincere apologies for this change).
+ */
+ static bool increment(std::vector<int>& x, int position, std::vector<int>& min, std::vector<int>& max);
+
+ /**
+ Computes the sum of the vector
+ */
+ template <typename T>
+ static T sum(const std::vector<T>& x);
+ /**
+ Computes the mean of the vector
+ @param x is the vector
+ @return @f$\dfrac{\sum_i{x_i}}{|x|}@f$
+ */
+ template <typename T>
+ static scalar mean(const std::vector<T>& x);
+ /**
+ Computes the variance of the vector
+ @param x is the vector
+ @return @f$ \sum_i{ (x_i - \bar{x})^2 } / (|x| - 1) @f$
+ */
+ template <typename T>
+ static scalar variance(const std::vector<T>& x);
+ /**
+ Computes the variance of the vector using the given mean
+ @param x is the vector
+ @param mean is the mean value of the vector
+ @return @f$ \sum_i{ (x_i - \bar{x})^2 } / (|x| - 1) @f$
+ */
+ template <typename T>
+ static scalar variance(const std::vector<T>& x, scalar mean);
+ /**
+ Computes the standard deviation of the vector
+ @param x
+ @return @f$ \sqrt{\mbox{variance}(x, \bar{x})} @f$
+ */
+ template <typename T>
+ static scalar standardDeviation(const std::vector<T>& x);
+ /**
+ Computes the standard deviation of the vector using the given mean
+ @param x
+ @param mean is the mean value of x
+ @return @f$ \sqrt{\mbox{variance}(x, \bar{x})} @f$
+ */
+ template <typename T>
+ static scalar standardDeviation(const std::vector<T>& x, scalar mean);
+
+ /**
+ Returns a valid name for variables
+ @param name
+ @return an name whose characters are in `[a-zA-Z_0-9.]`
+ */
+ static std::string validName(const std::string& name);
+
+ /**
+ Replaces the substrings that are equal to the given expression
+ @param str is the target string
+ @param find is the string to find
+ @param replace is the string to replace the findings
+ @param replaceAll whether all the substrings are to be replaced or
+ just the first string
+ @return the original string with replacements
+ */
+ static std::string findReplace(const std::string& str, const std::string& find,
+ const std::string& replace, bool replaceAll = true);
+
+ /**
+ Replaces the first substring that is equal to the given expression
+ @param str is the target string
+ @param find is the string to find
+ @param replace is the string to replace
+ @return the original string with the replacement
+ */
+ static std::string replaceFirst(const std::string& str, const std::string& find,
+ const std::string& replace);
+
+ /**
+ Replaces the every substring that is equal to the given expression
+ @param str is the target string
+ @param find is the string to find
+ @param replace is the string to replace
+ @return the original string with all of the replacements
+ */
+ static std::string replaceAll(const std::string& str, const std::string& find,
+ const std::string& replace);
+
+ /**
+ Splits the string around the given delimiter
+ @param str is the string to split
+ @param delimiter is the substrings on which the string will be split
+ @param ignoreEmpty whether the empty strings are discarded
+ @return the string split around the given delimiter
+ */
+ static std::vector<std::string> split(const std::string& str,
+ const std::string& delimiter = " ", bool ignoreEmpty = true);
+
+ /**
+ Removes whitespace at the beginning and end of the text
+ @param text
+ @return a space-trimmed string
+ */
+ static std::string trim(const std::string& text);
+
+ /**
+ Replaces every matching character in the text with the given
+ replacement
+ @param text is the string to have replacements
+ @param matchesChar is a pointer to a method that indicates whether
+ the given character is a match
+ @param replacement a string to replace a matching character
+ @return the string with every matching character replaced
+ */
+ static std::string format(const std::string& text, int matchesChar(int),
+ const std::string& replacement = "");
+
+ /**
+ Parses the given string into a scalar value
+ @param x is the string to parse
+ @return the given string into a scalar value
+ @throws fl::Exception if the string does not contain a scalar value
+ */
+ static scalar toScalar(const std::string& x); //throws (fl::Exception)
+
+ /**
+ Parses the given string into a scalar value without throwing an
+ exception
+ @param x is the string to parse
+ @param alternative is the value to return if the string does not
+ contain a scalar value
+ @param ok contains whether the operation was successful (optional)
+ @return the given string into a scalar value or the alternative value
+ if the string does not contain a scalar value
+ */
+ static scalar toScalar(const std::string& x, scalar alternative,
+ bool* ok = fl::null) FL_INOEXCEPT;
+
+ /**
+ Parses the given string into a vector of scalar values
+ @param x is the string containing space-separated values to parse
+ @return the vector of scalar values
+ @throws fl::Exception if the string contains an invalid scalar value
+ */
+ static std::vector<scalar> toScalars(const std::string& x); //throws (fl::Exception)
+
+ /**
+ Parses the given string into a vector of scalar values
+ @param x is the string containing space-separated values to parse
+ @param alternative is the value to use if an invalid value is found
+ @param ok contains whether the operation was successful (optional)
+ @return the vector of scalar values
+ */
+ static std::vector<scalar> toScalars(const std::string& x, scalar alternative,
+ bool* ok = fl::null) FL_INOEXCEPT;
+
+ /**
+ Indicates whether the string can be converted to a numeric value.
+ @param x
+ @return whether the string can be converted to a numeric value
+ */
+ static bool isNumeric(const std::string& x);
+
+ /**
+ Returns a string representation of the given value
+ @param x is the value
+ @param decimals is the number of decimals to display
+ @param scalarFormat are the flags for the underlying std::ostringstream
+ @return a string representation of the given value
+ */
+ template <typename T>
+ static std::string str(T x, int decimals = fuzzylite::_decimals,
+ std::ios_base::fmtflags scalarFormat = fuzzylite::_scalarFormat);
+
+ /**
+ Joins a vector of elements by the given separator into a single
+ string. The elements are represented as strings utilizing the
+ Operation::str() method on each element
+ @param x is the vector of elements
+ @param separator is the string to add between the elements
+ @return a single string joining the vector of elements by the given
+ separator
+ */
+ template <typename T>
+ static std::string join(const std::vector<T>& x, const std::string& separator);
+
+ /**
+ Joins a variadic number of elements by the given separator into a
+ single string. The elements are represented as strings utilizing the
+ Operation::str() method on each element
+ @param items is the number of elements to join
+ @param separator is the string to add between the elements
+ @param first is the first element, which defines the type of the
+ subsequent elements
+ @param ... are the remaining elements to join
+ @return a single string joining the variadic number of elements by
+ the given separator
+ */
+ template <typename T>
+ static std::string join(int items, const std::string& separator, T first, ...);
+ };
+
+ /**A shortened type to refer to Operation*/
+ typedef Operation Op;
+}
+
+
+/**
+ Template implementation
+ */
+
+#include "fl/defuzzifier/Defuzzifier.h"
+#include "fl/norm/Norm.h"
+#include "fl/norm/SNorm.h"
+#include "fl/norm/TNorm.h"
+
+#include <algorithm>
+#include <iomanip>
+#include <cstdarg>
+#include <cctype>
+
+namespace fl {
+
+ template <typename T>
+ inline T Operation::min(T a, T b) {
+ if (Op::isNaN(a)) return b;
+ if (Op::isNaN(b)) return a;
+ return a < b ? a : b;
+ }
+
+ template <typename T>
+ inline T Operation::max(T a, T b) {
+ if (Op::isNaN(a)) return b;
+ if (Op::isNaN(b)) return a;
+ return a > b ? a : b;
+ }
+
+ template <typename T>
+ inline T Operation::bound(T x, T min, T max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ template <typename T>
+ inline bool Operation::in(T x, T min, T max, bool geq, bool leq) {
+ bool left = geq ? Op::isGE(x, min) : Op::isGt(x, min);
+ bool right = leq ? Op::isLE(x, max) : Op::isLt(x, max);
+ return (left and right);
+ }
+
+ template <typename T>
+ inline bool Operation::isInf(T x) {
+ return x == fl::inf or x == -fl::inf;
+ }
+
+ template <typename T>
+ inline bool Operation::isNaN(T x) {
+ return (x != x);
+ }
+
+ template<typename T>
+ inline bool Operation::isFinite(T x) {
+ return not (x != x or x == fl::inf or x == -fl::inf);
+ }
+
+ inline bool Operation::isLt(scalar a, scalar b, scalar macheps) {
+ return not (a == b or std::abs(a - b) < macheps or (a != a and b != b)) and a < b;
+ }
+
+ inline bool Operation::isLE(scalar a, scalar b, scalar macheps) {
+ return a == b or std::abs(a - b) < macheps or (a != a and b != b) or a < b;
+ }
+
+ inline bool Operation::isEq(scalar a, scalar b, scalar macheps) {
+ return a == b or std::abs(a - b) < macheps or (a != a and b != b);
+ }
+
+ inline bool Operation::isGt(scalar a, scalar b, scalar macheps) {
+ return not (a == b or std::abs(a - b) < macheps or (a != a and b != b)) and a > b;
+ }
+
+ inline bool Operation::isGE(scalar a, scalar b, scalar macheps) {
+ return a == b or std::abs(a - b) < macheps or (a != a and b != b) or a > b;
+ }
+
+ inline scalar Operation::scale(scalar x, scalar fromMin, scalar fromMax, scalar toMin, scalar toMax) {
+ return (toMax - toMin) / (fromMax - fromMin) * (x - fromMin) + toMin;
+ }
+
+ inline scalar Operation::scale(scalar x, scalar fromMin, scalar fromMax, scalar toMin, scalar toMax, bool bounded) {
+ scalar result = (toMax - toMin) / (fromMax - fromMin) * (x - fromMin) + toMin;
+ return bounded ? Op::bound(result, toMin, toMax) : result;
+ }
+
+ inline scalar Operation::add(scalar a, scalar b) {
+ return a + b;
+ }
+
+ inline scalar Operation::subtract(scalar a, scalar b) {
+ return a - b;
+ }
+
+ inline scalar Operation::multiply(scalar a, scalar b) {
+ return a * b;
+ }
+
+ inline scalar Operation::divide(scalar a, scalar b) {
+ return a / b;
+ }
+
+ inline scalar Operation::modulo(scalar a, scalar b) {
+ return fmod(a, b);
+ }
+
+ inline scalar Operation::logicalAnd(scalar a, scalar b) {
+ return (isEq(a, 1.0) and isEq(b, 1.0)) ? 1.0 : 0.0;
+ }
+
+ inline scalar Operation::logicalOr(scalar a, scalar b) {
+ return (isEq(a, 1.0) or isEq(b, 1.0)) ? 1.0 : 0.0;
+ }
+
+ inline scalar Operation::logicalNot(scalar a) {
+ return isEq(a, 1.0) ? 0.0 : 1.0;
+ }
+
+ inline scalar Operation::negate(scalar a) {
+ return -a;
+ }
+
+ inline scalar Operation::round(scalar x) {
+ return (x > 0.0) ? std::floor(x + 0.5) : std::ceil(x - 0.5);
+ }
+
+ inline scalar Operation::gt(scalar a, scalar b) {
+ return isGt(a, b);
+ }
+
+ inline scalar Operation::ge(scalar a, scalar b) {
+ return isGE(a, b);
+ }
+
+ inline scalar Operation::eq(scalar a, scalar b) {
+ return isEq(a, b);
+ }
+
+ inline scalar Operation::neq(scalar a, scalar b) {
+ return not isEq(a, b);
+ }
+
+ inline scalar Operation::le(scalar a, scalar b) {
+ return isLE(a, b);
+ }
+
+ inline scalar Operation::lt(scalar a, scalar b) {
+ return isLt(a, b);
+ }
+
+ inline int Operation::random() {
+ return std::rand();
+ }
+
+ inline bool Operation::increment(std::vector<int>& x, std::vector<int>& min, std::vector<int>& max) {
+ return increment(x, -1 + int(x.size()), min, max);
+ }
+
+ inline bool Operation::increment(std::vector<int>& x, int position, std::vector<int>& min, std::vector<int>& max) {
+ if (x.empty() or position < 0) return false;
+
+ bool incremented = true;
+ if (x.at(position) < max.at(position)) {
+ ++x.at(position);
+ } else {
+ incremented = !(position == 0);
+ x.at(position) = min.at(position);
+ --position;
+ if (position >= 0) {
+ incremented = increment(x, position, min, max);
+ }
+ }
+ return incremented;
+ }
+
+ template<typename T>
+ inline T Operation::sum(const std::vector<T>& x) {
+ T result = T(0);
+ for (std::size_t i = 0; i < x.size(); ++i) {
+ result += x.at(i);
+ }
+ return result;
+ }
+
+ template<typename T>
+ inline scalar Operation::mean(const std::vector<T>& x) {
+ return scalar(sum(x)) / x.size();
+ }
+
+ template<typename T>
+ inline scalar Operation::standardDeviation(const std::vector<T>& x) {
+ return standardDeviation(x, mean(x));
+ }
+
+ template<typename T>
+ inline scalar Operation::standardDeviation(const std::vector<T>& x, scalar mean) {
+ if (x.empty()) return fl::nan;
+ if (x.size() == 1) return scalar(0.0);
+ return std::sqrt(variance(x, mean));
+ }
+
+ template<typename T>
+ inline scalar Operation::variance(const std::vector<T>& x) {
+ return variance(x, mean(x));
+ }
+
+ template<typename T>
+ inline scalar Operation::variance(const std::vector<T>& x, scalar mean) {
+ if (x.empty()) return fl::nan;
+ if (x.size() == 1) return scalar(0.0);
+ scalar result = 0.0;
+ for (std::size_t i = 0; i < x.size(); ++i) {
+ result += (x.at(i) - mean) * (x.at(i) - mean);
+ }
+ result /= -1 + x.size();
+ return result;
+ }
+
+
+
+ //Text Operations:
+
+ inline std::string Operation::validName(const std::string& name) {
+ if (trim(name).empty()) return "unnamed";
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < name.length(); ++i) {
+ char c = name[i];
+ if (c == '_' or c == '.' or isalnum(c)) {
+ ss << c;
+ }
+ }
+ return ss.str();
+ }
+
+ inline std::string Operation::findReplace(const std::string& str, const std::string& find,
+ const std::string& replace, bool replaceAll) {
+ std::ostringstream result;
+ std::size_t fromIndex = 0, nextIndex;
+ do {
+ nextIndex = str.find(find, fromIndex);
+ result << str.substr(fromIndex, nextIndex - fromIndex);
+ if (nextIndex != std::string::npos)
+ result << replace;
+ fromIndex = nextIndex + find.size();
+ } while (replaceAll and nextIndex != std::string::npos);
+ return result.str();
+ }
+
+ inline std::string Operation::replaceFirst(const std::string& str,
+ const std::string& find, const std::string& replace) {
+ return findReplace(str, find, replace, false);
+ }
+
+ inline std::string Operation::replaceAll(const std::string& str,
+ const std::string& find, const std::string& replace) {
+ return findReplace(str, find, replace, true);
+ }
+
+ inline std::vector<std::string> Operation::split(const std::string& str,
+ const std::string& delimiter, bool ignoreEmpty) {
+ std::vector<std::string> result;
+ if (str.empty() or delimiter.empty()) {
+ result.push_back(str);
+ return result;
+ }
+ std::string::const_iterator position = str.begin(), next = str.begin();
+ while (next != str.end()) {
+ next = std::search(position, str.end(), delimiter.begin(), delimiter.end());
+ std::string token(position, next);
+ if (not (token.empty() and ignoreEmpty)) {
+ result.push_back(token);
+ }
+ if (next != str.end()) {
+ position = next + delimiter.size();
+ }
+ }
+ return result;
+ }
+
+ inline std::string Operation::trim(const std::string& text) {
+ if (text.empty()) return text;
+ if (not (std::isspace(text.at(0)) or std::isspace(text.at(text.size() - 1))))
+ return text;
+ std::size_t start = 0, end = text.size() - 1;
+ while (start <= end and std::isspace(text.at(start))) {
+ ++start;
+ }
+ while (end >= start and std::isspace(text.at(end))) {
+ --end;
+ }
+ std::size_t length = end - start + 1;
+ if (length <= 0) return "";
+ return text.substr(start, length);
+ }
+
+ inline std::string Operation::format(const std::string& text, int matchesChar(int),
+ const std::string& replacement) {
+ std::ostringstream ss;
+ std::string::const_iterator it = text.begin();
+ while (it != text.end()) {
+ if (matchesChar(*it)) {
+ ss << *it;
+ } else {
+ ss << replacement;
+ }
+ ++it;
+ }
+ return ss.str();
+ }
+
+ inline scalar Operation::toScalar(const std::string& x) {
+ std::istringstream iss(x);
+ scalar result;
+ iss >> result;
+ char strict;
+ if (not (iss.fail() or iss.get(strict))) return result;
+
+ std::ostringstream _nan;
+ _nan << fl::nan;
+ if (x == _nan.str() or x == "nan")
+ return fl::nan;
+
+ std::ostringstream pInf;
+ pInf << fl::inf;
+ if (x == pInf.str() or x == "inf")
+ return fl::inf;
+
+ std::ostringstream nInf;
+ nInf << (-fl::inf);
+ if (x == nInf.str() or x == "-inf")
+ return -fl::inf;
+
+ throw Exception("[conversion error] from <" + x + "> to scalar", FL_AT);
+ }
+
+ inline scalar Operation::toScalar(const std::string& x, scalar alternative, bool* ok) FL_INOEXCEPT {
+ if (ok) *ok = true;
+ std::istringstream iss(x);
+ scalar result;
+ iss >> result;
+ char strict;
+ if (not (iss.fail() or iss.get(strict))) return result;
+
+ std::ostringstream _nan;
+ _nan << fl::nan;
+ if (x == _nan.str() or x == "nan")
+ return fl::nan;
+
+ std::ostringstream pInf;
+ pInf << fl::inf;
+ if (x == pInf.str() or x == "inf")
+ return fl::inf;
+
+ std::ostringstream nInf;
+ nInf << (-fl::inf);
+ if (x == nInf.str() or x == "-inf")
+ return -fl::inf;
+
+ if (ok) *ok = false;
+ return alternative;
+ }
+
+ inline std::vector<scalar> Operation::toScalars(const std::string& x) {
+ std::vector<scalar> result;
+ std::istringstream tokenizer(x);
+ std::string token;
+ while (tokenizer >> token) {
+ result.push_back(Op::toScalar(token));
+ }
+ return result;
+ }
+
+ inline std::vector<scalar> Operation::toScalars(const std::string& x,
+ scalar alternative, bool* ok) FL_INOEXCEPT {
+ std::vector<scalar> result;
+ std::istringstream tokenizer(x);
+ std::string token;
+ bool allOK = true;
+ while (tokenizer >> token) {
+ bool good;
+ result.push_back(Op::toScalar(token, alternative, &good));
+ allOK &= good;
+ }
+ if (ok) *ok = allOK;
+ return result;
+ }
+
+ inline bool Operation::isNumeric(const std::string& x) {
+ try {
+ Op::toScalar(x);
+ return true;
+ } catch (...) {
+ return false;
+ }
+ }
+
+ template <typename T>
+ inline std::string Operation::str(T x, int decimals,
+ std::ios_base::fmtflags scalarFormat) {
+ std::ostringstream ss;
+ if (scalarFormat != std::ios_base::fmtflags(0x0)) ss.flags(scalarFormat);
+ if (decimals >= 0) ss.precision(decimals);
+ if (Op::isNaN(x)) {
+ ss << "nan";
+ } else if (Op::isInf(x)) {
+ ss << (x < T(0) ? "-inf" : "inf");
+ } else if (decimals >= 0 //print x considering the given decimals regardless of macheps
+ and Op::isEq(scalar(x), 0.0, std::pow(10.0, -decimals))) {
+ ss << T(0);
+ } else ss << x;
+ return ss.str();
+ }
+
+ template <> FL_API
+ inline std::string Operation::str(const std::string& x, int decimals,
+ std::ios_base::fmtflags scalarFormat) {
+ FL_IUNUSED(decimals);
+ FL_IUNUSED(scalarFormat);
+ return x;
+ }
+
+ template <typename T>
+ inline std::string Operation::join(const std::vector<T>& x,
+ const std::string& separator) {
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < x.size(); ++i) {
+ ss << str(x.at(i));
+ if (i + 1 < x.size()) ss << separator;
+ }
+ return ss.str();
+ }
+
+ template <> FL_API
+ inline std::string Operation::join(const std::vector<std::string>& x,
+ const std::string& separator) {
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < x.size(); ++i) {
+ ss << x.at(i);
+ if (i + 1 < x.size()) ss << separator;
+ }
+ return ss.str();
+ }
+
+ template <typename T>
+ inline std::string Operation::join(int items, const std::string& separator, T first, ...) {
+ std::ostringstream ss;
+ ss << str(first);
+ if (items > 1) ss << separator;
+ va_list args;
+ va_start(args, first);
+ for (int i = 0; i < items - 1; ++i) {
+ ss << str(va_arg(args, T));
+ if (i + 1 < items - 1) ss << separator;
+ }
+ va_end(args);
+ return ss.str();
+ }
+
+ template <> FL_API
+ inline std::string Operation::join(int items, const std::string& separator,
+ float first, ...) {
+ std::ostringstream ss;
+ ss << str(first);
+ if (items > 1) ss << separator;
+ va_list args;
+ va_start(args, first);
+ for (int i = 0; i < items - 1; ++i) {
+ ss << str(va_arg(args, double)); //automatic promotion
+ if (i + 1 < items - 1) ss << separator;
+ }
+ va_end(args);
+ return ss.str();
+ }
+
+ template <> FL_API
+ inline std::string Operation::join(int items, const std::string& separator, const char* first, ...) {
+ std::ostringstream ss;
+ ss << first;
+ if (items > 1) ss << separator;
+ va_list args;
+ va_start(args, first);
+ for (int i = 0; i < items - 1; ++i) {
+ ss << va_arg(args, const char*);
+ if (i + 1 < items - 1) ss << separator;
+ }
+ va_end(args);
+ return ss.str();
+ }
+}
+#endif /* FL_OPERATION_H */
+
diff --git a/fuzzylite/fl/activation/Activation.h b/fuzzylite/fl/activation/Activation.h
new file mode 100644
index 0000000..562d53e
--- /dev/null
+++ b/fuzzylite/fl/activation/Activation.h
@@ -0,0 +1,95 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ACTIVATION_H
+#define FL_ACTIVATION_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+namespace fl {
+ class RuleBlock;
+
+ /**
+ The Activation class is the abstract class for RuleBlock activation
+ methods. An activation method implements the criteria to activate the
+ rules within a given rule block. An activation method needs to process
+ every rule and determine whether the rule is to be activated or
+ deactivated. The activation methods were first introduced in version 6.0,
+ but in earlier versions the term `activation` referred to the TNorm that
+ modulated the consequent of a rule, which is now referred to as the
+ `implication` operator.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+
+ class FL_API Activation {
+ public:
+
+ Activation() { }
+
+ virtual ~Activation() { }
+
+ FL_DEFAULT_COPY_AND_MOVE(Activation)
+
+ /**
+ Returns the name of the activation method, which is also utilized to
+ register the activation method in the ActivationFactory.
+ @return the name of the activation method
+ @see ActivationFactory
+ */
+ virtual std::string className() const = 0;
+
+ /**
+ Returns the parameters of the activation method, which can be used to
+ configure other instances of the activation method.
+ @return the parameters of the activation method
+ */
+ virtual std::string parameters() const = 0;
+
+ /**
+ Configures the activation method with the given parameters.
+ @param parameters contains a list of space-separated parameter values
+ */
+ virtual void configure(const std::string& parameters) = 0;
+
+ /**
+ Computes the estimated complexity of activating the given rule block
+ @return the estimated complexity of activating the given rule block
+ */
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const = 0;
+
+ /**
+ Activates the rule block
+ @param ruleBlock is the rule block to activate
+ */
+ virtual void activate(RuleBlock* ruleBlock) = 0;
+
+ /**
+ Clones the activation method.
+ @return a clone of the activation method
+ */
+ virtual Activation* clone() const = 0;
+ };
+
+}
+
+#endif /* FL_ACTIVATION_H */
diff --git a/fuzzylite/fl/activation/First.h b/fuzzylite/fl/activation/First.h
new file mode 100644
index 0000000..355b1a9
--- /dev/null
+++ b/fuzzylite/fl/activation/First.h
@@ -0,0 +1,104 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FIRST_H
+#define FL_FIRST_H
+
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The First class is a RuleBlock Activation method that activates the first
+ @f$n@f$ rules whose activation degrees are greater than or equal to the given
+ threshold. The rules are iterated in the order they were added to the rule block.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Last
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+
+ class FL_API First : public Activation {
+ private:
+ int _numberOfRules;
+ scalar _threshold;
+ public:
+
+ explicit First(int numberOfRules = 1, scalar threshold = 0.0);
+ virtual ~First();
+ FL_DEFAULT_COPY_AND_MOVE(First)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ Returns the number of rules and the threshold of the activation method
+ @return "numberOfRules threshold"
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ Configures the activation method with the given number of rules and
+ threshold
+ @param parameters as "numberOfRules threshold"
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Sets the number of rules for the activation degree
+ @param numberOfRules is the number of rules for the activation degree
+ */
+ virtual void setNumberOfRules(int numberOfRules);
+
+ /**
+ Gets the number of rules for the activation degree
+ @return the number of rules for the activation degree
+ */
+ virtual int getNumberOfRules() const;
+
+ /**
+ Sets the threshold for the activation degree
+ @param threshold is the threshold for the activation degree
+ */
+ virtual void setThreshold(scalar threshold);
+
+ /**
+ Gets the threshold for the activation degree
+ @return the threshold for the activation degree
+ */
+ virtual scalar getThreshold() const;
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates the first @f$n@f$ rules whose activation degrees are greater than or
+ equal to the given threshold. The rules are iterated in the order the
+ rules were added to the rule block.
+ @param ruleBlock is the rule block to activate
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual First* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+
+}
+
+
+#endif /* FL_FIRST_H */
diff --git a/fuzzylite/fl/activation/General.h b/fuzzylite/fl/activation/General.h
new file mode 100644
index 0000000..8b057e9
--- /dev/null
+++ b/fuzzylite/fl/activation/General.h
@@ -0,0 +1,73 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_GENERAL_H
+#define FL_GENERAL_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The General class is a RuleBlock Activation method that activates every
+ rule following the order in which the rules were added to the rule block.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+
+ class FL_API General : public Activation {
+ public:
+
+ General();
+ virtual ~General();
+ FL_DEFAULT_COPY_AND_MOVE(General)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ No parameters are required to configure the activation method.
+ @return an empty string
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ No parameters are required to configure the activation method.
+ @param parameters is an empty string
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates every rule in the given rule block following the order in
+ which the rules were added.
+ @param ruleBlock is the rule block to activate
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual General* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+}
+
+#endif /* FL_GENERAL_H */
diff --git a/fuzzylite/fl/activation/Highest.h b/fuzzylite/fl/activation/Highest.h
new file mode 100644
index 0000000..d3abc72
--- /dev/null
+++ b/fuzzylite/fl/activation/Highest.h
@@ -0,0 +1,86 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HIGHEST_H
+#define FL_HIGHEST_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The Highest class is a RuleBlock Activation method that activates a given
+ number of rules with highest activation degrees in descending order.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Lowest
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+ class FL_API Highest : public Activation {
+ private:
+ int _numberOfRules;
+ public:
+ explicit Highest(int numberOfRules = 1);
+ virtual ~Highest();
+ FL_DEFAULT_COPY_AND_MOVE(Highest)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ Returns the number of rules to activate.
+ @return number of rules to activate
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ Configures the activation method with the number of rules to activate.
+ @param parameters contains the number of rules to activate
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Sets the number of rules to activate
+ @param numberOfRules is the number of rules to activate
+ */
+ virtual void setNumberOfRules(int numberOfRules);
+
+ /**
+ Returns the number of rules to activate
+ @return the number of rules to activate
+ */
+ virtual int getNumberOfRules() const;
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates the given number of rules with the highest activation
+ degrees
+ @param ruleBlock is the rule block to activate.
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual Highest* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+}
+
+#endif /* FL_HIGHEST_H */
diff --git a/fuzzylite/fl/activation/Last.h b/fuzzylite/fl/activation/Last.h
new file mode 100644
index 0000000..9dadede
--- /dev/null
+++ b/fuzzylite/fl/activation/Last.h
@@ -0,0 +1,103 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_LAST_H
+#define FL_LAST_H
+
+
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The Last class is a RuleBlock Activation method that activates the last
+ @f$n@f$ rules whose activation degrees are greater than or equal to the given
+ threshold. The rules are iterated in the reverse order in which they were
+ added to the rule block.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see First
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+
+ class FL_API Last : public Activation {
+ private:
+ int _numberOfRules;
+ scalar _threshold;
+ public:
+ explicit Last(int numberOfRules = 1, scalar threshold = 0.0);
+ virtual ~Last();
+ FL_DEFAULT_COPY_AND_MOVE(Last)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ Returns the number of rules and the threshold of the activation method
+ @return "numberOfRules threshold"
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ Configures the activation method with the given number of rules and
+ threshold
+ @param parameters as "numberOfRules threshold"
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Sets the number of rules for the activation degree
+ @param numberOfRules is the number of rules for the activation degree
+ */
+ virtual void setNumberOfRules(int numberOfRules);
+
+ /**
+ Gets the number of rules for the activation degree
+ @return the number of rules for the activation degree
+ */
+ virtual int getNumberOfRules() const;
+ /**
+ Sets the threshold for the activation degree
+ @param threshold is the threshold for the activation degree
+ */
+ virtual void setThreshold(scalar threshold);
+
+ /**
+ Gets the threshold for the activation degree
+ @return the threshold for the activation degree
+ */
+ virtual scalar getThreshold() const;
+
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates the last @f$n@f$ rules whose activation degrees are greater
+ than the given threshold. The rules are iterated in the reverse order
+ that the rules were added to the rule block.
+ @param ruleBlock is the rule block to activate
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual Last* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+}
+
+#endif /* FL_LAST_H */
diff --git a/fuzzylite/fl/activation/Lowest.h b/fuzzylite/fl/activation/Lowest.h
new file mode 100644
index 0000000..dab8419
--- /dev/null
+++ b/fuzzylite/fl/activation/Lowest.h
@@ -0,0 +1,87 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_LOWEST_H
+#define FL_LOWEST_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The Lowest class is a RuleBlock Activation method that activates a given
+ number of rules with lowest activation degrees in ascending order
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Highest
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+ class FL_API Lowest : public Activation {
+ private:
+ int _numberOfRules;
+ public:
+ explicit Lowest(int numberOfRules = 1);
+ virtual ~Lowest();
+ FL_DEFAULT_COPY_AND_MOVE(Lowest)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ Returns the number of rules to activate
+ @return number of rules to activate
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ Configures the activation method with the number of rules to activate
+ @param parameters contains the number of rules to activate
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Sets the number of rules to activate
+ @param numberOfRules is the number of rules to activate
+ */
+ virtual void setNumberOfRules(int numberOfRules);
+
+ /**
+ Returns the number of rules to activate
+ @return the number of rules to activate
+ */
+ virtual int getNumberOfRules() const;
+
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates the rules with the lowest activation degrees in the given
+ rule block
+ @param ruleBlock is the rule block to activate
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual Lowest* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+}
+
+#endif /* FL_LOWEST_H */
diff --git a/fuzzylite/fl/activation/Proportional.h b/fuzzylite/fl/activation/Proportional.h
new file mode 100644
index 0000000..09e51a7
--- /dev/null
+++ b/fuzzylite/fl/activation/Proportional.h
@@ -0,0 +1,71 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_PROPORTIONAL_H
+#define FL_PROPORTIONAL_H
+
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The Proportional class is a RuleBlock Activation method that activates
+ the rules utilizing activation degrees proportional to the activation
+ degrees of the other rules, thus the sum of the activation degrees is
+ equal to one.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+ class FL_API Proportional : public Activation {
+ public:
+ Proportional();
+ virtual ~Proportional();
+ FL_DEFAULT_COPY_AND_MOVE(Proportional)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ No parameters are required to configure the activation method
+ @return an empty string
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ No parameters are required to configure the activation method
+ @param parameters is an empty string
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates the rules utilizing activation degrees proportional to
+ the activation degrees of the other rules in the rule block.
+ @param ruleBlock is the rule block to activate.
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual Proportional* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+}
+
+#endif /* FL_PROPORTIONAL_H */
diff --git a/fuzzylite/fl/activation/Threshold.h b/fuzzylite/fl/activation/Threshold.h
new file mode 100644
index 0000000..0baadfa
--- /dev/null
+++ b/fuzzylite/fl/activation/Threshold.h
@@ -0,0 +1,183 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_THRESHOLD_H
+#define FL_THRESHOLD_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/activation/Activation.h"
+
+#include <vector>
+
+namespace fl {
+
+ /**
+ The Threshold class is a RuleBlock Activation method that activates the
+ rules whose activation degrees satisfy the equation given by the
+ comparison operator and the threshold, and deactivates the rules which do
+ not satisfy the equation.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Rule
+ @see RuleBlock
+ @see ActivationFactory
+ @since 6.0
+ */
+
+ class FL_API Threshold : public Activation {
+ public:
+
+ /**
+ Comparison is an enumerator that provides six comparison operators
+ between the activation degree @f$a@f$ and the threshold @f$\theta@f$.
+ */
+ enum Comparison {
+ /**@f$a < \theta@f$*/
+ LessThan,
+ /**@f$a \leq \theta@f$*/
+ LessThanOrEqualTo,
+ /**@f$a = \theta@f$*/
+ EqualTo,
+ /**@f$a \neq \theta@f$*/
+ NotEqualTo,
+ /**@f$a \geq \theta@f$*/
+ GreaterThanOrEqualTo,
+ /**@f$a > \theta@f$*/
+ GreaterThan
+ };
+ private:
+ Comparison _comparison;
+ scalar _value;
+ public:
+ explicit Threshold(Comparison comparison = GreaterThanOrEqualTo, scalar threshold = 0.0);
+ explicit Threshold(const std::string& comparison, scalar threshold);
+ virtual ~Threshold();
+ FL_DEFAULT_COPY_AND_MOVE(Threshold)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ Returns the comparison operator followed by the threshold.
+ @return comparison operator and threshold
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+
+ /**
+ Configures the activation method with the comparison operator and the
+ threshold.
+ @param parameters is the comparison operator and threshold
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Sets the comparison operator for the activation method
+ @param comparison is the operator for the activation method
+ */
+ virtual void setComparison(Comparison comparison);
+
+ /**
+ Gets the comparison operator for the activation method
+ @return comparison operator for the activation method
+ */
+ virtual Comparison getComparison() const;
+
+ /**
+ Returns the comparison operator of the activation method
+ @return the comparison operator in (`==`, `!=`, `<`, `>`, `<=`, `>=`)
+ */
+ virtual std::string comparisonOperator() const;
+
+ /**
+ Returns the given comparison operator of the activation method
+ @param comparison is a valid enum value
+ @return the comparison operator for the given enum value
+ @throws fl::Exception if the given comparison operator is not valid
+ */
+ virtual std::string comparisonOperator(Comparison comparison) const;
+
+ /**
+ Returns the list of available comparison operators of the activation
+ method
+ @return (`==`, `!=`, `<`, `>`, `<=`, `>=`)
+ */
+ virtual std::vector<std::string> availableComparisonOperators() const;
+
+
+ /**
+ Parses the comparison operator, or throws an
+ exception if the parameter does not correspond to a valid operator
+ @param comparisonOperator is an operator in (`==`, `!=`, `<`, `>`,
+ `<=`, `>=`)
+ */
+ virtual Comparison parseComparison(const std::string& comparisonOperator) const;
+
+ /**
+ Sets the threshold value of the activation method
+ @param value is the threshold value for activation degrees
+ */
+ virtual void setValue(scalar value);
+
+ /**
+ Gets the threshold value of the activation method
+ @return the threshold value of the activation method
+ */
+ virtual scalar getValue() const;
+
+ /**
+ Sets the comparison operator and the threshold for the activation
+ method
+ @param comparison is the comparison enumerator
+ @param value is the threshold of the activation method
+ */
+ virtual void setThreshold(Comparison comparison, scalar value);
+
+ /**
+ Sets the comparison operator and the threshold for the activation method
+ @param comparison is a valid comparison operator
+ @param value is the threshold for activation degrees
+ @throws fl::Exception if the comparison operator is not valid
+ */
+ virtual void setThreshold(const std::string& comparison, scalar value);
+
+ /**
+ Returns whether the activation method will activate a rule with
+ the given activation degree
+ @param activationDegree an activation degree
+ @return whether the comparison equation is satisfied with the
+ activation degree and the threshold
+ */
+ virtual bool activatesWith(scalar activationDegree) const;
+
+
+ virtual Complexity complexity(const RuleBlock* ruleBlock) const FL_IOVERRIDE;
+
+ /**
+ Activates the rules whose activation degrees satisfy the comparison
+ equation with the given threshold, and deactivate the rules which do
+ not.
+ @param ruleBlock is the rule block to activate
+ */
+ virtual void activate(RuleBlock* ruleBlock) FL_IOVERRIDE;
+
+ virtual Threshold* clone() const FL_IOVERRIDE;
+
+ static Activation* constructor();
+ };
+
+}
+
+#endif /* FL_THRESHOLD_H */
diff --git a/fuzzylite/fl/defuzzifier/Bisector.h b/fuzzylite/fl/defuzzifier/Bisector.h
new file mode 100644
index 0000000..046b185
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/Bisector.h
@@ -0,0 +1,64 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_BISECTOR_H
+#define FL_BISECTOR_H
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The Bisector class is an IntegralDefuzzifier that computes the bisector
+ of a fuzzy set represented in a Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Centroid
+ @see IntegralDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API Bisector : public IntegralDefuzzifier {
+ public:
+ explicit Bisector(int resolution = defaultResolution());
+ virtual ~Bisector() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Bisector)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the bisector of a fuzzy set. The defuzzification process
+ integrates over the fuzzy set utilizing the boundaries given as
+ parameters. The integration algorithm is the midpoint rectangle
+ method (https://en.wikipedia.org/wiki/Rectangle_method).
+
+ @param term is the fuzzy set
+ @param minimum is the minimum value of the fuzzy set
+ @param maximum is the maximum value of the fuzzy set
+ @return the @f$x@f$-coordinate of the bisector of the fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual Bisector* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_BISECTOR_H */
+
diff --git a/fuzzylite/fl/defuzzifier/Centroid.h b/fuzzylite/fl/defuzzifier/Centroid.h
new file mode 100644
index 0000000..b056eac
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/Centroid.h
@@ -0,0 +1,63 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CENTROID_H
+#define FL_CENTROID_H
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The Centroid class is an IntegralDefuzzifier that computes the centroid
+ of a fuzzy set represented in a Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see BiSector
+ @see IntegralDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API Centroid : public IntegralDefuzzifier {
+ public:
+ explicit Centroid(int resolution = defaultResolution());
+ virtual ~Centroid() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Centroid)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the centroid of a fuzzy set. The defuzzification process
+ integrates over the fuzzy set utilizing the boundaries given as
+ parameters. The integration algorithm is the midpoint rectangle
+ method (https://en.wikipedia.org/wiki/Rectangle_method).
+
+ @param term is the fuzzy set
+ @param minimum is the minimum value of the fuzzy set
+ @param maximum is the maximum value of the fuzzy set
+ @return the @f$x@f$-coordinate of the centroid of the fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual Centroid* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_CENTROID_H */
diff --git a/fuzzylite/fl/defuzzifier/Defuzzifier.h b/fuzzylite/fl/defuzzifier/Defuzzifier.h
new file mode 100644
index 0000000..25749eb
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/Defuzzifier.h
@@ -0,0 +1,76 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_DEFUZZIFIER_H
+#define FL_DEFUZZIFIER_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+#include <string>
+
+namespace fl {
+ class Term;
+
+ /**
+ The Defuzzifier class is the abstract class for defuzzifiers.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see IntegralDefuzzifier
+ @see WeightedDefuzzifier
+ @since 4.0
+ */
+ class FL_API Defuzzifier {
+ public:
+
+ Defuzzifier() {
+ }
+
+ virtual ~Defuzzifier() {
+ }
+ FL_DEFAULT_COPY_AND_MOVE(Defuzzifier)
+
+ /**
+ Returns the name of the class of the defuzzifier
+ @return the name of the class of the defuzzifier
+ */
+ virtual std::string className() const = 0;
+ /**
+ Creates a clone of the defuzzifier
+ @return a clone of the defuzzifier
+ */
+ virtual Defuzzifier* clone() const = 0;
+
+ /**
+ Computes the complexity of defuzzifying the given term
+ @param term is the term to defuzzify
+ @return the complexity of defuzzifying the given term
+ */
+ virtual Complexity complexity(const Term* term) const = 0;
+ /**
+ Defuzzifies the given fuzzy term utilizing the range `[minimum,maximum]`
+ @param term is the term to defuzzify, typically an Aggregated term
+ @param minimum is the minimum value of the range
+ @param maximum is the maximum value of the range
+ @return the defuzzified value of the given fuzzy term
+ */
+ virtual scalar defuzzify(const Term* term, scalar minimum, scalar maximum) const = 0;
+
+ };
+}
+
+#endif /* FL_DEFUZZIFIER_H */
diff --git a/fuzzylite/fl/defuzzifier/IntegralDefuzzifier.h b/fuzzylite/fl/defuzzifier/IntegralDefuzzifier.h
new file mode 100644
index 0000000..9cfd132
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/IntegralDefuzzifier.h
@@ -0,0 +1,73 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_INTEGRALDEFUZZIFIER_H
+#define FL_INTEGRALDEFUZZIFIER_H
+
+#include "fl/defuzzifier/Defuzzifier.h"
+
+namespace fl {
+
+ /**
+ The IntegralDefuzzifier class is the base class for defuzzifiers which integrate
+ over the fuzzy set.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 4.0
+ */
+ class FL_API IntegralDefuzzifier : public Defuzzifier {
+ private:
+ static int _defaultResolution;
+
+ int _resolution;
+ public:
+ explicit IntegralDefuzzifier(int resolution = defaultResolution());
+ virtual ~IntegralDefuzzifier() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(IntegralDefuzzifier)
+
+ /**
+ Sets the resolution of the defuzzifier. The resolution refers to the
+ number of divisions in which the range `[minimum,maximum]` is divided
+ in order to integrate the area under the curve
+
+ @param resolution is the resolution of the defuzzifier
+ */
+ virtual void setResolution(int resolution);
+ /**
+ Gets the resolution of the defuzzifier. The resolution refers to the
+ number of divisions in which the range `[minimum,maximum]` is divided
+ in order to integrate the area under the curve
+
+ @return the resolution of the defuzzifier
+ */
+ virtual int getResolution() const;
+
+ /**
+ Sets the default resolution for integral-based defuzzifiers
+ @param defaultResolution is the default resolution for integral-based defuzzifiers
+ */
+ static void setDefaultResolution(int defaultResolution);
+ /**
+ Gets the default resolution for integral-based defuzzifiers
+ @return the default resolution for integral-based defuzzifiers
+ */
+ static int defaultResolution();
+
+ };
+}
+
+#endif /* INTEGRALDEFUZZIFIER_H */
+
diff --git a/fuzzylite/fl/defuzzifier/LargestOfMaximum.h b/fuzzylite/fl/defuzzifier/LargestOfMaximum.h
new file mode 100644
index 0000000..e325db5
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/LargestOfMaximum.h
@@ -0,0 +1,67 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_LARGESTOFMAXIMUM_H
+#define FL_LARGESTOFMAXIMUM_H
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The LargestOfMaximum class is an IntegralDefuzzifier that computes the
+ largest value of the maximum membership function of a fuzzy set
+ represented in a Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see SmallestOfMaximum
+ @see MeanOfMaximum
+ @see IntegralDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API LargestOfMaximum : public IntegralDefuzzifier {
+ public:
+ explicit LargestOfMaximum(int resolution = defaultResolution());
+ virtual ~LargestOfMaximum() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(LargestOfMaximum)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the largest value of the maximum membership function of a
+ fuzzy set. The largest value is computed by integrating over the
+ fuzzy set. The integration algorithm is the midpoint rectangle method
+ (https://en.wikipedia.org/wiki/Rectangle_method).
+
+ @param term is the fuzzy set
+ @param minimum is the minimum value of the fuzzy set
+ @param maximum is the maximum value of the fuzzy set
+ @return the largest @f$x@f$-coordinate of the maximum membership
+ function value in the fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual LargestOfMaximum* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_LARGESTOFMAXIMUM_H */
+
diff --git a/fuzzylite/fl/defuzzifier/MeanOfMaximum.h b/fuzzylite/fl/defuzzifier/MeanOfMaximum.h
new file mode 100644
index 0000000..027f43b
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/MeanOfMaximum.h
@@ -0,0 +1,67 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_MEANOFMAXIMUM_H
+#define FL_MEANOFMAXIMUM_H
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The MeanOfMaximum class is an IntegralDefuzzifier that computes the mean
+ value of the maximum membership function of a fuzzy set represented in a
+ Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see SmallestOfMaximum
+ @see MeanOfMaximum
+ @see IntegralDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API MeanOfMaximum : public IntegralDefuzzifier {
+ public:
+ explicit MeanOfMaximum(int resolution = defaultResolution());
+ virtual ~MeanOfMaximum() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(MeanOfMaximum)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the mean value of the maximum membership function
+ of a fuzzy set. The mean value is computed while integrating
+ over the fuzzy set. The integration algorithm is the midpoint
+ rectangle method (https://en.wikipedia.org/wiki/Rectangle_method).
+
+ @param term is the fuzzy set
+ @param minimum is the minimum value of the fuzzy set
+ @param maximum is the maximum value of the fuzzy set
+ @return the mean @f$x@f$-coordinate of the maximum membership
+ function value in the fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual MeanOfMaximum* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_MEANOFMAXIMUM_H */
+
diff --git a/fuzzylite/fl/defuzzifier/SmallestOfMaximum.h b/fuzzylite/fl/defuzzifier/SmallestOfMaximum.h
new file mode 100644
index 0000000..94f8a7a
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/SmallestOfMaximum.h
@@ -0,0 +1,67 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SMALLESTOFMAXIMUM_H
+#define FL_SMALLESTOFMAXIMUM_H
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The SmallestOfMaximum class is an IntegralDefuzzifier that computes the
+ smallest value of the maximum membership function of a fuzzy set
+ represented in a Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see LargestOfMaximum
+ @see MeanOfMaximum
+ @see IntegralDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API SmallestOfMaximum : public IntegralDefuzzifier {
+ public:
+ explicit SmallestOfMaximum(int resolution = defaultResolution());
+ virtual ~SmallestOfMaximum() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(SmallestOfMaximum)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the smallest value of the maximum membership function in the
+ fuzzy set. The smallest value is computed while integrating over the
+ fuzzy set. The integration algorithm is the midpoint rectangle method
+ (https://en.wikipedia.org/wiki/Rectangle_method).
+
+ @param term is the fuzzy set
+ @param minimum is the minimum value of the fuzzy set
+ @param maximum is the maximum value of the fuzzy set
+ @return the smallest @f$x@f$-coordinate of the maximum membership
+ function value in the fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual SmallestOfMaximum* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_SMALLESTOFMAXIMUM_H */
+
diff --git a/fuzzylite/fl/defuzzifier/WeightedAverage.h b/fuzzylite/fl/defuzzifier/WeightedAverage.h
new file mode 100644
index 0000000..7f8e9f6
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/WeightedAverage.h
@@ -0,0 +1,71 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_WEIGHTEDAVERAGE_H
+#define FL_WEIGHTEDAVERAGE_H
+
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+
+namespace fl {
+ class Activated;
+
+ /**
+ The WeightedAverage class is a WeightedDefuzzifier that computes the
+ weighted average of a fuzzy set represented in an Aggregated Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see WeightedAverageCustom
+ @see WeightedSum
+ @see WeightedSumCustom
+ @see WeightedDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API WeightedAverage : public WeightedDefuzzifier {
+ public:
+ explicit WeightedAverage(Type type = Automatic);
+ explicit WeightedAverage(const std::string& type);
+ virtual ~WeightedAverage() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(WeightedAverage)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the weighted average of the given fuzzy set represented in
+ an Aggregated term as @f$y = \dfrac{\sum_i w_iz_i}{\sum_i w_i} @f$,
+ where @f$w_i@f$ is the activation degree of term @f$i@f$, and
+ @f$z_i = \mu_i(w_i) @f$.
+
+ From version 6.0, the implication and aggregation operators are not
+ utilized for defuzzification.
+
+ @param term is the fuzzy set represented as an Aggregated Term
+ @param minimum is the minimum value of the range (only used for Tsukamoto)
+ @param maximum is the maximum value of the range (only used for Tsukamoto)
+ @return the weighted average of the given fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual WeightedAverage* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_WEIGHTEDAVERAGE_H */
+
diff --git a/fuzzylite/fl/defuzzifier/WeightedAverageCustom.h b/fuzzylite/fl/defuzzifier/WeightedAverageCustom.h
new file mode 100644
index 0000000..5597f97
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/WeightedAverageCustom.h
@@ -0,0 +1,77 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_WEIGHTEDAVERAGECUSTOM_H
+#define FL_WEIGHTEDAVERAGECUSTOM_H
+
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+
+namespace fl {
+ class Activated;
+
+ /**
+ The (experimental) WeightedAverageCustom class is a WeightedDefuzzifier that computes the
+ weighted average of a fuzzy set represented in an Aggregated Term utilizing
+ the fuzzy operators for implication and aggregation to compute the weighted
+ average. This is an experimental approach to take advantage of customization
+ thanks to the object-oriented design.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see WeightedAverage
+ @see WeightedSum
+ @see WeightedSumCustom
+ @see WeightedDefuzzifier
+ @see Defuzzifier
+ @since 6.0
+ */
+ class FL_API WeightedAverageCustom : public WeightedDefuzzifier {
+ public:
+ explicit WeightedAverageCustom(Type type = Automatic);
+ explicit WeightedAverageCustom(const std::string& type);
+ virtual ~WeightedAverageCustom() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(WeightedAverageCustom)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the weighted average of the given fuzzy set represented as
+ an AggregatedTerm as @f$y = \dfrac{\sum_i w_iz_i}{\sum_i w_i} @f$,
+ where @f$w_i@f$ is the activation degree of term @f$i@f$, and
+ @f$z_i = \mu_i(w_i) @f$.
+
+ If the implication and aggregation operators are set to fl::null (or
+ set to AlgebraicProduct and UnboundedSum, respectively), then the
+ operation of WeightedAverageCustom is the same as the WeightedAverage.
+ Otherwise, the implication and aggregation operators are utilized to
+ compute the multiplications and sums in @f$y@f$, respectively.
+
+ @param term is the fuzzy set represented as an Aggregated Term
+ @param minimum is the minimum value of the range (only used for Tsukamoto)
+ @param maximum is the maximum value of the range (only used for Tsukamoto)
+ @return the weighted average of the given fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual WeightedAverageCustom* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_WEIGHTEDAVERAGECUSTOM_H */
+
diff --git a/fuzzylite/fl/defuzzifier/WeightedDefuzzifier.h b/fuzzylite/fl/defuzzifier/WeightedDefuzzifier.h
new file mode 100644
index 0000000..2045772
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/WeightedDefuzzifier.h
@@ -0,0 +1,90 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_WEIGHTEDDEFUZZIFIER_H
+#define FL_WEIGHTEDDEFUZZIFIER_H
+
+#include "fl/defuzzifier/Defuzzifier.h"
+
+namespace fl {
+ class Activated;
+
+ /**
+ The WeightedDefuzzifier class is the base class for defuzzifiers which
+ compute a weighted function on the fuzzy set without requiring to
+ integrate over the fuzzy set.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 5.0
+ */
+ class FL_API WeightedDefuzzifier : public Defuzzifier {
+ public:
+
+ /**The Type enum indicates the type of the WeightedDefuzzifier based
+ the terms included in the fuzzy set.*/
+ enum Type {
+ /**Automatic: Automatically inferred from the terms */
+ Automatic,
+ /**TakagiSugeno: Manually set to TakagiSugeno (or Inverse Tsukamoto)*/
+ TakagiSugeno,
+ /**Tsukamoto: Manually set to Tsukamoto*/
+ Tsukamoto
+ };
+ /**
+ Returns a string representation of the given type
+ @param type is the type of a defuzzifier
+ @return a string representation of the given type
+ */
+ static std::string typeName(Type type);
+ private:
+ Type _type;
+
+ public:
+ explicit WeightedDefuzzifier(Type type = Automatic);
+ explicit WeightedDefuzzifier(const std::string& type);
+ virtual ~WeightedDefuzzifier() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(WeightedDefuzzifier)
+
+ /**
+ Sets the type of the weighted defuzzifier
+ @param type is the type of the weighted defuzzifier
+ */
+ void setType(Type type);
+ /**
+ Gets the type of the weighted defuzzifier
+ @return the type of the weighted defuzzifier
+ */
+ Type getType() const;
+ /**
+ Returns a string representation of the type of the defuzzifier
+ @return a string representation of the type of the defuzzifier
+ */
+ virtual std::string getTypeName() const;
+ /**
+ Infers the type of the defuzzifier based on the given term. If the
+ given term is Constant, Linear or Function, then the type is
+ TakagiSugeno; otherwise, the type is Tsukamoto
+
+ @param term is the given term
+ @return the inferred type of the defuzzifier based on the given term
+ */
+ virtual Type inferType(const Term* term) const;
+
+ };
+}
+
+#endif /* FL_WEIGHTEDDEFUZZIFIER_H */
+
diff --git a/fuzzylite/fl/defuzzifier/WeightedSum.h b/fuzzylite/fl/defuzzifier/WeightedSum.h
new file mode 100644
index 0000000..fb61ef3
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/WeightedSum.h
@@ -0,0 +1,71 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_WEIGHTEDSUM_H
+#define FL_WEIGHTEDSUM_H
+
+
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The WeightedSum class is a WeightedDefuzzifier that computes the
+ weighted sum of a fuzzy set represented in an Aggregated Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see WeightedSumCustom
+ @see WeightedAverage
+ @see WeightedAverageCustom
+ @see WeightedDefuzzifier
+ @see Defuzzifier
+ @since 4.0
+ */
+ class FL_API WeightedSum : public WeightedDefuzzifier {
+ public:
+ explicit WeightedSum(Type type = Automatic);
+ explicit WeightedSum(const std::string& type);
+ virtual ~WeightedSum() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(WeightedSum)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the weighted sum of the given fuzzy set represented as an
+ Aggregated Term as @f$y = \sum_i{w_iz_i} @f$,
+ where @f$w_i@f$ is the activation degree of term @f$i@f$, and @f$z_i
+ = \mu_i(w_i) @f$.
+
+ From version 6.0, the implication and aggregation operators are not
+ utilized for defuzzification.
+
+ @param term is the fuzzy set represented as an AggregatedTerm
+ @param minimum is the minimum value of the range (only used for Tsukamoto)
+ @param maximum is the maximum value of the range (only used for Tsukamoto)
+ @return the weighted sum of the given fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual WeightedSum* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_WEIGHTEDSUM_H */
+
diff --git a/fuzzylite/fl/defuzzifier/WeightedSumCustom.h b/fuzzylite/fl/defuzzifier/WeightedSumCustom.h
new file mode 100644
index 0000000..c055d1e
--- /dev/null
+++ b/fuzzylite/fl/defuzzifier/WeightedSumCustom.h
@@ -0,0 +1,78 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_WEIGHTEDSUMCUSTOM_H
+#define FL_WEIGHTEDSUMCUSTOM_H
+
+
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The (experimental) WeightedSumCustom class is a WeightedDefuzzifier that computes the
+ weighted sum of a fuzzy set represented in an Aggregated Term utilizing
+ the fuzzy operators for implication and aggregation to compute the weighted
+ sum. This is an experimental approach to take advantage of customization
+ thanks to the object-oriented design.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see WeightedSum
+ @see WeightedAverage
+ @see WeightedAverageCustom
+ @see WeightedDefuzzifier
+ @see Defuzzifier
+ @since 6.0
+ @experimental
+ */
+ class FL_API WeightedSumCustom : public WeightedDefuzzifier {
+ public:
+ explicit WeightedSumCustom(Type type = Automatic);
+ explicit WeightedSumCustom(const std::string& type);
+ virtual ~WeightedSumCustom() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(WeightedSumCustom)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ virtual Complexity complexity(const Term* term) const FL_IOVERRIDE;
+
+ /**
+ Computes the weighted sum of the given fuzzy set represented in an
+ Aggregated Term as @f$y = \sum_i{w_iz_i} @f$,
+ where @f$w_i@f$ is the activation degree of term @f$i@f$, and @f$z_i
+ = \mu_i(w_i) @f$.
+
+ If the implication and aggregation operators are set to fl::null (or
+ set to AlgebraicProduct and UnboundedSum, respectively), then the
+ operation of WeightedAverageCustom is the same as the WeightedAverage.
+ Otherwise, the implication and aggregation operators are utilized to
+ compute the multiplications and sums in @f$y@f$, respectively.
+
+ @param term is the fuzzy set represented as an AggregatedTerm
+ @param minimum is the minimum value of the range (only used for Tsukamoto)
+ @param maximum is the maximum value of the range (only used for Tsukamoto)
+ @return the weighted sum of the given fuzzy set
+ */
+ virtual scalar defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+ virtual WeightedSumCustom* clone() const FL_IOVERRIDE;
+
+ static Defuzzifier* constructor();
+ };
+}
+
+#endif /* FL_WEIGHTEDSUMCUSTOM_H */
+
diff --git a/fuzzylite/fl/factory/ActivationFactory.h b/fuzzylite/fl/factory/ActivationFactory.h
new file mode 100644
index 0000000..6ebfc73
--- /dev/null
+++ b/fuzzylite/fl/factory/ActivationFactory.h
@@ -0,0 +1,46 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ACTIVATIONFACTORY_H
+#define FL_ACTIVATIONFACTORY_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/factory/ConstructionFactory.h"
+#include "fl/activation/Activation.h"
+
+namespace fl {
+
+ /**
+ The ActivationFactory class is a ConstructionFactory of Activation
+ methods for RuleBlock%s.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Activation
+ @see RuleBlock
+ @see ConstructionFactory
+ @see FactoryManager
+ @since 6.0
+ */
+ class FL_API ActivationFactory : public ConstructionFactory<Activation*> {
+ public:
+ ActivationFactory();
+ virtual ~ActivationFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(ActivationFactory)
+ };
+}
+
+#endif /* FL_ACTIVATIONFACTORY_H */
diff --git a/fuzzylite/fl/factory/CloningFactory.h b/fuzzylite/fl/factory/CloningFactory.h
new file mode 100644
index 0000000..a21e1d2
--- /dev/null
+++ b/fuzzylite/fl/factory/CloningFactory.h
@@ -0,0 +1,226 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CLONINGFACTORY_H
+#define FL_CLONINGFACTORY_H
+
+#include "fl/fuzzylite.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ /**
+ The CloningFactory class is the base class for a factory whose objects
+ are created from a registered object by calling the `clone()` method.
+
+ @param <T> is the class of the object to be cloned
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FactoryManager
+ @since 5.0
+ */
+
+ template <typename T>
+ class CloningFactory {
+ private:
+ std::string _name;
+ std::map<std::string, T> _objects;
+
+ public:
+ explicit CloningFactory(const std::string& name = "");
+ CloningFactory(const CloningFactory& other);
+ CloningFactory& operator=(const CloningFactory& other);
+ virtual ~CloningFactory();
+ FL_DEFAULT_MOVE(CloningFactory)
+
+ /**
+ Returns the name of the factory
+ @return the name of the factory
+ */
+ virtual std::string name() const;
+
+ /**
+ Registers the object in the factory and assumes its ownership
+ @param key is the unique name by which objects are registered
+ @param object is the object to be cloned via a `clone` method
+ */
+ virtual void registerObject(const std::string& key, T object);
+ /**
+ Deregisters the given object from the factory and deletes it
+ @param key is the unique name by which objects are registered
+ */
+ virtual void deregisterObject(const std::string& key);
+ /**
+ Checks whether the factory has the given object registered
+ @param key is the unique name by which objects are registered
+ @return whether the factory has the given object registered
+ */
+ virtual bool hasObject(const std::string& key) const;
+ /**
+ Gets the object registered by the given key, not a clone of the object
+ @param key is the unique name by which objects are registered
+ @return the object registered by the given key
+ */
+ virtual T getObject(const std::string& key) const;
+ /**
+ Creates a cloned object by executing the clone method on the registered object
+ @param key is the unique name by which objects are registered
+ @return a cloned object by executing the clone method on the registered object
+ */
+ virtual T cloneObject(const std::string& key) const;
+ /**
+ Returns a vector of the available objects
+ @return a vector of the available objects
+ */
+ virtual std::vector<std::string> available() const;
+ /**
+ Gets the map of registered keys and objects
+ @return the map of registered keys and objects
+ */
+ virtual std::map<std::string, T>& objects();
+ /**
+ Gets an immutable map of registered keys and objects
+ @return an immutable map of registered keys and objects
+ */
+ virtual const std::map<std::string, T>& objects() const;
+
+ };
+}
+
+/**
+ Template implementation
+ */
+
+#include "fl/Exception.h"
+
+namespace fl {
+
+ template<typename T>
+ inline CloningFactory<T>::CloningFactory(const std::string& name) : _name(name) {
+
+ }
+
+ template<typename T>
+ inline CloningFactory<T>::CloningFactory(const CloningFactory& other) {
+ typename std::map<std::string, T>::const_iterator it = other._objects.begin();
+ while (it != other._objects.end()) {
+ T clone = fl::null;
+ if (it->second) clone = it->second->clone();
+ this->_objects[it->first] = clone;
+ ++it;
+ }
+ }
+
+ template<typename T>
+ inline CloningFactory<T>& CloningFactory<T>::operator=(const CloningFactory& other) {
+ if (this != &other) {
+ typename std::map<std::string, T>::const_iterator it = this->_objects.begin();
+ while (it != this->_objects.end()) {
+ if (it->second) delete it->second;
+ ++it;
+ }
+ this->_objects.clear();
+
+ it = other._objects.begin();
+ while (it != other._objects.end()) {
+ T clone = fl::null;
+ if (it->second) clone = it->second->clone();
+ this->_objects[it->first] = clone;
+ ++it;
+ }
+ }
+ return *this;
+ }
+
+ template<typename T>
+ inline CloningFactory<T>::~CloningFactory() {
+ typename std::map<std::string, T>::const_iterator it = this->_objects.begin();
+ while (it != this->_objects.end()) {
+ if (it->second) delete it->second;
+ ++it;
+ }
+ }
+
+ template<typename T>
+ inline std::string CloningFactory<T>::name() const {
+ return this->_name;
+ }
+
+ template<typename T>
+ inline void CloningFactory<T>::registerObject(const std::string& key, T object) {
+ this->_objects[key] = object;
+ }
+
+ template<typename T>
+ inline void CloningFactory<T>::deregisterObject(const std::string& key) {
+ typename std::map<std::string, T>::iterator it = this->_objects.find(key);
+ if (it != this->_objects.end()) {
+ this->_objects.erase(it);
+ delete it->second;
+ }
+ }
+
+ template<typename T>
+ inline bool CloningFactory<T>::hasObject(const std::string& key) const {
+ typename std::map<std::string, T>::const_iterator it = this->_objects.find(key);
+ return (it != this->_objects.end());
+ }
+
+ template<typename T>
+ inline T CloningFactory<T>::getObject(const std::string& key) const {
+ typename std::map<std::string, T>::const_iterator it = this->_objects.find(key);
+ if (it != this->_objects.end()) {
+ if (it->second) return it->second;
+ }
+ return fl::null;
+ }
+
+ template<typename T>
+ inline T CloningFactory<T>::cloneObject(const std::string& key) const {
+ typename std::map<std::string, T>::const_iterator it = this->_objects.find(key);
+ if (it != this->_objects.end()) {
+ if (it->second) return it->second->clone();
+ return fl::null;
+ }
+ throw Exception("[cloning error] " + _name + " object by name <" + key + "> not registered", FL_AT);
+ }
+
+ template<typename T>
+ inline std::vector<std::string> CloningFactory<T>::available() const {
+ std::vector<std::string> result;
+ typename std::map<std::string, T>::const_iterator it = this->_objects.begin();
+ while (it != this->_objects.end()) {
+ result.push_back(it->first);
+ }
+ return result;
+ }
+
+ template<typename T>
+ inline std::map<std::string, T>& CloningFactory<T>::objects() {
+ return this->_objects;
+ }
+
+ template<typename T>
+ inline const std::map<std::string, T>& CloningFactory<T>::objects() const {
+ return this->_objects;
+ }
+}
+
+#endif /* FL_CLONINGFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/ConstructionFactory.h b/fuzzylite/fl/factory/ConstructionFactory.h
new file mode 100644
index 0000000..2558d7f
--- /dev/null
+++ b/fuzzylite/fl/factory/ConstructionFactory.h
@@ -0,0 +1,202 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CONSTRUCTIONFACTORY_H
+#define FL_CONSTRUCTIONFACTORY_H
+
+#include "fl/fuzzylite.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ /**
+ The ConstructionFactory class is the base class for a factory whose
+ objects are created from a registered ConstructionFactory::Constructor.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FactoryManager
+ @since 5.0
+ */
+
+ template <typename T>
+ class ConstructionFactory {
+ public:
+ /**
+ The Constructor type definition refers to a zero-parameter method
+ which returns an instance of T
+ */
+ typedef T(*Constructor)();
+
+ private:
+ std::string _name;
+ std::map<std::string, Constructor> _constructors;
+
+ public:
+ explicit ConstructionFactory(const std::string& name);
+ virtual ~ConstructionFactory();
+ FL_DEFAULT_COPY_AND_MOVE(ConstructionFactory)
+
+ /**
+ Returns the name of the factory
+ @return the name of the factory
+ */
+ virtual std::string name() const;
+
+ /**
+ Registers the constructor in the factory
+ @param key is the unique name by which constructors are registered
+ @param constructor is the pointer to the constructor of the object
+ */
+ virtual void registerConstructor(const std::string& key, Constructor constructor);
+ /**
+ Deregisters from the factory the constructor associated to the given key
+ @param key is the unique name by which constructors are registered
+ */
+ virtual void deregisterConstructor(const std::string& key);
+ /**
+ Checks whether the factory has a constructor registered by the given key
+ @param key is the unique name by which constructors are registered
+ @return whether the factory has the given constructor registered
+ */
+ virtual bool hasConstructor(const std::string& key) const;
+ /**
+ Gets the constructor registered by the given key
+ @param key is the unique name by which constructors are registered
+ @return the pointer to the given constructor
+ */
+ virtual Constructor getConstructor(const std::string& key) const;
+ /**
+ Creates an object by executing the constructor associated to the given key
+ @param key is the unique name by which constructors are registered
+ @return an object by executing the constructor associated to the given key
+ */
+ virtual T constructObject(const std::string& key) const;
+ /**
+ Returns a vector of keys for the constructors available
+ @return a vector of keys for the constructors available
+ */
+ virtual std::vector<std::string> available() const;
+ /**
+ Gets the map of registered keys and constructors
+ @return the map of registered keys and constructors
+ */
+ virtual std::map<std::string, Constructor>& constructors();
+ /**
+ Gets an immutable map of registered keys and constructors
+ @return an immutable map of registered keys and constructors
+ */
+ virtual const std::map<std::string, Constructor>& constructors() const;
+ };
+
+}
+
+/**
+ * Template implementation
+ */
+
+
+#include "fl/Exception.h"
+#include "fl/defuzzifier/Defuzzifier.h"
+#include "fl/hedge/Hedge.h"
+#include "fl/norm/SNorm.h"
+#include "fl/norm/TNorm.h"
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ template <typename T>
+ inline ConstructionFactory<T>::ConstructionFactory(const std::string& name) : _name(name) {
+
+ }
+
+ template <typename T>
+ inline ConstructionFactory<T>::~ConstructionFactory() {
+ }
+
+ template<typename T>
+ inline std::string ConstructionFactory<T>::name() const {
+ return this->_name;
+ }
+
+ template <typename T>
+ inline void ConstructionFactory<T>::registerConstructor(const std::string& key, Constructor constructor) {
+ this->_constructors[key] = constructor;
+ }
+
+ template <typename T>
+ inline void ConstructionFactory<T>::deregisterConstructor(const std::string& key) {
+ typename std::map<std::string, Constructor>::iterator it = this->_constructors.find(key);
+ if (it != this->_constructors.end()) {
+ this->_constructors.erase(it);
+ }
+ }
+
+ template <typename T>
+ inline bool ConstructionFactory<T>::hasConstructor(const std::string& key) const {
+ typename std::map<std::string, Constructor>::const_iterator it = this->_constructors.find(key);
+ return (it != this->_constructors.end());
+ }
+
+ template <typename T>
+ inline typename ConstructionFactory<T>::Constructor ConstructionFactory<T>::getConstructor(const std::string& key) const {
+ typename std::map<std::string, Constructor>::const_iterator it = this->_constructors.find(key);
+ if (it != this->_constructors.end()) {
+ return it->second;
+ }
+ return fl::null;
+ }
+
+ template <typename T>
+ inline T ConstructionFactory<T>::constructObject(const std::string& key) const {
+ typename std::map<std::string, Constructor>::const_iterator it = this->_constructors.find(key);
+ if (it != this->_constructors.end()) {
+ if (it->second) {
+ return it->second();
+ }
+ return fl::null;
+ }
+ std::ostringstream ss;
+ ss << "[factory error] constructor of " + _name + " <" << key << "> not registered";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ template <typename T>
+ inline std::vector<std::string> ConstructionFactory<T>::available() const {
+ std::vector<std::string> result;
+ typename std::map<std::string, Constructor>::const_iterator it = this->_constructors.begin();
+ while (it != this->_constructors.end()) {
+ result.push_back(it->first);
+ ++it;
+ }
+ return result;
+ }
+
+ template<typename T>
+ inline std::map<std::string, typename ConstructionFactory<T>::Constructor>& ConstructionFactory<T>::constructors() {
+ return this->_constructors;
+ }
+
+ template<typename T>
+ inline const std::map<std::string, typename ConstructionFactory<T>::Constructor>& ConstructionFactory<T>::constructors() const {
+ return this->_constructors;
+ }
+}
+
+#endif /* FL_CONSTRUCTIONFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/DefuzzifierFactory.h b/fuzzylite/fl/factory/DefuzzifierFactory.h
new file mode 100644
index 0000000..8fa4c1b
--- /dev/null
+++ b/fuzzylite/fl/factory/DefuzzifierFactory.h
@@ -0,0 +1,75 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_DEFUZZIFIERFACTORY_H
+#define FL_DEFUZZIFIERFACTORY_H
+
+#include "fl/factory/ConstructionFactory.h"
+
+#include "fl/defuzzifier/Defuzzifier.h"
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+
+namespace fl {
+
+ /**
+ The DefuzzifierFactory class is a ConstructionFactory of Defuzzifier%s.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Defuzzifier
+ @see ConstructionFactory
+ @see FactoryManager
+ @since 4.0
+ */
+ class FL_API DefuzzifierFactory : public ConstructionFactory<Defuzzifier*> {
+ public:
+ DefuzzifierFactory();
+ virtual ~DefuzzifierFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(DefuzzifierFactory)
+
+ /**
+ Creates a Defuzzifier by executing the registered constructor
+ @param key is the unique name by which constructors are registered
+ @param resolution is the resolution of an IntegralDefuzzifier
+ @param type is the type of a WeightedDefuzzifier
+ @return a Defuzzifier by executing the registered constructor and
+ setting its resolution or type accordingly
+ */
+ virtual Defuzzifier* constructDefuzzifier(const std::string& key,
+ int resolution, WeightedDefuzzifier::Type type) const;
+
+ /**
+ Creates a Defuzzifier by executing the registered constructor
+ @param key is the unique name by which constructors are registered
+ @param resolution is the resolution of an IntegralDefuzzifier
+ @return a Defuzzifier by executing the registered constructor and
+ setting its resolution
+ */
+ virtual Defuzzifier* constructDefuzzifier(const std::string& key, int resolution) const;
+
+ /**
+ Creates a Defuzzifier by executing the registered constructor
+ @param key is the unique name by which constructors are registered
+ @param type is the type of a WeightedDefuzzifier
+ @return a Defuzzifier by executing the registered constructor and
+ setting its type
+ */
+ virtual Defuzzifier* constructDefuzzifier(const std::string& key, WeightedDefuzzifier::Type type);
+ };
+}
+
+#endif /* DEFUZZIFIERFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/FactoryManager.h b/fuzzylite/fl/factory/FactoryManager.h
new file mode 100644
index 0000000..79f7996
--- /dev/null
+++ b/fuzzylite/fl/factory/FactoryManager.h
@@ -0,0 +1,154 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FACTORYMANAGER_H
+#define FL_FACTORYMANAGER_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/factory/TNormFactory.h"
+#include "fl/factory/SNormFactory.h"
+#include "fl/factory/ActivationFactory.h"
+#include "fl/factory/DefuzzifierFactory.h"
+#include "fl/factory/TermFactory.h"
+#include "fl/factory/HedgeFactory.h"
+#include "fl/factory/FunctionFactory.h"
+
+namespace fl {
+
+ /**
+ The FactoryManager class is a central class grouping different factories
+ of objects, together with a singleton instance to access each of the
+ factories throughout the library.
+
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see TermFactory
+ @see TNormFactory
+ @see SNormFactory
+ @see HedgeFactory
+ @see ActivationFactory
+ @see DefuzzifierFactory
+ @see FunctionFactory
+ @since 4.0
+ */
+ class FL_API FactoryManager {
+ private:
+ FL_unique_ptr<TNormFactory> _tnorm;
+ FL_unique_ptr<SNormFactory> _snorm;
+ FL_unique_ptr<ActivationFactory> _activation;
+ FL_unique_ptr<DefuzzifierFactory> _defuzzifier;
+ FL_unique_ptr<TermFactory> _term;
+ FL_unique_ptr<HedgeFactory> _hedge;
+ FL_unique_ptr<FunctionFactory> _function;
+
+ public:
+ FactoryManager();
+ explicit FactoryManager(TNormFactory* tnorm, SNormFactory* snorm,
+ ActivationFactory* activation, DefuzzifierFactory* defuzzifier,
+ TermFactory* term, HedgeFactory* hedge, FunctionFactory* function);
+ explicit FactoryManager(const FactoryManager& other);
+ FactoryManager& operator=(const FactoryManager& other);
+ FL_DEFAULT_MOVE(FactoryManager)
+ virtual ~FactoryManager();
+
+ /**
+ Gets the static instance of the manager
+ @return the static instance of the manager
+ */
+ static FactoryManager* instance();
+
+ /**
+ Sets the factory of TNorm%s
+ @param tnorm is the factory of TNorm%s
+ */
+ virtual void setTnorm(TNormFactory* tnorm);
+ /**
+ Gets the factory of TNorm%s
+ @return the factory of TNorm%s
+ */
+ virtual TNormFactory* tnorm() const;
+
+ /**
+ Sets the factory of SNorm%s
+ @param snorm is the factory of SNorm%s
+ */
+ virtual void setSnorm(SNormFactory* snorm);
+ /**
+ Gets the factory of SNorm%s
+ @return the factory of SNorm%s
+ */
+ virtual SNormFactory* snorm() const;
+
+ /**
+ Sets the factory of Activation methods
+ @param activation is the factory of Activation methods
+ */
+ virtual void setActivation(ActivationFactory* activation);
+ /**
+ Gets the factory of Activation methods
+ @return the factory of Activation methods
+ */
+ virtual ActivationFactory* activation() const;
+
+ /**
+ Sets the factory of Defuzzifier%s
+ @param defuzzifier is the factory of Defuzzifier%s
+ */
+ virtual void setDefuzzifier(DefuzzifierFactory* defuzzifier);
+ /**
+ Gets the factory of Defuzzifier%s
+ @return the factory of Defuzzifier%s
+ */
+ virtual DefuzzifierFactory* defuzzifier() const;
+
+ /**
+ Sets the factory of Term%s
+ @param term is the factory of Term%s
+ */
+ virtual void setTerm(TermFactory* term);
+ /**
+ Gets the factory of Term%s
+ @return the factory of Term%s
+ */
+ virtual TermFactory* term() const;
+
+ /**
+ Sets the factory of Hedge%s
+ @param hedge is the factory of Hedge%s
+ */
+ virtual void setHedge(HedgeFactory* hedge);
+ /**
+ Gets the factory of Hedge%s
+ @return the factory of Hedge%s
+ */
+ virtual HedgeFactory* hedge() const;
+
+ /**
+ Sets the factory of Function Element%s
+ @param function is the factory of Function Element%s
+ */
+ virtual void setFunction(FunctionFactory* function);
+ /**
+ Gets the factory of Function Element%s
+ @return the factory of Function Element%s
+ */
+ virtual FunctionFactory* function() const;
+ };
+}
+
+#endif /* FL_FACTORYMANAGER_H */
+
diff --git a/fuzzylite/fl/factory/FunctionFactory.h b/fuzzylite/fl/factory/FunctionFactory.h
new file mode 100644
index 0000000..84e0104
--- /dev/null
+++ b/fuzzylite/fl/factory/FunctionFactory.h
@@ -0,0 +1,61 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FUNCTIONFACTORY_H
+#define FL_FUNCTIONFACTORY_H
+
+#include "fl/factory/CloningFactory.h"
+
+#include "fl/term/Function.h"
+
+namespace fl {
+
+ /**
+ The FunctionFactory class is a CloningFactory of operators and functions
+ utilized by the Function term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Function
+ @see Element
+ @see CloningFactory
+ @see FactoryManager
+ @since 5.0
+ */
+ class FL_API FunctionFactory : public CloningFactory<Function::Element*> {
+ private:
+ void registerOperators();
+ void registerFunctions();
+ public:
+ FunctionFactory();
+ virtual ~FunctionFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FunctionFactory)
+
+ /**
+ Returns a vector of the operators available
+ @return a vector of the operators available
+ */
+ virtual std::vector<std::string> availableOperators() const;
+ /**
+ Returns a vector of the functions available
+ @return a vector of the functions available
+ */
+ virtual std::vector<std::string> availableFunctions() const;
+
+ };
+}
+
+#endif /* FL_FUNCTIONFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/HedgeFactory.h b/fuzzylite/fl/factory/HedgeFactory.h
new file mode 100644
index 0000000..e4733b2
--- /dev/null
+++ b/fuzzylite/fl/factory/HedgeFactory.h
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HEDGEFACTORY_H
+#define FL_HEDGEFACTORY_H
+
+#include "fl/factory/ConstructionFactory.h"
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The HedgeFactory class is a ConstructionFactory of Hedge%s.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see ConstructionFactory
+ @see FactoryManager
+ @since 4.0
+ */
+ class FL_API HedgeFactory : public ConstructionFactory<Hedge*> {
+ public:
+ HedgeFactory();
+ virtual ~HedgeFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(HedgeFactory)
+ };
+}
+
+#endif /* FL_HEDGEFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/SNormFactory.h b/fuzzylite/fl/factory/SNormFactory.h
new file mode 100644
index 0000000..111664a
--- /dev/null
+++ b/fuzzylite/fl/factory/SNormFactory.h
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SNORMFACTORY_H
+#define FL_SNORMFACTORY_H
+
+#include "fl/factory/ConstructionFactory.h"
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The SNormFactory class is a ConstructionFactory of SNorm%s.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see SNorm
+ @see ConstructionFactory
+ @see FactoryManager
+ @since 4.0
+ */
+ class FL_API SNormFactory : public ConstructionFactory<SNorm*> {
+ public:
+ SNormFactory();
+ virtual ~SNormFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(SNormFactory)
+ };
+}
+
+#endif /* FL_SNORMFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/TNormFactory.h b/fuzzylite/fl/factory/TNormFactory.h
new file mode 100644
index 0000000..5093fa7
--- /dev/null
+++ b/fuzzylite/fl/factory/TNormFactory.h
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TNORMFACTORY_H
+#define FL_TNORMFACTORY_H
+
+#include "fl/factory/ConstructionFactory.h"
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The TNormFactory class is a ConstructionFactory of TNorm%s.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see TNorm
+ @see ConstructionFactory
+ @see FactoryManager
+ @since 4.0
+ */
+ class FL_API TNormFactory : public ConstructionFactory<TNorm*> {
+ public:
+ TNormFactory();
+ virtual ~TNormFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(TNormFactory)
+ };
+}
+
+#endif /* FL_TNORMFACTORY_H */
+
diff --git a/fuzzylite/fl/factory/TermFactory.h b/fuzzylite/fl/factory/TermFactory.h
new file mode 100644
index 0000000..f6a5d60
--- /dev/null
+++ b/fuzzylite/fl/factory/TermFactory.h
@@ -0,0 +1,45 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TERMFACTORY_H
+#define FL_TERMFACTORY_H
+
+
+#include "fl/factory/ConstructionFactory.h"
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The TermFactory class is a ConstructionFactory of Term%s.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see ConstructionFactory
+ @see FactoryManager
+ @since 4.0
+ */
+ class FL_API TermFactory : public ConstructionFactory<Term*> {
+ public:
+ TermFactory();
+ virtual ~TermFactory() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(TermFactory)
+ };
+}
+
+#endif /* FL_TERMFACTORY_H */
+
diff --git a/fuzzylite/fl/fuzzylite.h b/fuzzylite/fl/fuzzylite.h
new file mode 100644
index 0000000..3cca94b
--- /dev/null
+++ b/fuzzylite/fl/fuzzylite.h
@@ -0,0 +1,427 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FUZZYLITE_H
+#define FL_FUZZYLITE_H
+
+#include <algorithm>
+#include <cmath>
+#include <iostream>
+#include <sstream>
+#include <limits>
+#include <memory>
+#include <cstddef>
+
+#ifndef FL_BUILD_PATH
+#define FL_BUILD_PATH ""
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#define FL_WINDOWS
+#endif
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#define FL_UNIX
+#endif
+
+#ifdef __APPLE__
+#define FL_APPLE
+#ifndef FL_UNIX
+#define FL_UNIX
+#endif
+#endif
+
+#define FL__FILE__ std::string(__FILE__).substr(std::string(FL_BUILD_PATH).size())
+
+#define FL_LOG_PREFIX FL__FILE__ << " (" << __LINE__ << "):"
+
+#define FL_AT FL__FILE__, __LINE__, __FUNCTION__
+
+#define FL_LOG(message) {if (fl::fuzzylite::isLogging()){std::cout << FL_LOG_PREFIX << message << std::endl;}}
+#define FL_LOGP(message) {if (fl::fuzzylite::isLogging()){std::cout << message << std::endl;}}
+
+#define FL_DEBUG_BEGIN if (fl::fuzzylite::isDebugging()){
+#define FL_DEBUG_END }
+
+#define FL_DBG(message) FL_DEBUG_BEGIN\
+ std::cout << FL__FILE__ << "::" << __FUNCTION__ << "[" << __LINE__ << "]:" \
+ << message << std::endl;\
+ FL_DEBUG_END
+
+
+#ifdef FL_WINDOWS
+#include <ciso646> //alternative operator spellings:
+//#define and &&
+//#define or ||
+//#define not !
+//#define bitand &
+//#define bitor |
+
+//@todo: Address warning 4251 by exporting members?
+//http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html
+#ifdef _MSC_VER
+#pragma warning (disable:4251)
+#endif
+
+//fuzzylite as a shared library is exported
+//Applications linking with fuzzylite as a shared library need to import
+
+//fuzzylite as a static library does not export or import
+//Applications linking with fuzzylite as a static library do not import
+
+#if defined(FL_EXPORT_LIBRARY)
+#define FL_API __declspec(dllexport)
+#elif defined(FL_IMPORT_LIBRARY)
+#define FL_API __declspec(dllimport)
+#else
+#define FL_API
+#endif
+
+#else
+#define FL_API
+#endif
+
+/**
+ The fl namespace is the namespace where all the classes of the `fuzzylite`
+ library are contained in.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 4.0
+ */
+namespace fl {
+ /**
+ Represents floating-point values (typedef to float or double).
+ */
+#ifdef FL_USE_FLOAT
+ typedef float scalar;
+#else
+ /**
+ Represents floating-point values as doubles.
+ */
+ typedef double scalar;
+#endif
+
+#define FL_IUNUSED(x) (void) (x)
+
+#ifdef __GNUC__
+#define FL_IUNUSED_DECL __attribute__((unused))
+#else
+#define FL_IUNUSED_DECL
+#endif
+
+ /**
+ Represents the Not-A-Number scalar value
+ */
+ const scalar nan FL_IUNUSED_DECL = std::numeric_limits<scalar>::quiet_NaN();
+ /**
+ Represents the infinity scalar value
+ */
+ const scalar inf FL_IUNUSED_DECL = std::numeric_limits<scalar>::infinity();
+
+#ifdef FL_CPP98
+ //C++98 defines
+
+ //Pointers
+ /**
+ Represents the `C++11` or `C++98` null pointer depending on whether the
+ compilation flag `-DFL_CPP98` is set
+ */
+ const long null = 0L;
+#define FL_unique_ptr std::auto_ptr
+#define FL_move_ptr(x) x
+
+ //Identifiers
+#define FL_IOVERRIDE
+#define FL_IFINAL
+#define FL_IDEFAULT
+#define FL_IDELETE
+#define FL_INOEXCEPT throw()
+#define FL_ITHREAD_LOCAL
+
+ //Constructors
+#define FL_DEFAULT_COPY(Class)
+#define FL_DEFAULT_MOVE(Class)
+#define FL_DEFAULT_COPY_AND_MOVE(Class)
+
+#define FL_DISABLE_COPY(Class) \
+ Class(const Class &);\
+ Class &operator=(const Class &);
+
+#else
+ //C++11 defines
+
+ //Pointers
+ /**
+ Represents the `C++11` or `C++98` null pointer depending on whether the
+ compilation flag `-DFL_CPP98` is set
+ */
+ const std::nullptr_t null = nullptr;
+#define FL_unique_ptr std::unique_ptr
+#define FL_move_ptr(x) std::move(x)
+
+ //Identifiers
+#define FL_IOVERRIDE override
+#define FL_IFINAL final
+#define FL_IDEFAULT = default
+#define FL_IDELETE = delete
+#define FL_INOEXCEPT noexcept
+#define FL_ITHREAD_LOCAL /*thread_local (commented for performance)*/
+
+ //Constructors
+#define FL_DEFAULT_COPY(Class) \
+ Class(const Class&) = default; \
+ Class& operator=(const Class&) = default;
+#define FL_DEFAULT_MOVE(Class) \
+ Class(Class&&) = default; \
+ Class& operator=(Class&&) = default;
+#define FL_DEFAULT_COPY_AND_MOVE(Class) \
+ Class(const Class&) = default; \
+ Class& operator=(const Class&) = default;\
+ Class(Class&&) = default; \
+ Class& operator=(Class&&) = default;
+
+#define FL_DISABLE_COPY(Class) \
+ Class(const Class &) = delete;\
+ Class &operator=(const Class &) = delete;
+
+#endif
+
+}
+
+
+namespace fl {
+
+ /**
+
+ The fuzzylite class contains global settings and information about the
+ library.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @since 4.0
+
+ */
+
+ class FL_API fuzzylite {
+ friend class Operation;
+ private:
+ static int _decimals;
+ static scalar _macheps;
+ static std::ios_base::fmtflags _scalarFormat;
+ static bool _logging;
+ static bool _debugging;
+ public:
+ /**
+ Returns the name of the `fuzzylite` library
+ @return the name of the `fuzzylite` library
+ */
+ static std::string name();
+ /**
+ Returns the version of the `fuzzylite` library
+ @return the version of the `fuzzylite` library
+ */
+ static std::string version();
+ /**
+ Returns the name of the `fuzzylite` library including the version
+ @return the name of the `fuzzylite` library including the version
+ */
+ static std::string library();
+
+ /**
+ Returns the license under which the `fuzzylite` library is released
+ @return the license under which the `fuzzylite` library is released
+ */
+ static std::string license();
+
+ /**
+ Returns the name of the author of the `fuzzylite` library
+ @return "Juan Rada-Vilela, Ph.D."
+ */
+ static std::string author();
+
+ /**
+ Returns the name of the company that owns the `fuzzylite` library
+ @return "FuzzyLite Limited"
+ */
+ static std::string company();
+
+ /**
+ Returns the website of the `fuzzylite` library
+ @return "http://www.fuzzylite.com/"
+ */
+ static std::string website();
+
+ /**
+ Returns the number of decimals utilized when formatting scalar values
+ @return the number of decimals utilized when formatting scalar values
+ (default is 3)
+ */
+ static int decimals();
+
+ /**
+ Sets the number of decimals utilized when formatting scalar values
+ @param decimals is the number of decimals utilized when formatting
+ scalar values
+ */
+ static void setDecimals(int decimals);
+
+ /**
+ Returns the minimum difference at which two floating-point values
+ are considered equivalent
+ @return the minimum difference at which two floating-point values
+ are considered equivalent (default is 1e-6)
+ */
+ static scalar macheps();
+
+ /**
+ Sets the minimum difference at which two floating-point values are
+ considered equivalent
+ @param macheps is the minimum difference at which two floating-point
+ values are considered equivalent (default is 1e-6)
+ */
+ static void setMachEps(scalar macheps);
+
+ /**
+ Sets the default format to be utilized for every fl::scalar passed to
+ Op::str()
+ @param scalarFormat is the format to be utilized for every fl::scalar
+ passed to Op::str()
+ */
+ static void setScalarFormat(std::ios_base::fmtflags scalarFormat);
+
+ /**
+ Gets the default format to be utilized for every fl::scalar passed to
+ Op::str()
+ @return the format to be utilized for every fl::scalar passed to Op::str()
+ */
+ static std::ios_base::fmtflags scalarFormat();
+
+ /**
+ Returns whether the library is logging information via the `FL_LOG`
+ macro
+ @return whether the library is logging information via the `FL_LOG`
+ macro
+ */
+ static bool isLogging();
+
+ /**
+ Sets whether the library is set to log information using the macro
+ `FL_LOG`
+ @param logging indicates whether the library is set to log
+ information via the `FL_LOG` macro
+ */
+ static void setLogging(bool logging);
+
+ /**
+ Indicates whether the library is running in debug mode
+ @return `true` if the library is running in debug mode, and `false`
+ if it is running in release mode
+ */
+ static bool isDebugging();
+
+ /**
+ Sets whether the library is set to run in debug mode
+ @param debugging indicates whether the library is set to run in debug mode
+ */
+ static void setDebugging(bool debugging);
+
+ /**
+ Returns the platform under which the `fuzzylite` library was built
+ @return `Unix` or `Windows`
+ */
+ static std::string platform();
+
+ /**
+ Returns the name of the type of the floating-point variables
+ @return `double` or `float`
+ */
+ static std::string floatingPoint();
+ };
+}
+
+
+namespace fl {
+
+ inline std::string fuzzylite::name() {
+ return "fuzzylite";
+ }
+
+ inline std::string fuzzylite::library() {
+ return name() + " " + version();
+ }
+
+ inline std::string fuzzylite::version() {
+ return "6.0";
+ }
+
+ inline std::string fuzzylite::license() {
+ return "FuzzyLite License";
+ }
+
+ inline std::string fuzzylite::author() {
+ return "Juan Rada-Vilela, Ph.D.";
+ }
+
+ inline std::string fuzzylite::company() {
+ return "FuzzyLite Limited";
+ }
+
+ inline std::string fuzzylite::website() {
+ return "http://www.fuzzylite.com/";
+ }
+
+ inline void fuzzylite::setDebugging(bool debugging) {
+ _debugging = debugging;
+ }
+
+ inline bool fuzzylite::isDebugging() {
+ return _debugging;
+ }
+
+ inline void fuzzylite::setDecimals(int decimals) {
+ _decimals = decimals;
+ }
+
+ inline int fuzzylite::decimals() {
+ return _decimals;
+ }
+
+ inline void fuzzylite::setScalarFormat(std::ios_base::fmtflags scalarFormat) {
+ _scalarFormat = scalarFormat;
+ }
+
+ inline std::ios_base::fmtflags fuzzylite::scalarFormat() {
+ return _scalarFormat;
+ }
+
+ inline void fuzzylite::setMachEps(scalar macheps) {
+ _macheps = macheps;
+ }
+
+ inline scalar fuzzylite::macheps() {
+ return _macheps;
+ }
+
+ inline void fuzzylite::setLogging(bool logging) {
+ _logging = logging;
+ }
+
+ inline bool fuzzylite::isLogging() {
+ return _logging;
+ }
+}
+
+#endif /* FL_FUZZYLITE_H */
+
diff --git a/fuzzylite/fl/hedge/Any.h b/fuzzylite/fl/hedge/Any.h
new file mode 100644
index 0000000..bf71842
--- /dev/null
+++ b/fuzzylite/fl/hedge/Any.h
@@ -0,0 +1,60 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ANY_H
+#define FL_ANY_H
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The Any class is a special Hedge that always returns `1.0`. Its
+ position with respect to the other hedges is last in the ordered set
+ (Not, Seldom, Somewhat, Very, Extremely, Any). The Antecedent of a Rule
+ considers Any to be a syntactically special hedge because it is not
+ followed by a Term (e.g., `if Variable is any then...`). Amongst hedges,
+ only Any has virtual methods to be overriden due to its particular case.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Any : public Hedge {
+ public:
+ Any();
+ virtual ~Any() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Any)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the given value
+ @param x is irrelevant
+ @return `1.0`
+ */
+ virtual scalar hedge(scalar x) const FL_IOVERRIDE;
+ virtual Any* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+
+#endif /* FL_ANY_H */
diff --git a/fuzzylite/fl/hedge/Extremely.h b/fuzzylite/fl/hedge/Extremely.h
new file mode 100644
index 0000000..fbd617a
--- /dev/null
+++ b/fuzzylite/fl/hedge/Extremely.h
@@ -0,0 +1,55 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_EXTREMELY_H
+#define FL_EXTREMELY_H
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The Extremely class is a Hedge located fifth in the ordered set
+ (Not, Seldom, Somewhat, Very, Extremely, Any).
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Extremely FL_IFINAL : public Hedge {
+ public:
+ std::string name() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the membership function value @f$x@f$
+ @param x is a membership function value
+ @return @f$
+ \begin{cases}
+ 2x^2 & \mbox{if $x \le 0.5$} \cr
+ 1-2(1-x)^2 & \mbox{otherwise} \cr
+ \end{cases}@f$
+ */
+ scalar hedge(scalar x) const FL_IOVERRIDE;
+ Extremely* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+
+#endif /* FL_EXTREMELY_H */
diff --git a/fuzzylite/fl/hedge/Hedge.h b/fuzzylite/fl/hedge/Hedge.h
new file mode 100644
index 0000000..9dac17c
--- /dev/null
+++ b/fuzzylite/fl/hedge/Hedge.h
@@ -0,0 +1,77 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HEDGE_H
+#define FL_HEDGE_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+#include <string>
+
+namespace fl {
+
+ /**
+ The Hedge class is the abstract class for hedges. Hedges are utilized
+ within the Antecedent and Consequent of a Rule in order to modify the
+ membership function of a linguistic Term.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Consequent
+ @see Rule
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Hedge {
+ public:
+
+ Hedge() {
+ }
+
+ virtual ~Hedge() {
+ }
+ FL_DEFAULT_COPY_AND_MOVE(Hedge)
+
+ /**
+ Returns the name of the hedge
+ @return the name of the hedge
+ */
+ virtual std::string name() const = 0;
+
+ /**
+ Computes the estimated complexity of applying the hedge
+ @return the estimated complexity of applying the hedge
+ */
+ virtual Complexity complexity() const = 0;
+ /**
+ Computes the hedge for the membership function value @f$x@f$
+ @param x is a membership function value
+ @return the hedge of @f$x@f$
+ */
+ virtual scalar hedge(scalar x) const = 0;
+
+ /**
+ Creates a clone of the hedge
+ @return a clone of the hedge.
+ */
+ virtual Hedge* clone() const = 0;
+
+ };
+}
+
+#endif /* FL_HEDGE_H */
diff --git a/fuzzylite/fl/hedge/HedgeFunction.h b/fuzzylite/fl/hedge/HedgeFunction.h
new file mode 100644
index 0000000..bc8930d
--- /dev/null
+++ b/fuzzylite/fl/hedge/HedgeFunction.h
@@ -0,0 +1,82 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HEDGEFUNCTION_H
+#define FL_HEDGEFUNCTION_H
+
+#include "fl/hedge/Hedge.h"
+
+#include "fl/term/Function.h"
+
+namespace fl {
+
+ /**
+ The HedgeFunction class is a customizable Hedge via Function, which
+ computes any function based on the @f$x@f$ value. This hedge is not
+ registered with the HedgeFactory due to issues configuring the formula
+ within. To register the hedge, a static method with the
+ constructor needs to be manually created and registered. Please, check the
+ file `test/hedge/HedgeFunction.cpp` for further details.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Function
+ @see Hedge
+ @see HedgeFactory
+ @since 6.0
+ */
+
+ class FL_API HedgeFunction FL_IFINAL : public Hedge {
+ private:
+ Function _function;
+ public:
+ explicit HedgeFunction(const std::string& formula = "");
+
+ std::string name() const FL_IOVERRIDE;
+
+ /**
+ Returns the reference to the Function
+ @return the reference to the Function
+ */
+ Function& function();
+
+ /**
+ Loads the function with the given formula
+ @param formula is a valid formula in infix notation
+ */
+ void setFormula(const std::string& formula);
+ /**
+ Returns the formula loaded into the function
+ @return the formula loaded into the function
+ */
+ std::string getFormula() const;
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the membership function value @f$x@f$ utilizing
+ the given function via HedgeFunction::setFormula()
+ @param x is a membership function value
+ @return the evaluation of the function
+ */
+ scalar hedge(scalar x) const FL_IOVERRIDE;
+ HedgeFunction* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+
+#endif /* FL_HEDGEFUNCTION_H */
+
diff --git a/fuzzylite/fl/hedge/Not.h b/fuzzylite/fl/hedge/Not.h
new file mode 100644
index 0000000..e981ac9
--- /dev/null
+++ b/fuzzylite/fl/hedge/Not.h
@@ -0,0 +1,51 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_NOT_H
+#define FL_NOT_H
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The Not class is a Hedge located first in the ordered set
+ (Not, Seldom, Somewhat, Very, Extremely, Any).
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Not FL_IFINAL : public Hedge {
+ public:
+ std::string name() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the membership function value @f$x@f$
+ @param x is a membership function value
+ @return @f$1-x@f$
+ */
+ scalar hedge(scalar x) const FL_IOVERRIDE;
+ Not* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+
+#endif /* FL_NOT_H */
diff --git a/fuzzylite/fl/hedge/Seldom.h b/fuzzylite/fl/hedge/Seldom.h
new file mode 100644
index 0000000..0bbedbf
--- /dev/null
+++ b/fuzzylite/fl/hedge/Seldom.h
@@ -0,0 +1,56 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SELDOM_H
+#define FL_SELDOM_H
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The Seldom class is a Hedge located second in the ordered set
+ (Not, Seldom, Somewhat, Very, Extremely, Any).
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Seldom FL_IFINAL : public Hedge {
+ public:
+ std::string name() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the membership function value @f$x@f$
+ @param x is a membership function value
+ @return @f$
+ \begin{cases}
+ \sqrt{0.5x} & \mbox{if $x \le 0.5$} \cr
+ 1-\sqrt{0.5(1-x)} & \mbox{otherwise}\cr
+ \end{cases}
+ @f$
+ */
+ scalar hedge(scalar x) const FL_IOVERRIDE;
+ Seldom* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+
+#endif /* FL_SELDOM_H */
diff --git a/fuzzylite/fl/hedge/Somewhat.h b/fuzzylite/fl/hedge/Somewhat.h
new file mode 100644
index 0000000..ccd21ec
--- /dev/null
+++ b/fuzzylite/fl/hedge/Somewhat.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SOMEWHAT_H
+#define FL_SOMEWHAT_H
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The Somewhat class is a Hedge located third in the ordered set
+ (Not, Seldom, Somewhat, Very, Extremely, Any).
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Somewhat FL_IFINAL : public Hedge {
+ public:
+ std::string name() const FL_IOVERRIDE;
+
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the membership function value @f$x@f$
+ @param x is a membership function value
+ @return @f$\sqrt{x}@f$
+ */
+ scalar hedge(scalar x) const FL_IOVERRIDE;
+ Somewhat* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+
+#endif /* FL_SOMEWHAT_H */
diff --git a/fuzzylite/fl/hedge/Very.h b/fuzzylite/fl/hedge/Very.h
new file mode 100644
index 0000000..b80c994
--- /dev/null
+++ b/fuzzylite/fl/hedge/Very.h
@@ -0,0 +1,50 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_VERY_H
+#define FL_VERY_H
+
+#include "fl/hedge/Hedge.h"
+
+namespace fl {
+
+ /**
+ The Very class is a Hedge located fourth in the ordered set
+ (Not, Seldom, Somewhat, Very, Extremely, Any).
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Hedge
+ @see HedgeFactory
+ @since 4.0
+ */
+ class FL_API Very FL_IFINAL : public Hedge {
+ public:
+ std::string name() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the hedge for the membership function value @f$x@f$
+ @param x is a membership function value
+ @return @f$x^2@f$
+ */
+ scalar hedge(scalar x) const FL_IOVERRIDE;
+ Very* clone() const FL_IOVERRIDE;
+
+ static Hedge* constructor();
+ };
+}
+#endif /* FL_VERY_H */
diff --git a/fuzzylite/fl/imex/CppExporter.h b/fuzzylite/fl/imex/CppExporter.h
new file mode 100644
index 0000000..1c48225
--- /dev/null
+++ b/fuzzylite/fl/imex/CppExporter.h
@@ -0,0 +1,161 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CPPEXPORTER_H
+#define FL_CPPEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+
+namespace fl {
+ class Engine;
+ class InputVariable;
+ class OutputVariable;
+ class Term;
+ class RuleBlock;
+ class Norm;
+ class Defuzzifier;
+ class Hedge;
+ class Activation;
+
+ /**
+ The CppExporter class is an Exporter that translates an Engine and its
+ components to the `C++` programming language using the `fuzzylite`
+ library.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see JavaExporter
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API CppExporter : public Exporter {
+ private:
+ bool _usingNamespace;
+ bool _usingVariableNames;
+ public:
+ explicit CppExporter(bool usingNamespace = false, bool usingVariableNames = true);
+ virtual ~CppExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(CppExporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+
+ /**
+ Sets whether the fl namespace of the library is prepended to types
+ (e.g., fl::Engine)
+
+ @param usingNamespace whether the fl namespace of the library is
+ prepended to types (e.g., fl::Engine)
+ */
+ virtual void setUsingNamespace(bool usingNamespace);
+ /**
+ Gets whether the fl namespace of the library is prepended to types
+ (e.g., fl::Engine)
+ @return whether the fl namespace of the library is prepended to types
+ */
+ virtual bool isUsingNamespace() const;
+
+ /**
+ Returns the given text prepended with the `fl` namespace if
+ CppExporter::isUsingNamespace is `true`, or the text otherwise
+
+ @param clazz is the text to be prepended the `fl::`.
+ @return the given text prepended with the `fl` namespace if
+ CppExporter::isUsingNamespace is `true`, or the text otherwise
+ */
+ virtual std::string fl(const std::string& clazz) const;
+ /**
+ Sets whether variables are exported using their names
+ (e.g., `power->setValue(fl::nan)`) instead of numbered identifiers
+ (e.g., `inputVariable1->setValue(fl::nan)`)
+ @param usingVariableNames indicates whether variables are exported using
+ their names
+ */
+ virtual void setUsingVariableNames(bool usingVariableNames);
+ /**
+ Gets whether variables are exported using their names
+ (e.g., `power->setValue(fl::nan)`) instead of numbered identifiers
+ (e.g., `inputVariable1->setValue(fl::nan)`)
+ @return whether variables are exported using their names
+ */
+ virtual bool isUsingVariableNames() const;
+
+ /**
+ Returns a string representation of InputVariable in the `C++` programming language
+ @param inputVariable is the input variable
+ @param engine is the engine in which the input variable is registered
+ @return a string representation of the input variable in the `C++` programming language
+ */
+ virtual std::string toString(const InputVariable* inputVariable, const Engine* engine) const;
+ /**
+ Returns a string representation of the OutputVariable in the `C++` programming language
+ @param outputVariable is the output variable
+ @param engine is the engine in which the output variable is registered
+ @return a string representation of the output variable in the `C++` programming language
+ */
+ virtual std::string toString(const OutputVariable* outputVariable, const Engine* engine) const;
+ /**
+ Returns a string representation of the RuleBlock in the `C++` programming language
+ @param ruleBlock is the rule block
+ @param engine is the engine in which the rule block is registered
+ @return a string representation of the rule block in the `C++` programming language
+ */
+ virtual std::string toString(const RuleBlock* ruleBlock, const Engine* engine) const;
+
+ /**
+ Returns a string representation of the Activation method in the `C++` programming language
+ @param activation is the activation method
+ @return a string representation of the activation method in the `C++` programming language
+ */
+ virtual std::string toString(const Activation* activation) const;
+
+ /**
+ Returns a string representation of the scalar value in the `C++` programming language
+ @param value is the scalar value
+ @return a string representation of the scalar value in the `C++` programming language
+ */
+ virtual std::string toString(scalar value) const;
+
+ /**
+ Returns a string representation of the Hedge in the `C++` programming language
+ @param hedge is the hedge
+ @return a string representation of the hedge in the `C++` programming language
+ */
+ virtual std::string toString(const Hedge* hedge) const;
+ /**
+ Returns a string representation of the Term in the `C++` programming language
+ @param term is the term
+ @return a string representation of the term in the `C++` programming language
+ */
+ virtual std::string toString(const Term* term) const;
+ /**
+ Returns a string representation of the Norm in the `C++` programming language
+ @param norm is the norm
+ @return a string representation of the norm in the `C++` programming language
+ */
+ virtual std::string toString(const Norm* norm) const;
+ /**
+ Returns a string representation of the Defuzzifier in the `C++` programming language
+ @param defuzzifier is the defuzzifier
+ @return a string representation of the defuzzifier in the `C++` programming language
+ */
+ virtual std::string toString(const Defuzzifier* defuzzifier) const;
+
+ virtual CppExporter* clone() const FL_IOVERRIDE;
+
+ };
+}
+#endif /* FL_CPPEXPORTER_H */
+
diff --git a/fuzzylite/fl/imex/Exporter.h b/fuzzylite/fl/imex/Exporter.h
new file mode 100644
index 0000000..b883edf
--- /dev/null
+++ b/fuzzylite/fl/imex/Exporter.h
@@ -0,0 +1,74 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_EXPORTER_H
+#define FL_EXPORTER_H
+
+#include "fl/fuzzylite.h"
+
+#include <string>
+
+namespace fl {
+ class Engine;
+
+ /**
+ The Exporter class is the abstract class for exporters to translate an
+ Engine into different formats.
+
+ @todo declare methods for exporting other components (e.g., Variable)
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Importer
+ @since 4.0
+ */
+ class FL_API Exporter {
+ public:
+
+ Exporter();
+ virtual ~Exporter();
+ FL_DEFAULT_COPY_AND_MOVE(Exporter)
+
+ /**
+ Returns a string representation of the engine
+ @param engine is the engine to export
+ @return a string representation of the engine
+ */
+ virtual std::string toString(const Engine* engine) const = 0;
+ /**
+ Stores the string representation of the engine into the specified file
+ @param path is the full path of the file to export the engine to
+ @param engine is the engine to export
+ @throws fl::Exception if the file cannot be created
+ */
+ virtual void toFile(const std::string& path, const Engine* engine) const;
+
+ /**
+ Returns the name of the exporter
+ @return the name of the exporter
+ */
+ virtual std::string name() const = 0;
+
+ /**
+ Creates a clone of the exporter
+ @return a clone of the exporter
+ */
+ virtual Exporter* clone() const = 0;
+ };
+
+}
+
+#endif /* FL_EXPORTER_H */
+
diff --git a/fuzzylite/fl/imex/FclExporter.h b/fuzzylite/fl/imex/FclExporter.h
new file mode 100644
index 0000000..efec3c4
--- /dev/null
+++ b/fuzzylite/fl/imex/FclExporter.h
@@ -0,0 +1,105 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FCLEXPORTER_H
+#define FL_FCLEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+
+namespace fl {
+ class InputVariable;
+ class OutputVariable;
+ class RuleBlock;
+ class Norm;
+ class TNorm;
+ class SNorm;
+ class Defuzzifier;
+ class Term;
+
+ /**
+ The FclExporter class is an Exporter that translates an Engine and its
+ components to the Fuzzy Control Language specification.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FclImporter
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API FclExporter : public Exporter {
+ private:
+ std::string _indent;
+
+ public:
+ explicit FclExporter(const std::string& indent = " ");
+ virtual ~FclExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FclExporter)
+
+ /**
+ Sets the indentation string within blocks
+ @param indent is the indentation string within blocks
+ */
+ virtual void setIndent(const std::string& indent);
+ /**
+ Gets the indentation string within blocks
+ @return the indentation string within blocks
+ */
+ virtual std::string getIndent() const;
+
+ virtual std::string name() const FL_IOVERRIDE;
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+
+ /**
+ Returns a string representation of the InputVariable according to the Fuzzy Control Language specification
+ @param variable is the input variable
+ @return a string representation of the input variable according to the Fuzzy Control Language specification
+ */
+ virtual std::string toString(const InputVariable* variable) const;
+ /**
+ Returns a string representation of the OutputVariable according to the Fuzzy Control Language specification
+ @param variable is the output variable
+ @return a string representation of the output variable according to the Fuzzy Control Language specification
+ */
+ virtual std::string toString(const OutputVariable* variable) const;
+ /**
+ Returns a string representation of the RuleBlock according to the Fuzzy Control Language specification
+ @param ruleBlock is the rule block
+ @return a string representation of the rule block according to the Fuzzy Control Language specification
+ */
+ virtual std::string toString(const RuleBlock* ruleBlock) const;
+ /**
+ Returns a string representation of the Norm according to the Fuzzy Control Language specification
+ @param norm is the norm
+ @return a string representation of the norm according to the Fuzzy Control Language specification
+ */
+ virtual std::string toString(const Norm* norm) const;
+ /**
+ Returns a string representation of the Defuzzifier according to the Fuzzy Control Language specification
+ @param defuzzifier is the defuzzifier
+ @return a string representation of the defuzzifier according to the Fuzzy Control Language specification
+ */
+ virtual std::string toString(const Defuzzifier* defuzzifier) const;
+ /**
+ Returns a string representation of the Term according to the Fuzzy Control Language specification
+ @param term is the term
+ @return a string representation of the term according to the Fuzzy Control Language specification
+ */
+ virtual std::string toString(const Term* term) const;
+
+ virtual FclExporter* clone() const FL_IOVERRIDE;
+ };
+}
+
+#endif /* FL_FCLEXPORTER_H */
diff --git a/fuzzylite/fl/imex/FclImporter.h b/fuzzylite/fl/imex/FclImporter.h
new file mode 100644
index 0000000..2e75432
--- /dev/null
+++ b/fuzzylite/fl/imex/FclImporter.h
@@ -0,0 +1,74 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FCLIMPORTER_H
+#define FL_FCLIMPORTER_H
+
+#include "fl/imex/Importer.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+
+namespace fl {
+ class Norm;
+ class TNorm;
+ class SNorm;
+ class Term;
+ class Defuzzifier;
+
+ /**
+ The FclImporter class is an Importer that configures an Engine and its
+ components utilizing the Fuzzy Control Language specification.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FclExporter
+ @see Importer
+ @since 4.0
+ */
+ class FL_API FclImporter : public Importer {
+ public:
+ FclImporter();
+ virtual ~FclImporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FclImporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+ virtual Engine* fromString(const std::string& fcl) const FL_IOVERRIDE;
+
+ virtual FclImporter* clone() const FL_IOVERRIDE;
+
+ protected:
+ virtual void processBlock(const std::string& tag, const std::string& block, Engine* engine) const;
+ virtual void processVar(const std::string& var, const std::string& block, Engine* engine)const;
+ virtual void processFuzzify(const std::string& block, Engine* engine)const;
+ virtual void processDefuzzify(const std::string& block, Engine* engine)const;
+ virtual void processRuleBlock(const std::string& block, Engine* engine)const;
+
+ virtual TNorm* parseTNorm(const std::string& line) const;
+ virtual SNorm* parseSNorm(const std::string& line) const;
+ virtual Term* parseTerm(const std::string& line, const Engine* engine) const;
+
+ virtual Defuzzifier* parseDefuzzifier(const std::string& line) const;
+ virtual std::pair<scalar, bool> parseDefaultValue(const std::string& line) const;
+ virtual std::pair<scalar, scalar> parseRange(const std::string& line) const;
+ virtual std::pair<bool, bool> parseLocks(const std::string& line) const;
+ virtual bool parseEnabled(const std::string& line) const;
+
+ };
+}
+#endif /* FL_FCLIMPORTER_H */
diff --git a/fuzzylite/fl/imex/FisExporter.h b/fuzzylite/fl/imex/FisExporter.h
new file mode 100644
index 0000000..a7f5d8c
--- /dev/null
+++ b/fuzzylite/fl/imex/FisExporter.h
@@ -0,0 +1,121 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FISEXPORTER_H
+#define FL_FISEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+
+#include <vector>
+
+namespace fl {
+ class Norm;
+ class TNorm;
+ class SNorm;
+ class Defuzzifier;
+ class Term;
+ class Rule;
+ class Proposition;
+ class Variable;
+
+ /**
+ The FisExporter class is an Exporter that translates an Engine and its
+ components into the Fuzzy Inference System format for Matlab or Octave.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FisImporter
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API FisExporter : public Exporter {
+ protected:
+
+ virtual std::string translate(const std::vector<Proposition*>& propositions,
+ const std::vector<Variable*> variables) const;
+
+ public:
+ FisExporter();
+ virtual ~FisExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FisExporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+
+ /**
+ Returns a string representation of the TNorm in the Fuzzy Inference System format
+ @param tnorm is the TNorm
+ @return a string representation of the TNorm in the Fuzzy Inference System format
+ */
+ virtual std::string toString(const TNorm* tnorm) const;
+
+ /**
+ Returns a string representation of the SNorm in the Fuzzy Inference System format
+ @param snorm is the SNorm
+ @return a string representation of the SNorm in the Fuzzy Inference System format
+ */
+ virtual std::string toString(const SNorm* snorm) const;
+
+ /**
+ Returns a string representation of the Defuzzifier in the Fuzzy Inference System format
+ @param defuzzifier is the defuzzifier
+ @return a string representation of the Defuzzifier in the Fuzzy Inference System format
+ */
+ virtual std::string toString(const Defuzzifier* defuzzifier) const;
+ /**
+ Returns a string representation of the Term in the Fuzzy Inference System format
+ @param term is the term
+ @return a string representation of the term in the Fuzzy Inference System format
+ */
+ virtual std::string toString(const Term* term) const;
+
+ /**
+ Returns a string representation of the `[System]` configuration
+ @param engine is the engine
+ @return a string representation of the `[System]` configuration
+ */
+ virtual std::string exportSystem(const Engine* engine) const;
+ /**
+ Returns a string representation of the `[Input]` configuration
+ @param engine is the engine
+ @return a string representation of the `[Input]` configuration
+ */
+ virtual std::string exportInputs(const Engine* engine) const;
+ /**
+ Returns a string representation of the `[Output]` configuration
+ @param engine is the engine
+ @return a string representation of the `[Output]` configuration
+ */
+ virtual std::string exportOutputs(const Engine* engine) const;
+ /**
+ Returns a string representation of the `[Rules]` configuration
+ @param engine is the engine
+ @return a string representation of the `[Rules]` configuration
+ */
+ virtual std::string exportRules(const Engine* engine) const;
+ /**
+ Returns a string representation for the Rule in the Fuzzy Inference System format
+ @param rule is the rule
+ @param engine is the engine in which the rule is registered
+ @return a string representation for the rule in the Fuzzy Inference System format
+ */
+ virtual std::string exportRule(const Rule* rule, const Engine* engine) const;
+
+ virtual FisExporter* clone() const FL_IOVERRIDE;
+ };
+}
+
+#endif /* FL_FISEXPORTER_H */
+
diff --git a/fuzzylite/fl/imex/FisImporter.h b/fuzzylite/fl/imex/FisImporter.h
new file mode 100644
index 0000000..2c9ce36
--- /dev/null
+++ b/fuzzylite/fl/imex/FisImporter.h
@@ -0,0 +1,80 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FISIMPORTER_H
+#define FL_FISIMPORTER_H
+
+#include "fl/imex/Importer.h"
+
+#include <utility>
+#include <vector>
+
+
+namespace fl {
+ class Norm;
+ class TNorm;
+ class SNorm;
+ class Term;
+ class Defuzzifier;
+ class Variable;
+
+ /**
+ The FisImporter class is an Importer that configures an Engine and its
+ components from utilizing the Fuzzy Inference System format for Matlab or
+ Octave.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FisExporter
+ @see Importer
+ @since 4.0
+ */
+ class FL_API FisImporter : public Importer {
+ public:
+ FisImporter();
+ virtual ~FisImporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FisImporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+ virtual Engine* fromString(const std::string& fcl) const FL_IOVERRIDE;
+
+ virtual FisImporter* clone() const FL_IOVERRIDE;
+
+ protected:
+ virtual void importSystem(const std::string& section, Engine* engine,
+ std::string& andMethod, std::string& orMethod,
+ std::string& impMethod, std::string& aggMethod,
+ std::string& defuzzMethod) const;
+ virtual void importInput(const std::string& section, Engine* engine) const;
+ virtual void importOutput(const std::string& section, Engine* engine) const;
+ virtual void importRules(const std::string& section, Engine* engine) const;
+ virtual std::string translateProposition(scalar code, Variable* variable) const;
+
+ virtual std::string translateTNorm(const std::string& tnorm) const;
+ virtual std::string translateSNorm(const std::string& tnorm) const;
+ virtual std::string translateDefuzzifier(const std::string& defuzzifier) const;
+
+ virtual Term* parseTerm(const std::string& line, const Engine* engine) const;
+ virtual Term* createInstance(const std::string& termClass, const std::string& name,
+ const std::vector<std::string>& params, const Engine* engine) const;
+
+ virtual std::pair<scalar, scalar> parseRange(const std::string& range) const;
+
+ };
+}
+
+#endif /* FL_FISIMPORTER_H */
+
diff --git a/fuzzylite/fl/imex/FldExporter.h b/fuzzylite/fl/imex/FldExporter.h
new file mode 100644
index 0000000..98a14c9
--- /dev/null
+++ b/fuzzylite/fl/imex/FldExporter.h
@@ -0,0 +1,248 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FLDEXPORTER_H
+#define FL_FLDEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+
+#include <vector>
+
+namespace fl {
+ class Engine;
+ class InputVariable;
+ class OutputVariable;
+
+ /**
+ The FldExporter class is an Exporter that evaluates an Engine and exports
+ its input values and output values to the FuzzyLite Dataset (FLD) format,
+ see [http://www.fuzzylite.com/fll-fld](http://www.fuzzylite.com/fll-fld)
+ for more information.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FllExporter
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API FldExporter : public Exporter {
+ private:
+ std::string _separator;
+ bool _exportHeaders;
+ bool _exportInputValues;
+ bool _exportOutputValues;
+ public:
+
+ /**
+ The ScopeOfValues refers to the scope of the equally-distributed values
+ to generate.
+ */
+ enum ScopeOfValues {
+ /**Generates @f$n@f$ values for each variable*/
+ EachVariable,
+ /**Generates @f$n@f$ values for all variables*/
+ AllVariables
+ };
+ explicit FldExporter(const std::string& separator = " ");
+ virtual ~FldExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FldExporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+ /**
+ Sets the separator of the dataset columns
+ @param separator is the separator of the dataset columns
+ */
+ virtual void setSeparator(const std::string& separator);
+ /**
+ Gets the separator of the dataset columns
+ @return the separator of the dataset columns
+ */
+ virtual std::string getSeparator() const;
+
+ /**
+ Sets whether the header of the dataset is to be exported
+ @param exportHeaders indicates whether the header of the dataset is
+ to be exported
+ */
+ virtual void setExportHeader(bool exportHeaders);
+ /**
+ Gets whether the header of the dataset is to be exported
+ @return whether the header of the dataset is to be exported
+ */
+ virtual bool exportsHeader() const;
+
+ /**
+ Sets whether the values of the input variables are to be exported
+ @param exportInputValues indicates whether the values of the input
+ variables are to be exported
+ */
+ virtual void setExportInputValues(bool exportInputValues);
+ /**
+ Gets whether the values of the input variables are to be exported
+ @return whether the values of the input variables are to be exported
+ */
+ virtual bool exportsInputValues() const;
+
+ /**
+ Sets whether the values of the output variables are to be exported
+ @param exportOutputValues indicates whether the values of the output
+ variables are to be exported
+ */
+ virtual void setExportOutputValues(bool exportOutputValues);
+ /**
+ Gets whether the values of the output variables are to be exported
+ @return whether the values of the output variables are to be exported
+ */
+ virtual bool exportsOutputValues() const;
+
+ /**
+ Gets the header of the dataset for the given engine
+ @param engine is the engine to be exported
+ @return the header of the dataset for the given engine
+ */
+ virtual std::string header(const Engine* engine) const;
+
+ /**
+ Returns a FuzzyLite Dataset from the engine. Please consider that the
+ engine will be `const_cast`ed to achieve so; that is, despite being
+ marked as `const`, the engine will be modified in order to compute
+ the output values based on the input values.
+ @param engine is the engine to export
+ @return a FuzzyLite Dataset from the engine
+ */
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+ /**
+ Returns a FuzzyLite Dataset from the engine.
+ @param engine is the engine to export
+ @param values is the number of values to export
+ @param scope indicates the scope of the values
+ @return a FuzzyLite Dataset from the engine
+ */
+ virtual std::string toString(Engine* engine, int values, ScopeOfValues scope = AllVariables) const;
+
+ /**
+ Returns a FuzzyLite Dataset from the engine.
+ @param engine is the engine to export
+ @param values is the number of values to export
+ @param scope indicates the scope of the values
+ @param activeVariables contains the input variables to generate values for.
+ The input variables must be in the same order as in the engine. A value of
+ fl::null indicates the variable is not active.
+ @return a FuzzyLite Dataset from the engine
+ */
+ virtual std::string toString(Engine* engine, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const;
+ /**
+ Returns a FuzzyLite Dataset from the engine.
+ @param engine is the engine to export
+ @param reader is the reader of a set of lines containing space-separated
+ input values
+ @return a FuzzyLite Dataset from the engine
+ */
+ virtual std::string toString(Engine* engine, std::istream& reader) const;
+
+
+ using Exporter::toFile;
+ /**
+ Saves the engine as a FuzzyLite Dataset into the specified file
+ @param path is the full path of the file
+ @param engine is the engine to export
+ @param values is the number of values to export
+ @param scope indicates the scope of the values
+ */
+ virtual void toFile(const std::string& path, Engine* engine,
+ int values, ScopeOfValues scope = AllVariables) const;
+ /**
+ Saves the engine as a FuzzyLite Dataset into the specified file
+ @param path is the full path of the file
+ @param engine is the engine to export
+ @param values is the number of values to export
+ @param scope indicates the scope of the values
+ @param activeVariables contains the input variables to generate values for.
+ The input variables must be in the same order as in the engine. A value of
+ fl::null indicates the variable is not active.
+ */
+ virtual void toFile(const std::string& path, Engine* engine,
+ int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const;
+ /**
+ Saves the engine as a FuzzyLite Dataset into the specified file
+ @param path is the full path of the file
+ @param engine is the engine to export
+ @param reader is the reader of a set of lines containing space-separated input values
+ */
+ virtual void toFile(const std::string& path, Engine* engine, std::istream& reader) const;
+
+ /**
+ Parses the string into a vector of values unless the string starts with `#`
+ @param values is a space-separated set of values
+ @return a vector of values
+ */
+ virtual std::vector<scalar> parse(const std::string& values) const;
+
+ /**
+ Writes the engine into the given writer
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param values is the number of values to export
+ @param scope indicates the scope of the values
+ */
+ virtual void write(Engine* engine, std::ostream& writer, int values,
+ ScopeOfValues scope = AllVariables) const;
+ /**
+ Writes the engine into the given writer
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param values is the number of values to export
+ @param scope indicates the scope of the values
+ @param activeVariables contains the input variables to generate values for.
+ The input variables must be in the same order as in the engine. A value of
+ fl::null indicates the variable is not active.
+ */
+ virtual void write(Engine* engine, std::ostream& writer, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const;
+ /**
+ Writes the engine into the given writer
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param reader is the reader of a set of lines containing space-separated input values
+ */
+ virtual void write(Engine* engine, std::ostream& writer, std::istream& reader) const;
+ /**
+ Writes the engine into the given writer
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param inputValues is the vector of input values
+ */
+ virtual void write(Engine* engine, std::ostream& writer, const std::vector<scalar>& inputValues) const;
+ /**
+ Writes the engine into the given writer
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param inputValues is the vector of input values
+ @param activeVariables contains the input variables to generate values for.
+ The input variables must be in the same order as in the engine. A value of
+ fl::null indicates the variable is not active.
+ */
+ virtual void write(Engine* engine, std::ostream& writer, const std::vector<scalar>& inputValues,
+ const std::vector<InputVariable*>& activeVariables) const;
+
+ virtual FldExporter* clone() const FL_IOVERRIDE;
+ };
+}
+
+#endif /* FL_FLDEXPORTER_H */
+
diff --git a/fuzzylite/fl/imex/FllExporter.h b/fuzzylite/fl/imex/FllExporter.h
new file mode 100644
index 0000000..5a222e4
--- /dev/null
+++ b/fuzzylite/fl/imex/FllExporter.h
@@ -0,0 +1,168 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FLLEXPORTER_H
+#define FL_FLLEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+
+#include <vector>
+
+namespace fl {
+ class Variable;
+ class InputVariable;
+ class OutputVariable;
+ class RuleBlock;
+ class Rule;
+ class Norm;
+ class Activation;
+ class Defuzzifier;
+ class Term;
+
+ /**
+ The FllExporter class is an Exporter that translates an Engine and its
+ components to the FuzzyLite Language (FLL), see
+ [http://www.fuzzylite.com/fll-fld](http://www.fuzzylite.com/fll-fld) for
+ more information.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FllImporter
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API FllExporter : public Exporter {
+ private:
+ std::string _indent;
+ std::string _separator;
+ public:
+ explicit FllExporter(const std::string& indent = " ", const std::string& separator = "\n");
+ virtual ~FllExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FllExporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+ /**
+ Sets the indent string of the FuzzyLite Language
+ @param indent is the indent string of the FuzzyLite Language
+ */
+ virtual void setIndent(const std::string& indent);
+ /**
+ Gets the indent string of the FuzzyLite Language
+ @return the indent string of the FuzzyLite Language
+ */
+ virtual std::string getIndent() const;
+
+ /**
+ Gets the separator of the FuzzyLite Language
+ @param separator of the FuzzyLite Language
+ */
+ virtual void setSeparator(const std::string& separator);
+ /**
+ Gets the separator of the FuzzyLite Language
+ @return the separator of the FuzzyLite Language
+ */
+ virtual std::string getSeparator() const;
+
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+
+ /**
+ Returns a string representation of the vector of variables in the FuzzyLite Language
+ @param variables is the vector of variables
+ @return a string representation of the vector of variables in the FuzzyLite Language
+ */
+ virtual std::string toString(const std::vector<Variable*>& variables) const;
+ /**
+ Returns a string representation of the vector of input variables in the FuzzyLite Language
+ @param inputVariables is the vector of input variables
+ @return a string representation of the vector of input variables in the FuzzyLite Language
+ */
+ virtual std::string toString(const std::vector<InputVariable*>& inputVariables) const;
+ /**
+ Returns a string representation of the vector of output variables in the FuzzyLite Language
+ @param outputVariables is a vector of output variables
+ @return a string representation of the vector of output variables in the FuzzyLite Language
+ */
+ virtual std::string toString(const std::vector<OutputVariable*>& outputVariables) const;
+ /**
+ Returns a string representation of the vector of rule blocks in the FuzzyLite Language
+ @param ruleBlocks is the vector of rule blocks
+ @return a string representation of the vector of rule blocks in the FuzzyLite Language
+ */
+ virtual std::string toString(const std::vector<RuleBlock*>& ruleBlocks) const;
+
+ /**
+ Returns a string representation of the Variable in the FuzzyLite Language
+ @param variable is the variable
+ @return a string representation of the variable in the FuzzyLite Language
+ */
+ virtual std::string toString(const Variable* variable) const;
+ /**
+ Returns a string representation of the InputVariable in the FuzzyLite Language
+ @param inputVariable is the input variable to export
+ @return a string representation of the input variable in the FuzzyLite Language
+ */
+ virtual std::string toString(const InputVariable* inputVariable) const;
+ /**
+ Returns a string representation of the OutputVariable in the FuzzyLite Language
+ @param outputVariable is the output variable
+ @return a string representation of the output variable in the FuzzyLite Language
+ */
+ virtual std::string toString(const OutputVariable* outputVariable) const;
+
+ /**
+ Returns a string representation of the RuleBlock in the FuzzyLite Language
+ @param ruleBlock is the rule block
+ @return a string representation of the rule block in the FuzzyLite Language
+ */
+ virtual std::string toString(const RuleBlock* ruleBlock) const;
+ /**
+ Returns a string representation of the Rule in the FuzzyLite Language
+ @param rule is the rule
+ @return a string representation of the rule in the FuzzyLite Language
+ */
+ virtual std::string toString(const Rule* rule) const;
+
+ /**
+ Returns a string representation of the Norm in the FuzzyLite Language
+ @param norm is the norm
+ @return a string representation of the norm in the FuzzyLite Language
+ */
+ virtual std::string toString(const Norm* norm) const;
+ /**
+ Returns a string representation of the Activation method in the FuzzyLite Language
+ @param activation is the activation method
+ @return a string representation of the activation method in the FuzzyLite Language
+ */
+ virtual std::string toString(const Activation* activation) const;
+ /**
+ Returns a string representation of the Defuzzifier in the FuzzyLite Language
+ @param defuzzifier is the defuzzifier
+ @return a string representation of the defuzzifier in the FuzzyLite Language
+ */
+ virtual std::string toString(const Defuzzifier* defuzzifier) const;
+ /**
+ Returns a string representation of the Term in the FuzzyLite Language
+ @param term is the term
+ @return a string representation of the term in the FuzzyLite Language
+ */
+ virtual std::string toString(const Term* term) const;
+
+ virtual FllExporter* clone() const FL_IOVERRIDE;
+ };
+}
+
+#endif /* FL_FLLEXPORTER_H */
+
diff --git a/fuzzylite/fl/imex/FllImporter.h b/fuzzylite/fl/imex/FllImporter.h
new file mode 100644
index 0000000..055bb88
--- /dev/null
+++ b/fuzzylite/fl/imex/FllImporter.h
@@ -0,0 +1,91 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FLLIMPORTER_H
+#define FL_FLLIMPORTER_H
+
+#include "fl/imex/Importer.h"
+
+#include <utility>
+
+namespace fl {
+ class TNorm;
+ class SNorm;
+ class Activation;
+ class Term;
+ class Defuzzifier;
+
+ /**
+ The FllImporter class is an Importer that configures an Engine and its
+ components utilizing the FuzzyLite Language (FLL), see
+ [http://www.fuzzylite.com/fll-fld](http://www.fuzzylite.com/fll-fld) for
+ more information.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FllExporter
+ @see Importer
+ @since 4.0
+ @todo parse methods returning respective instances from blocks of text
+ */
+ class FL_API FllImporter : public Importer {
+ private:
+ std::string _separator;
+ public:
+ explicit FllImporter(const std::string& separator = "\n");
+ virtual ~FllImporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(FllImporter)
+
+ /**
+ Sets the separator of the language (default separator is a new line '\n')
+ @param separator is the separator of the language
+ */
+ virtual void setSeparator(const std::string& separator);
+ /**
+ Gets the separator of the language (default separator is a new line '\n')
+ @return the separator of the language
+ */
+ virtual std::string getSeparator() const;
+
+ virtual std::string name() const FL_IOVERRIDE;
+ virtual Engine* fromString(const std::string& fll) const FL_IOVERRIDE;
+
+ virtual FllImporter* clone() const FL_IOVERRIDE;
+
+ protected:
+
+ virtual void process(const std::string& tag, const std::string& block, Engine* engine) const;
+ virtual void processInputVariable(const std::string& block, Engine* engine) const;
+ virtual void processOutputVariable(const std::string& block, Engine* engine) const;
+ virtual void processRuleBlock(const std::string& block, Engine* engine) const;
+
+ virtual TNorm* parseTNorm(const std::string& name) const;
+ virtual SNorm* parseSNorm(const std::string& name) const;
+ virtual Activation* parseActivation(const std::string& name) const;
+
+ virtual Term* parseTerm(const std::string& text, Engine* engine) const;
+
+ virtual Defuzzifier* parseDefuzzifier(const std::string& line) const;
+ virtual std::pair<scalar, scalar> parseRange(const std::string& line) const;
+ virtual bool parseBoolean(const std::string& boolean) const;
+
+ virtual std::pair<std::string, std::string> parseKeyValue(const std::string& text,
+ char separator = ':') const;
+
+ };
+}
+
+#endif /* FL_FLLIMPORTER_H */
+
diff --git a/fuzzylite/fl/imex/Importer.h b/fuzzylite/fl/imex/Importer.h
new file mode 100644
index 0000000..1250e66
--- /dev/null
+++ b/fuzzylite/fl/imex/Importer.h
@@ -0,0 +1,71 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_IMPORTER_H
+#define FL_IMPORTER_H
+
+#include "fl/fuzzylite.h"
+
+#include <string>
+
+namespace fl {
+ class Engine;
+
+ /**
+ The Importer class is the abstract class for importers to configure an
+ Engine and its components from different text formats.
+
+ @todo declare methods to import specific components
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API Importer {
+ public:
+
+ Importer();
+ virtual ~Importer();
+ FL_DEFAULT_COPY_AND_MOVE(Importer)
+
+ /**
+ Imports the engine from the given text
+ @param text is the string representation of the engine to import from
+ @return the engine represented by the text
+ */
+ virtual Engine* fromString(const std::string& text) const = 0;
+ /**
+ Imports the engine from the given file
+ @param path is the full path of the file containing the engine to import from
+ @return the engine represented by the file
+ */
+ virtual Engine* fromFile(const std::string& path) const;
+
+ /**
+ Returns the name of the importer
+ @return the name of the importer
+ */
+ virtual std::string name() const = 0;
+ /**
+ Creates a clone of the importer
+ @return a clone of the importer
+ */
+ virtual Importer* clone() const = 0;
+ };
+}
+
+#endif /* IMPORTER_H */
+
diff --git a/fuzzylite/fl/imex/JavaExporter.h b/fuzzylite/fl/imex/JavaExporter.h
new file mode 100644
index 0000000..a1817f6
--- /dev/null
+++ b/fuzzylite/fl/imex/JavaExporter.h
@@ -0,0 +1,152 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_JAVAEXPORTER_H
+#define FL_JAVAEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+
+namespace fl {
+
+ class Engine;
+ class InputVariable;
+ class OutputVariable;
+ class RuleBlock;
+ class Term;
+ class Defuzzifier;
+ class Norm;
+ class SNorm;
+ class TNorm;
+ class Activation;
+
+ /**
+ The JavaExporter class is an Exporter that translates an Engine and its
+ components to the `Java` programming language using the `jfuzzylite`
+ library.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see CppExporter
+ @see Exporter
+ @since 4.0
+ */
+ class FL_API JavaExporter : public Exporter {
+ private:
+ bool _usingVariableNames;
+ public:
+ explicit JavaExporter(bool usingVariableNames = true);
+ virtual ~JavaExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(JavaExporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+ /**
+ Sets whether variables are exported using their names
+ (e.g., `power.setValue(Double.NaN)`) instead of numbered identifiers
+ (e.g., `inputVariable1.setValue(Double.NaN)`)
+ @param usingVariableNames indicates whether variables are exported using
+ their names
+ */
+ virtual void setUsingVariableNames(bool usingVariableNames);
+
+ /**
+ Gets whether variables are exported using their names
+ (e.g., `power.setValue(Double.NaN)`) instead of numbered identifiers
+ (e.g., `inputVariable1.setValue(Double.NaN)`)
+ @return whether variables are exported using their names
+ */
+ virtual bool isUsingVariableNames() const;
+
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+ /**
+ Returns a string representation of the InputVariable in the Java
+ programming language
+ @param inputVariable is the input variable
+ @param engine is the engine in which the input variable is registered
+ @return a string representation of the input variable in the Java
+ programming language
+ */
+ virtual std::string toString(const InputVariable* inputVariable, const Engine* engine) const;
+ /**
+ Returns a string representation of the OutputVariable in the Java
+ programming language
+ @param outputVariable is the output variable
+ @param engine is the engine in which the output variable is registered
+ @return a string representation of the output variable in the Java
+ programming language
+ */
+ virtual std::string toString(const OutputVariable* outputVariable, const Engine* engine) const;
+ /**
+ Returns a string representation of the RuleBlock in the Java
+ programming language
+ @param ruleBlock is the rule block
+ @param engine is the engine in which the rule block is registered
+ @return a string representation of the rule block in the Java
+ programming language
+ */
+ virtual std::string toString(const RuleBlock* ruleBlock, const Engine* engine) const;
+
+ /**
+ Returns a string representation of the Term in the Java programming
+ language
+ @param term is the term
+ @return a string representation of the term in the Java programming
+ language
+ */
+ virtual std::string toString(const Term* term) const;
+
+ /**
+ Returns a string representation of the Activation method in the Java
+ programming language
+ @param activation is the activation method
+ @return a string representation of the activation method in the Java
+ programming language
+ */
+ virtual std::string toString(const Activation* activation) const;
+
+ /**
+ Returns a string representation of the Defuzzifier in the Java
+ programming language
+ @param defuzzifier is the defuzzifier
+ @return a string representation of the defuzzifier in the Java
+ programming language
+ */
+ virtual std::string toString(const Defuzzifier* defuzzifier) const;
+
+ /**
+ Returns a string representation of the Norm in the Java programming
+ language
+ @param norm is the norm
+ @return a string representation of the norm in the Java programming
+ language
+ */
+ virtual std::string toString(const Norm* norm) const;
+
+ /**
+ Returns a string representation of the scalar value in the Java
+ programming language
+ @param value is the scalar value
+ @return a string representation of the scalar value in the Java
+ programming language
+ */
+ virtual std::string toString(scalar value) const;
+
+ virtual JavaExporter* clone() const FL_IOVERRIDE;
+
+ };
+}
+
+#endif /* FL_JAVAEXPORTER_H */
+
diff --git a/fuzzylite/fl/imex/RScriptExporter.h b/fuzzylite/fl/imex/RScriptExporter.h
new file mode 100644
index 0000000..c53c751
--- /dev/null
+++ b/fuzzylite/fl/imex/RScriptExporter.h
@@ -0,0 +1,246 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_RSCRIPTEXPORTER_H
+#define FL_RSCRIPTEXPORTER_H
+
+#include "fl/imex/Exporter.h"
+#include "fl/imex/FldExporter.h"
+
+#include <vector>
+
+namespace fl {
+ class Engine;
+ class InputVariable;
+ class OutputVariable;
+
+ /**
+ The RScriptExporter class is an Exporter that creates an R script to plot one or
+ more surfaces of an engine for two input variables and any number of output
+ variables.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see FldExporter
+ @see Exporter
+ @since 6.0
+ */
+ class FL_API RScriptExporter : public Exporter {
+ private:
+ std::string _minimumColor;
+ std::string _maximumColor;
+ std::string _contourColor;
+
+ public:
+ RScriptExporter();
+ virtual ~RScriptExporter() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(RScriptExporter)
+
+ virtual std::string name() const FL_IOVERRIDE;
+
+ /**
+ Sets the color to represent the minimum values.
+ @param minimumColor is the color to represent the minimum values
+ */
+ void setMinimumColor(const std::string& minimumColor);
+ /**
+ Gets the color to represent the minimum values.
+ @return the color to represent the minimum values
+ */
+ std::string getMinimumColor() const;
+
+ /**
+ Sets the color to represent the maximum values.
+ @param maximumColor is the color to represent the maximum values
+ */
+ void setMaximumColor(const std::string& maximumColor);
+ /**
+ Gets the color to represent the maximum values.
+ @return maximumColor is the color to represent the maximum values
+ */
+ std::string getMaximumColor() const;
+
+ /**
+ Sets the color to draw the contour lines
+ @param contourColor is the color to draw the contour lines
+ */
+ void setContourColor(const std::string& contourColor);
+ /**
+ Gets the color to draw the contour lines
+ @return the color to draw the contour lines
+ */
+ std::string getContourColor() const;
+
+ /**
+ Returns an R script plotting multiple surfaces based on a data frame
+ generated with 1024 values in the scope of FldExporter::AllVariables
+ for the first two input variables.
+ @param engine is the engine to export
+ @return an R script plotting multiple surfaces for the first two input
+ variables in the engine.
+ */
+ virtual std::string toString(const Engine* engine) const FL_IOVERRIDE;
+
+ /**
+ Returns an R script plotting multiple surfaces based on a data frame
+ generated with the given number of values and scope for the two input
+ variables.
+ @param engine is the engine to export
+ @param a is the first input variable
+ @param b is the second input variable
+ @param values is the number of values to evaluate the engine
+ @param scope is the scope of the number of values to evaluate the engine
+ @param outputVariables are the output variables to create the surface for
+ @return an R script plotting multiple surfaces for the two input
+ variables on the output variables.
+ */
+ virtual std::string toString(Engine* engine, InputVariable* a, InputVariable* b,
+ int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+ /**
+ Returns an R script plotting multiple surfaces based on the input stream
+ of values for the two input variables.
+ @param engine is the engine to export
+ @param a is the first input variable
+ @param b is the second input variable
+ @param reader is an input stream of data whose lines contain space-separated
+ input values
+ @param outputVariables are the output variables to create the surface for
+ @return an R script plotting multiple surfaces for the two input
+ variables on the output variables
+ */
+ virtual std::string toString(Engine* engine, InputVariable* a, InputVariable* b,
+ std::istream& reader, const std::vector<OutputVariable*>& outputVariables) const;
+
+ /**
+ Creates an R script file plotting multiple surfaces based on a data frame
+ generated with 1024 values in the scope of FldExporter::AllVariables
+ for the two input variables
+ @param filePath is the full path of the R script file
+ @param engine is the engine to export
+ */
+ virtual void toFile(const std::string& filePath, const Engine* engine) const FL_IOVERRIDE;
+
+ /**
+ Creates an R script file plotting multiple surfaces based on a data frame
+ generated with the given number of values and scope for the two input
+ variables
+ @param filePath is the full path of the R script file
+ @param engine is the engine to export
+ @param a is the first input variable
+ @param b is the second input variable
+ @param values is the number of values to evaluate the engine
+ @param scope is the scope of the number of values to evaluate the engine
+ @param outputVariables are the output variables to create the surface for
+ */
+ virtual void toFile(const std::string& filePath, Engine* engine,
+ InputVariable* a, InputVariable* b,
+ int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+ /**
+ Creates an R script file plotting multiple surfaces based on the input stream
+ of values for the two input variables.
+ @param filePath is the full path of the R script file
+ @param engine is the engine to export
+ @param a is the first input variable
+ @param b is the second input variable
+ @param reader is an input stream of data whose lines contain space-separated
+ input values
+ @param outputVariables are the output variables to create the surface for
+ */
+ virtual void toFile(const std::string& filePath, Engine* engine,
+ InputVariable* a, InputVariable* b, std::istream& reader,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+
+ /**
+ Writes an R script plotting multiple surfaces based on a manually
+ imported data frame containing the data for the two input variables
+ on the output variables.
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param a is the first input variable
+ @param b is the second input variable
+ @param dataFramePath is the path where the data frame should be located
+ (the path will not be accessed, it will only be written to script)
+ @param outputVariables are the output variables to create the surface for
+ */
+ virtual void writeScriptImportingDataFrame(const Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, const std::string& dataFramePath,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+ /**
+ Writes an R script plotting multiple surfaces based on a data frame
+ generated with the given number of values and scope for the two input
+ variables on the output variables.
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param a is the first input variable
+ @param b is the second input variable
+ @param values is the number of values to evaluate the engine
+ @param scope is the scope of the number of values to evaluate the engine
+ @param outputVariables are the output variables to create the surface for
+ */
+ virtual void writeScriptExportingDataFrame(Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+ /**
+ Writes an R script plotting multiple surfaces based on a data frame
+ generated with the given number of values and scope for the two input
+ variables on the output variables.
+ @param engine is the engine to export
+ @param writer is the output where the engine will be written to
+ @param a is the first input variable
+ @param b is the second input variable
+ @param reader is an input stream of data whose lines contain space-separated
+ input values
+ @param outputVariables are the output variables to create the surface for
+ */
+ virtual void writeScriptExportingDataFrame(Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, std::istream& reader,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+ protected:
+ /**
+ Writes the header of the R script (e.g., import libraries)
+ @param writer is the output where the header will be written to
+ @param engine is the engine to export
+ */
+ virtual void writeScriptHeader(std::ostream& writer, const Engine* engine) const;
+
+ /**
+ Writes the code to generate the surface plots for the input variables
+ on the output variables.
+ @param writer is the output where the engine will be written to
+ @param a is the first input variable
+ @param b is the second input variable
+ @param outputVariables are the output variables to create the surface for
+ */
+ virtual void writeScriptPlots(std::ostream& writer,
+ InputVariable* a, InputVariable* b,
+ const std::vector<OutputVariable*>& outputVariables) const;
+
+
+ virtual RScriptExporter* clone() const FL_IOVERRIDE;
+
+ };
+
+}
+
+#endif /* FL_RSCRIPTEXPORTER_H */
+
diff --git a/fuzzylite/fl/norm/Norm.h b/fuzzylite/fl/norm/Norm.h
new file mode 100644
index 0000000..682d2ad
--- /dev/null
+++ b/fuzzylite/fl/norm/Norm.h
@@ -0,0 +1,75 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_NORM_H
+#define FL_NORM_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+#include <string>
+
+namespace fl {
+
+ /**
+ The Norm class is the abstract class for norms.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see TNorm
+ @see SNorm
+ @see TNormFactory
+ @see SNormFactory
+ @since 4.0
+ */
+ class FL_API Norm {
+ public:
+
+ Norm() {
+ }
+
+ virtual ~Norm() {
+ }
+
+ FL_DEFAULT_COPY_AND_MOVE(Norm)
+ /**
+ Returns the name of the class of the norm
+ @return the name of the class of the norm
+ */
+ virtual std::string className() const = 0;
+
+ /**
+ Computes the estimated complexity of computing the hedge
+ @return the complexity of computing the hedge
+ */
+ virtual Complexity complexity() const = 0;
+ /**
+ Computes the norm for @f$a@f$ and @f$b@f$
+ @param a is a membership function value
+ @param b is a membership function value
+ @return the norm between @f$a@f$ and @f$b@f$
+ */
+ virtual scalar compute(scalar a, scalar b) const = 0;
+
+ /**
+ Creates a clone of the norm
+ @return a clone of the norm
+ */
+ virtual Norm* clone() const = 0;
+
+ };
+}
+#endif /* FL_NORM_H */
diff --git a/fuzzylite/fl/norm/SNorm.h b/fuzzylite/fl/norm/SNorm.h
new file mode 100644
index 0000000..a68081c
--- /dev/null
+++ b/fuzzylite/fl/norm/SNorm.h
@@ -0,0 +1,51 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SNORM_H
+#define FL_SNORM_H
+
+#include "fl/norm/Norm.h"
+
+namespace fl {
+
+ /**
+ The SNorm class is the base class for all S-Norms, and it is utilized as
+ the disjunction fuzzy logic operator and as the aggregation (or
+ `accumulation` in versions 5.0 and earlier) fuzzy logic operator.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see RuleBlock::getDisjunction()
+ @see OutputVariable::fuzzyOutput()
+ @see Aggregated::getAggregation()
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API SNorm : public Norm {
+ public:
+
+ SNorm() {
+ }
+
+ virtual ~SNorm() FL_IOVERRIDE {
+ }
+
+ FL_DEFAULT_COPY_AND_MOVE(SNorm)
+
+ virtual SNorm* clone() const FL_IOVERRIDE = 0;
+ };
+}
+#endif /* FL_SNORM_H */
diff --git a/fuzzylite/fl/norm/TNorm.h b/fuzzylite/fl/norm/TNorm.h
new file mode 100644
index 0000000..b1f7cb7
--- /dev/null
+++ b/fuzzylite/fl/norm/TNorm.h
@@ -0,0 +1,50 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TNORM_H
+#define FL_TNORM_H
+
+#include "fl/norm/Norm.h"
+
+namespace fl {
+
+ /**
+ The TNorm class is the base class for T-Norms, and it is utilized as the
+ conjunction fuzzy logic operator and as the implication (or `activation`
+ in versions 5.0 and earlier) fuzzy logic operator.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see RuleBlock::getConjunction()
+ @see RuleBlock::getImplication()
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API TNorm : public Norm {
+ public:
+
+ TNorm() {
+ }
+
+ virtual ~TNorm() FL_IOVERRIDE {
+ }
+
+ FL_DEFAULT_COPY_AND_MOVE(TNorm)
+
+ virtual TNorm* clone() const FL_IOVERRIDE = 0;
+ };
+}
+#endif /* TNORM_H */
diff --git a/fuzzylite/fl/norm/s/AlgebraicSum.h b/fuzzylite/fl/norm/s/AlgebraicSum.h
new file mode 100644
index 0000000..2fbf4c1
--- /dev/null
+++ b/fuzzylite/fl/norm/s/AlgebraicSum.h
@@ -0,0 +1,53 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ALGEBRAICSUM_H
+#define FL_ALGEBRAICSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The AlgebraicSum class is an SNorm that computes the algebraic sum of
+ values any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see AlgebraicProduct
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API AlgebraicSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the algebraic sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$a+b-(a \times b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ AlgebraicSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+#endif /* FL_ALGEBRAICSUM_H */
diff --git a/fuzzylite/fl/norm/s/BoundedSum.h b/fuzzylite/fl/norm/s/BoundedSum.h
new file mode 100644
index 0000000..cd9438e
--- /dev/null
+++ b/fuzzylite/fl/norm/s/BoundedSum.h
@@ -0,0 +1,54 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_BOUNDEDSUM_H
+#define FL_BOUNDEDSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The BoundedSum class is an SNorm that computes the bounded sum of any two
+ values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see BoundedDifference
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API BoundedSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the bounded sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\min(1, a+b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ BoundedSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+
+}
+
+#endif /* FL_BOUNDEDSUM_H */
diff --git a/fuzzylite/fl/norm/s/DrasticSum.h b/fuzzylite/fl/norm/s/DrasticSum.h
new file mode 100644
index 0000000..a1e33fe
--- /dev/null
+++ b/fuzzylite/fl/norm/s/DrasticSum.h
@@ -0,0 +1,55 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_DRASTICSUM_H
+#define FL_DRASTICSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The DrasticSum class is an SNorm that computes the drastic sum of any two
+ values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see DrasticProduct
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API DrasticSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the drastic sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\begin{cases}
+ \max(a,b) & \mbox{if $\min(a,b)=0$} \cr
+ 1 & \mbox{otherwise}
+ \end{cases}@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ DrasticSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+#endif /* FL_DRASTICSUM_H */
diff --git a/fuzzylite/fl/norm/s/EinsteinSum.h b/fuzzylite/fl/norm/s/EinsteinSum.h
new file mode 100644
index 0000000..7450330
--- /dev/null
+++ b/fuzzylite/fl/norm/s/EinsteinSum.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_EINSTEINSUM_H
+#define FL_EINSTEINSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The EinsteinSum class is an SNorm that computes the einstein sum of any
+ two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see EinsteinProduct
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API EinsteinSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the Einstein sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$a+b/(1+a \times b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ EinsteinSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+#endif /* FL_EINSTEINSUM_H */
diff --git a/fuzzylite/fl/norm/s/HamacherSum.h b/fuzzylite/fl/norm/s/HamacherSum.h
new file mode 100644
index 0000000..0242512
--- /dev/null
+++ b/fuzzylite/fl/norm/s/HamacherSum.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HAMACHERSUM_H
+#define FL_HAMACHERSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The HamacherSum class is an SNorm that computes the Hamacher sum of any
+ two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see HamacherProduct
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API HamacherSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the Hamacher sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$a+b-(2\times a \times b)/(1-a\times b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ HamacherSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+#endif /* FL_HAMACHERSUM_H */
diff --git a/fuzzylite/fl/norm/s/Maximum.h b/fuzzylite/fl/norm/s/Maximum.h
new file mode 100644
index 0000000..c8ce488
--- /dev/null
+++ b/fuzzylite/fl/norm/s/Maximum.h
@@ -0,0 +1,51 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_MAXIMUM_H
+#define FL_MAXIMUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The Maximum class is an SNorm that computes the maximum of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Minimum
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API Maximum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the maximum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\max(a,b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ Maximum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+#endif /* FL_MAXIMUM_H */
diff --git a/fuzzylite/fl/norm/s/NilpotentMaximum.h b/fuzzylite/fl/norm/s/NilpotentMaximum.h
new file mode 100644
index 0000000..13e9793
--- /dev/null
+++ b/fuzzylite/fl/norm/s/NilpotentMaximum.h
@@ -0,0 +1,56 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_NILPOTENTMAXIMUM_H
+#define FL_NILPOTENTMAXIMUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The NilpotentMaximum class is an SNorm that computes the nilpotent
+ maximum of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see NilpotentMinimum
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 5.0
+ */
+ class FL_API NilpotentMaximum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the nilpotent maximum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\begin{cases}
+ \max(a,b) & \mbox{if $a+b<0$} \cr
+ 1 & \mbox{otherwise}
+ \end{cases}@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ NilpotentMaximum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+
+#endif /* FL_NILPOTENTMAXIMUM_H */
diff --git a/fuzzylite/fl/norm/s/NormalizedSum.h b/fuzzylite/fl/norm/s/NormalizedSum.h
new file mode 100644
index 0000000..e2e757b
--- /dev/null
+++ b/fuzzylite/fl/norm/s/NormalizedSum.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_NORMALIZEDSUM_H
+#define FL_NORMALIZEDSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The NormalizedSum class is an SNorm that computes the normalized sum of
+ any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API NormalizedSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the normalized sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$(a+b)/\max(1, a + b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ NormalizedSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+
+#endif /* FL_NORMALIZEDSUM_H */
diff --git a/fuzzylite/fl/norm/s/SNormFunction.h b/fuzzylite/fl/norm/s/SNormFunction.h
new file mode 100644
index 0000000..a78b1aa
--- /dev/null
+++ b/fuzzylite/fl/norm/s/SNormFunction.h
@@ -0,0 +1,81 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SNORMFUNCTION_H
+#define FL_SNORMFUNCTION_H
+
+#include "fl/norm/SNorm.h"
+
+#include "fl/term/Function.h"
+
+namespace fl {
+
+ /**
+ The SNormFunction class is a customizable SNorm via Function, which
+ computes any function based on the @f$a@f$ and @f$b@f$ values.
+ This SNorm is not registered with the SNormFactory.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Function
+ @see SNorm
+ @see Norm
+ @see SNormFactory
+ @since 6.0
+ */
+
+ class FL_API SNormFunction FL_IFINAL : public SNorm {
+ private:
+ Function _function;
+ public:
+ explicit SNormFunction(const std::string& formula = "");
+
+ /**
+ Returns the reference to the Function
+ @return the reference to the Function
+ */
+ Function& function();
+
+ /**
+ Loads the function with the given formula
+ @param formula is a valid formula in infix notation
+ */
+ void setFormula(const std::string& formula);
+ /**
+ Returns the formula loaded into the function
+ @return the formula loaded into the function
+ */
+ std::string getFormula() const;
+
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the S-Norm utilizing the given function via
+ SNormFunction::setFormula(), which automatically assigns the values
+ of @f$a@f$ and @f$b@f$.
+
+ @param a is a membership function value
+ @param b is a membership function value
+ @return the evaluation of the function
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ SNormFunction* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+#endif /* FL_SNORMFUNCTION_H */
+
diff --git a/fuzzylite/fl/norm/s/UnboundedSum.h b/fuzzylite/fl/norm/s/UnboundedSum.h
new file mode 100644
index 0000000..695fdfd
--- /dev/null
+++ b/fuzzylite/fl/norm/s/UnboundedSum.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_UNBOUNDEDSUM_H
+#define FL_UNBOUNDEDSUM_H
+
+#include "fl/norm/SNorm.h"
+
+namespace fl {
+
+ /**
+ The UnboundedSum class is an SNorm that computes the sum of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see BoundedSum
+ @see SNorm
+ @see SNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API UnboundedSum FL_IFINAL : public SNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the bounded sum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\min(1, a+b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ UnboundedSum* clone() const FL_IOVERRIDE;
+
+ static SNorm* constructor();
+ };
+}
+
+#endif /* FL_BOUNDEDSUM_H */
diff --git a/fuzzylite/fl/norm/t/AlgebraicProduct.h b/fuzzylite/fl/norm/t/AlgebraicProduct.h
new file mode 100644
index 0000000..d19cb64
--- /dev/null
+++ b/fuzzylite/fl/norm/t/AlgebraicProduct.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ALGEBRAICPRODUCT_H
+#define FL_ALGEBRAICPRODUCT_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The AlgebraicProduct class is a TNorm that computes the algebraic product
+ of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see AlgebraicSum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API AlgebraicProduct FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the algebraic product of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$a\times b@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ AlgebraicProduct* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_ALGEBRAICPRODUCT_H */
diff --git a/fuzzylite/fl/norm/t/BoundedDifference.h b/fuzzylite/fl/norm/t/BoundedDifference.h
new file mode 100644
index 0000000..250512b
--- /dev/null
+++ b/fuzzylite/fl/norm/t/BoundedDifference.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_BOUNDEDDIFFERENCE_H
+#define FL_BOUNDEDDIFFERENCE_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The BoundedDifference class is a TNorm that computes the bounded
+ difference between any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see BoundedSum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API BoundedDifference FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the bounded difference between two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\max(0, a+b - 1)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ BoundedDifference* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_BOUNDEDDIFFERENCE_H */
diff --git a/fuzzylite/fl/norm/t/DrasticProduct.h b/fuzzylite/fl/norm/t/DrasticProduct.h
new file mode 100644
index 0000000..d0d490e
--- /dev/null
+++ b/fuzzylite/fl/norm/t/DrasticProduct.h
@@ -0,0 +1,55 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_DRASTICPRODUCT_H
+#define FL_DRASTICPRODUCT_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The DrasticProduct class is a TNorm that computes the drastic product of
+ any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see DrasticSum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API DrasticProduct FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the drastic product of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\begin{cases}
+ \min(a,b) & \mbox{if $\max(a,b)=1$} \cr
+ 0 & \mbox{otherwise}
+ \end{cases}@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ DrasticProduct* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_DRASTICPRODUCT_H */
diff --git a/fuzzylite/fl/norm/t/EinsteinProduct.h b/fuzzylite/fl/norm/t/EinsteinProduct.h
new file mode 100644
index 0000000..9d3a71b
--- /dev/null
+++ b/fuzzylite/fl/norm/t/EinsteinProduct.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_EINSTEINPRODUCT_H
+#define FL_EINSTEINPRODUCT_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The EinsteinProduct class is a TNorm that computes the Einstein product
+ of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see EinsteinSum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API EinsteinProduct FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the Einstein product of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$(a\times b)/(2-(a+b-a\times b))@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ EinsteinProduct* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_EINSTEINPRODUCT_H */
diff --git a/fuzzylite/fl/norm/t/HamacherProduct.h b/fuzzylite/fl/norm/t/HamacherProduct.h
new file mode 100644
index 0000000..79c56ee
--- /dev/null
+++ b/fuzzylite/fl/norm/t/HamacherProduct.h
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_HAMACHERPRODUCT_H
+#define FL_HAMACHERPRODUCT_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The HamacherProduct class is a TNorm that computes the Hamacher product
+ of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see HamacherSum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API HamacherProduct FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the Hamacher product of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$(a \times b) / (a+b- a \times b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ HamacherProduct* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_HAMACHERPRODUCT_H */
diff --git a/fuzzylite/fl/norm/t/Minimum.h b/fuzzylite/fl/norm/t/Minimum.h
new file mode 100644
index 0000000..5df1ae2
--- /dev/null
+++ b/fuzzylite/fl/norm/t/Minimum.h
@@ -0,0 +1,51 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_MINIMUM_H
+#define FL_MINIMUM_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The Minimum class is a TNorm that computes the minimum of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Maximum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 4.0
+ */
+ class FL_API Minimum FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the minimum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\min(a,b)@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ Minimum* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_MINIMUM_H */
diff --git a/fuzzylite/fl/norm/t/NilpotentMinimum.h b/fuzzylite/fl/norm/t/NilpotentMinimum.h
new file mode 100644
index 0000000..2ea7f3c
--- /dev/null
+++ b/fuzzylite/fl/norm/t/NilpotentMinimum.h
@@ -0,0 +1,55 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_NILPOTENTMINIMUM_H
+#define FL_NILPOTENTMINIMUM_H
+
+#include "fl/norm/TNorm.h"
+
+namespace fl {
+
+ /**
+ The NilpotentMinimum class is a TNorm that computes the nilpotent minimum
+ of any two values.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see NilpotentMaximum
+ @see TNorm
+ @see TNormFactory
+ @see Norm
+ @since 5.0
+ */
+ class FL_API NilpotentMinimum FL_IFINAL : public TNorm {
+ public:
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the nilpotent minimum of two membership function values
+ @param a is a membership function value
+ @param b is a membership function value
+ @return @f$\begin{cases}
+ \min(a,b) & \mbox{if $a+b>1$} \cr
+ 0 & \mbox{otherwise}
+ \end{cases}@f$
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ NilpotentMinimum* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_NILPOTENTMINIMUM_H */
diff --git a/fuzzylite/fl/norm/t/TNormFunction.h b/fuzzylite/fl/norm/t/TNormFunction.h
new file mode 100644
index 0000000..1193a40
--- /dev/null
+++ b/fuzzylite/fl/norm/t/TNormFunction.h
@@ -0,0 +1,81 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TNORMFUNCTION_H
+#define FL_TNORMFUNCTION_H
+
+#include "fl/norm/TNorm.h"
+
+#include "fl/term/Function.h"
+
+namespace fl {
+
+ /**
+ The TNormFunction class is a customizable TNorm via Function, which
+ computes any function based on the @f$a@f$ and @f$b@f$ values.
+ This TNorm is not registered with the TNormFactory.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Function
+ @see TNorm
+ @see Norm
+ @see TNormFactory
+ @since 6.0
+ */
+
+ class FL_API TNormFunction FL_IFINAL : public TNorm {
+ private:
+ Function _function;
+ public:
+ explicit TNormFunction(const std::string& formula = "");
+
+ /**
+ Returns the reference to the Function
+ @return the reference to the Function
+ */
+ Function& function();
+
+ /**
+ Loads the function with the given formula
+ @param formula is a valid formula in infix notation
+ */
+ void setFormula(const std::string& formula);
+ /**
+ Returns the formula loaded into the function
+ @return the formula loaded into the function
+ */
+ std::string getFormula() const;
+
+ std::string className() const FL_IOVERRIDE;
+
+ Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the S-Norm utilizing the given function via
+ SNormFunction::setFormula(), which automatically assigns the values
+ of @f$a@f$ and @f$b@f$.
+
+ @param a is a membership function value
+ @param b is a membership function value
+ @return the evaluation of the function
+ */
+ scalar compute(scalar a, scalar b) const FL_IOVERRIDE;
+ TNormFunction* clone() const FL_IOVERRIDE;
+
+ static TNorm* constructor();
+ };
+}
+#endif /* FL_TNORMFUNCTION_H */
+
diff --git a/fuzzylite/fl/rule/Antecedent.h b/fuzzylite/fl/rule/Antecedent.h
new file mode 100644
index 0000000..a424d95
--- /dev/null
+++ b/fuzzylite/fl/rule/Antecedent.h
@@ -0,0 +1,185 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ANTECEDENT_H
+#define FL_ANTECEDENT_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+#include <string>
+
+namespace fl {
+ class Engine;
+ class Rule;
+ class TNorm;
+ class SNorm;
+ class Expression;
+
+ /**
+ The Antecedent class is an expression tree that represents and evaluates
+ the antecedent of a Rule. The structure of a rule is: `if (antecedent)
+ then (consequent)`. The structure of the antecedent of a rule is:
+
+ `if variable is [hedge]* term [(and|or) variable is [hedge]* term]*`
+
+ where `*`-marked elements may appear zero or more times, elements in
+ brackets are optional, and elements in parentheses are compulsory.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Consequent
+ @see Rule
+ @since 4.0
+ */
+ class FL_API Antecedent {
+ private:
+ std::string _text;
+ FL_unique_ptr<Expression> _expression;
+
+ public:
+ Antecedent();
+ virtual ~Antecedent();
+
+ /**
+ Sets the antecedent in text
+ @param text is the antecedent in text
+ */
+ virtual void setText(const std::string& text);
+ /**
+ Gets the antecedent in text
+ @return the antecedent in text
+ */
+ virtual std::string getText() const;
+
+ /**
+ Gets the expression tree of the antecedent
+ @return the expression tree of the antecedent
+ */
+ virtual Expression* getExpression() const;
+
+ /**
+ Sets the expression tree of the antecedent
+ @param expression is the expression tree of the antecedent
+ */
+ virtual void setExpression(Expression* expression);
+
+ /**
+ Indicates whether the antecedent is loaded
+ @return whether the antecedent is loaded
+ */
+ virtual bool isLoaded() const;
+
+ /**
+ Unloads the antecedent
+ */
+ virtual void unload();
+
+ /**
+ Loads the antecedent with the text obtained from
+ Antecedent::getText() and uses the engine to identify and retrieve
+ references to the input variables and output variables as required
+
+ @param engine is the engine from which the rules are part of
+ */
+ virtual void load(const Engine* engine);
+ /**
+ Loads the antecedent with the given text and uses the engine to
+ identify and retrieve references to the input variables and output
+ variables as required
+
+ @param antecedent is the antecedent of the rule in text
+ @param engine is the engine from which the rules are part of
+ */
+ virtual void load(const std::string& antecedent, const Engine* engine);
+
+ /**
+ Computes the estimated complexity of calculating the activation degree
+ @return the estimated complexity of calculating the activation degree
+ */
+ virtual Complexity complexity(const TNorm* conjunction, const SNorm* disjunction) const;
+ /**
+ Computes the estimated complexity of recursively calculating the
+ activation degree from the given node
+ @return the estimated complexity of recursively calculating the
+ activation degree from the given node
+ */
+ virtual Complexity complexity(const TNorm* conjunction, const SNorm* disjunction,
+ const Expression* node) const;
+
+
+ /**
+ Computes the activation degree of the antecedent on the expression
+ tree from the given node
+
+ @param conjunction is the conjunction operator from the RuleBlock
+ @param disjunction is the disjunction operator from the RuleBlock
+ @param node is a node in the expression tree of the antecedent
+ @return the activation degree of the antecedent
+ */
+ virtual scalar activationDegree(const TNorm* conjunction, const SNorm* disjunction,
+ const Expression* node) const;
+
+ /**
+ Computes the activation degree of the antecedent on the expression
+ tree from the root node
+
+ @param conjunction is the conjunction operator from the RuleBlock
+ @param disjunction is the disjunction operator from the RuleBlock
+ @return the activation degree of the antecedent on the expression tree
+ */
+ virtual scalar activationDegree(const TNorm* conjunction, const SNorm* disjunction) const;
+
+ /**
+ Returns a string representation of the expression tree in infix
+ notation
+
+ @return a string representation of the expression tree in infix
+ notation
+ */
+ virtual std::string toString() const;
+
+ /**
+ Returns a string represention of the given expression tree utilizing
+ prefix notation
+ @param node is a node in the expression tree of the antecedent
+ @return a string represention of the given expression tree utilizing
+ prefix notation
+ */
+ virtual std::string toPrefix(const Expression* node = fl::null) const;
+ /**
+ Returns a string represention of the given expression tree utilizing
+ infix notation
+ @param node is a node in the expression tree of the antecedent
+ @return a string represention of the given expression tree utilizing
+ infix notation
+ */
+ virtual std::string toInfix(const Expression* node = fl::null) const;
+ /**
+ Returns a string represention of the given expression tree utilizing
+ postfix notation
+ @param node is a node in the expression tree of the antecedent
+ @return a string represention of the given expression tree utilizing
+ postfix notation
+ */
+ virtual std::string toPostfix(const Expression* node = fl::null) const;
+
+
+ private:
+ FL_DISABLE_COPY(Antecedent)
+ };
+}
+#endif /* FL_ANTECEDENT_H */
diff --git a/fuzzylite/fl/rule/Consequent.h b/fuzzylite/fl/rule/Consequent.h
new file mode 100644
index 0000000..275d1e7
--- /dev/null
+++ b/fuzzylite/fl/rule/Consequent.h
@@ -0,0 +1,138 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CONSEQUENT_H
+#define FL_CONSEQUENT_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Complexity.h"
+
+#include <string>
+#include <vector>
+
+namespace fl {
+ class Engine;
+ class Rule;
+ class Proposition;
+ class TNorm;
+
+ /**
+ The Consequent class is a proposition set that represents and evaluates
+ the consequent of a Rule.. The structure of a rule is: `if (antecedent)
+ then (consequent)`. The structure of the consequent of a rule is:
+
+ `then variable is [hedge]* term [and variable is [hedge]* term]* [with
+ w]?`
+
+ where `*`-marked elements may appear zero or more times, elements in
+ brackets are optional, elements in parentheses are compulsory, and
+ `?`-marked elements may appear once or not at all.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Rule
+ @since 4.0
+ */
+
+ class FL_API Consequent {
+ private:
+ std::string _text;
+ std::vector<Proposition*> _conclusions;
+
+ public:
+ Consequent();
+ virtual ~Consequent();
+
+ /**
+ Sets the text of the consequent
+ @param text is the text of the consequent
+ */
+ virtual void setText(const std::string& text);
+ /**
+ Gets the text of the consequent
+ @return the text of the consequent
+ */
+ virtual std::string getText() const;
+
+ /**
+ Computes the estimated complexity of modifying the consequents
+ @return the estimated complexity of modifying the consequents
+ */
+ virtual Complexity complexity(const TNorm* implication) const;
+ /**
+ Returns an immutable vector of the propositions that represent the
+ Consequent of a Rule
+ @return an immutable vector of the set of propositions that represent
+ the Consequent of a Rule
+ */
+ virtual const std::vector<Proposition*>& conclusions() const;
+
+ /**
+ Returns the vector of propositions that represent the Consequent of a
+ Rule
+ @return the vector of propositions that represent the Consequent of a
+ Rule
+ */
+ virtual std::vector<Proposition*>& conclusions();
+
+ /**
+ Indicates whether the consequent is loaded
+ @return whether the consequent is loaded
+ */
+ virtual bool isLoaded();
+ /**
+ Unloads the consequent
+ */
+ virtual void unload();
+ /**
+ Loads the consequent with text given from Consequent::getText() and
+ uses the engine to identify and retrieve references to the input
+ variables and output variables as required
+ @param engine is the engine from which the rules are part of
+ */
+ virtual void load(const Engine* engine);
+ /**
+ Loads the consequent with the given text and uses the engine to
+ identify and retrieve references to the input variables and output
+ variables as required
+ @param consequent is the consequent of the rule in text
+ @param engine is the engine from which the rules are part of
+ */
+ virtual void load(const std::string& consequent, const Engine* engine);
+
+ /**
+ Modifies the proposition set according to the activation degree
+ (computed in the Antecedent of the Rule) and the implication operator
+ (given in the RuleBlock)
+ @param activationDegree is the activation degree computed in the
+ Antecedent of the Rule
+ @param implication is the implication operator configured in the
+ RuleBlock
+ */
+ virtual void modify(scalar activationDegree, const TNorm* implication);
+
+ /**
+ Returns a string representation of the Consequent
+ @return a string representation of the Consequent
+ */
+ virtual std::string toString() const;
+
+ private:
+ FL_DISABLE_COPY(Consequent)
+ };
+}
+#endif /* FL_CONSEQUENT_H */
diff --git a/fuzzylite/fl/rule/Expression.h b/fuzzylite/fl/rule/Expression.h
new file mode 100644
index 0000000..dbacc60
--- /dev/null
+++ b/fuzzylite/fl/rule/Expression.h
@@ -0,0 +1,133 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_EXPRESSION_H
+#define FL_EXPRESSION_H
+
+#include "fl/fuzzylite.h"
+
+#include <string>
+#include <vector>
+
+
+
+namespace fl {
+ class Variable;
+ class Hedge;
+ class Term;
+
+ /**
+ The Expression class is the base class to build an expression tree.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Consequent
+ @see Rule
+ @since 4.0
+ */
+ class FL_API Expression {
+ public:
+
+ enum Type {
+ Proposition, Operator
+ };
+ Expression();
+ virtual ~Expression();
+
+ /**
+ Returns the type of the expression
+ @return the type of the expression
+ */
+ virtual Type type() const = 0;
+ virtual std::string toString() const = 0;
+
+ private:
+ FL_DISABLE_COPY(Expression)
+ };
+
+ /**
+ The Proposition class is an Expression that represents a terminal node in
+ the expression tree as `variable is [hedge]* term`.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Consequent
+ @see Rule
+ @since 4.0
+ */
+ class FL_API Proposition FL_IFINAL : public Expression {
+ public:
+ /**Variable in `variable is [hedge]* term`*/
+ Variable* variable;
+ /**Hedge%s in `variable is [hedge]* term`, owned by the object,
+ destroyed on destructor*/
+ std::vector<Hedge*> hedges;
+ /**Term in `variable is [hedge]* term`*/
+ Term* term;
+
+ Proposition();
+ ~Proposition() FL_IOVERRIDE;
+
+ Expression::Type type() const FL_IOVERRIDE;
+
+ /**
+ Returns a string representation of the proposition
+ @return a string representation of the proposition
+ */
+ std::string toString() const FL_IOVERRIDE;
+
+
+ private:
+ FL_DISABLE_COPY(Proposition)
+ };
+
+ /**
+ The Operator class is an Expression that represents a non-terminal node
+ in the expression tree as a binary operator (i.e., `and` or `or`) on two
+ Expression nodes.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Consequent
+ @see Rule
+ @since 4.0
+ */
+ class FL_API Operator FL_IFINAL : public Expression {
+ public:
+ /**Name of the operator*/
+ std::string name;
+ /**Left expression in the binary tree*/
+ Expression* left;
+ /**Right expression in the binary tree*/
+ Expression* right;
+
+ Operator();
+ ~Operator() FL_IOVERRIDE;
+
+ Expression::Type type() const FL_IOVERRIDE;
+
+ /**
+ Returns the name of the operator
+ @return the name of the operator
+ */
+ std::string toString() const FL_IOVERRIDE;
+
+ private:
+ FL_DISABLE_COPY(Operator)
+
+ };
+}
+#endif /* FL_FUZZYEXPRESSION_H */
diff --git a/fuzzylite/fl/rule/Rule.h b/fuzzylite/fl/rule/Rule.h
new file mode 100644
index 0000000..b123d15
--- /dev/null
+++ b/fuzzylite/fl/rule/Rule.h
@@ -0,0 +1,305 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_RULE_H
+#define FL_RULE_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/rule/Consequent.h"
+#include "fl/rule/Antecedent.h"
+
+#include <map>
+#include <string>
+
+
+namespace fl {
+ class Engine;
+ class Hedge;
+ class TNorm;
+ class SNorm;
+
+ /**
+ The Rule class is a conditional statement that contributes to the control
+ of an Engine. Each rule consists of an Antecedent and a Consequent, each
+ of which comprises propositions in the form `variable is term`. The
+ propositions in the Antecedent can be connected by the conjunctive `and`
+ or the disjunctive `or`, both of which are fuzzy logic operators (TNorm
+ and SNorm, respectively). Differently, the propositions in the Consequent
+ are independent from each other and are separated with a symbolic `and`.
+ The Term in any proposition can be preceded by a Hedge that modifies its
+ membership function to model cases such as Very, Somewhat, Seldom and
+ Not. Additionally, the contribution of a rule to the control of the
+ engine can be determined by its weight @f$w \in [0.0, 1.0]@f$, which is
+ equal to 1.0 if omitted. The structure of a rule is the following: `if
+ (antecedent) then (consequent) [with weight]`. The structures of
+ the antecedent and the consequent are:
+
+ `if variable is [hedge]* term [(and|or) variable is [hedge]* term]*`
+
+ `then variable is [hedge]* term [and variable is [hedge]* term]* [with w]?`
+
+ where elements in brackets are optional, elements in parentheses are
+ compulsory, `*`-marked elements may appear zero or more times, and
+ `?`-marked elements may appear once or not at all.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Consequent
+ @see Hedge
+ @see RuleBlock
+ @since 4.0
+ */
+ class FL_API Rule {
+ private:
+ bool _enabled;
+ std::string _text;
+ scalar _weight;
+ scalar _activationDegree;
+ bool _triggered;
+ FL_unique_ptr<Antecedent> _antecedent;
+ FL_unique_ptr<Consequent> _consequent;
+
+ public:
+ explicit Rule(const std::string& text = "", scalar weight = 1.0);
+ Rule(const Rule& other);
+ Rule& operator=(const Rule& other);
+ virtual ~Rule();
+ FL_DEFAULT_MOVE(Rule)
+
+ /**
+ Sets whether the rule is enabled. An enabled rule will be fired, whereas
+ a disabled rule will not.
+ @param enabled determines whether the rule is enabled
+ */
+ virtual void setEnabled(bool enabled);
+
+ /**
+ Gets whether the rule is enabled. An enabled rule will be fired, whereas
+ a disabled rule will not.
+ @return whether the rule is enabled
+ */
+ virtual bool isEnabled() const;
+
+ /**
+ Sets the text of the rule
+ @param text is the text of the rule
+ */
+ virtual void setText(const std::string& text);
+ /**
+ Gets the text of the rule
+ @return the text of the rule
+ */
+ virtual std::string getText() const;
+
+ /**
+ Sets the weight of the rule
+ @param weight is the weight of the rule
+ */
+ virtual void setWeight(scalar weight);
+ /**
+ Gets the weight of the rule
+ @return the weight of the rule
+ */
+ virtual scalar getWeight() const;
+
+ /**
+ Sets the antecedent of the rule
+ @param antecedent is the antecedent of the rule
+ */
+ virtual void setAntecedent(Antecedent* antecedent);
+ /**
+ Gets the antecedent of the rule
+ @return the antecedent of the rule
+ */
+ virtual Antecedent* getAntecedent() const;
+
+ /**
+ Sets the consequent of the rule
+ @param consequent the consequent of the rule
+ */
+ virtual void setConsequent(Consequent* consequent);
+ /**
+ Gets the consequent of the rule
+ @return the consequent of the rule
+ */
+ virtual Consequent* getConsequent() const;
+
+ /**
+ Sets the activation degree of the rule
+ @param activationDegree is the activation degree of the rule
+ */
+ virtual void setActivationDegree(scalar activationDegree);
+
+ /**
+ Gets the activation degree of the rule
+ @return the activation degree of the rule
+ */
+ virtual scalar getActivationDegree() const;
+
+ /**
+ Activates the rule by computing its activation degree using the given
+ conjunction and disjunction operators
+ @param conjunction is the conjunction operator
+ @param disjunction is the disjunction operator
+ @return the activation degree of the rule
+ */
+ virtual scalar activateWith(const TNorm* conjunction, const SNorm* disjunction);
+
+ /**
+ Deactivates the rule
+ */
+ virtual void deactivate();
+
+ /**
+ Triggers the rule's implication (if the rule is enabled) using the
+ given implication operator and the underlying activation degree
+ @param implication is the implication operator
+ */
+ virtual void trigger(const TNorm* implication);
+
+ /**
+ Indicates whether the rule's implication was triggered
+ @return whether the rule's implication was triggered
+ */
+ virtual bool isTriggered() const;
+
+ /**
+ Returns a string representation of the rule in the FuzzyLite Language
+ @return a string representation of the rule in the FuzzyLite Language
+ */
+ virtual std::string toString() const;
+
+ /**
+ Indicates whether the rule is loaded
+ @return whether the rule is loaded
+ */
+ virtual bool isLoaded() const;
+ /**
+ Unloads the rule
+ */
+ virtual void unload();
+ /**
+ Loads the rule with the text from Rule::getText(), and uses the
+ engine to identify and retrieve references to the input variables and
+ output variables as required
+ @param engine is the engine from which the rule is part of
+ */
+ virtual void load(const Engine* engine);
+ /**
+ Loads the rule with the given text, and uses the engine to identify
+ and retrieve references to the input variables and output variables
+ as required
+
+ @param rule is the rule in text
+ @param engine is the engine from which the rule is part of
+ */
+ virtual void load(const std::string& rule, const Engine* engine);
+
+ /**
+ Creates a clone of the rule without the rule being loaded
+ @return a clone of the rule without the rule being loaded
+ */
+ virtual Rule* clone() const;
+
+ /**
+ Parses and creates a new rule based on the text passed
+ @param rule is the rule in text
+ @param engine is the engine from which the rule is part of
+ @return a new rule parsed from the given text
+ */
+ static Rule* parse(const std::string& rule, const Engine* engine);
+
+ /**
+ Returns a string representation of the `if` keyword in rules
+ @return a string representation of the `if` keyword in rules
+ */
+ inline static std::string ifKeyword() {
+ return "if";
+ }
+
+ /**
+ Returns a string representation of the `is` keyword in rules
+ @return a string representation of the `is` keyword in rules
+ */
+ inline static std::string isKeyword() {
+ return "is";
+ }
+
+ /**
+ Returns a string representation of the `then` keyword in rules
+ @return a string representation of the `then` keyword in rules
+ */
+ inline static std::string thenKeyword() {
+ return "then";
+ }
+
+ /**
+ Returns a string representation of the `and` keyword in rules
+ @return a string representation of the `and` keyword in rules
+ */
+ inline static std::string andKeyword() {
+ return "and";
+ }
+
+ /**
+ Returns a string representation of the `or` keyword in rules
+ @return a string representation of the `or` keyword in rules
+ */
+ inline static std::string orKeyword() {
+ return "or";
+ }
+
+ /**
+ Returns a string representation of the `with` keyword in rules
+ @return a string representation of the `with` keyword in rules
+ */
+ inline static std::string withKeyword() {
+ return "with";
+ }
+
+ /**
+ Computes the estimated complexity of calculating the activation degree
+ of the rule
+ @param conjunction is the conjunction operator
+ @param disjunction is the disjunction operator
+ @return the estimated complexity of calculating the activation degree
+ of the rule
+ */
+ virtual Complexity complexityOfActivation(const TNorm* conjunction,
+ const SNorm* disjunction) const;
+
+ /**
+ Computes the estimated complexity of firing the rule
+ @param implication is the implication operator
+ @return the estimated complexity of firing the rule
+ */
+ virtual Complexity complexityOfFiring(const TNorm* implication) const;
+
+ /**
+ Returns the estimated complexity of activating and firing the rule
+ @param conjunction is the conjunction operator
+ @param disjunction is the disjunction operator
+ @param implication is the implication operator
+ @return the estimated complexity of activating and firing the rule
+ */
+ virtual Complexity complexity(const TNorm* conjunction,
+ const SNorm* disjunction, const TNorm* implication) const;
+
+ };
+}
+
+#endif /* FL_RULE_H */
diff --git a/fuzzylite/fl/rule/RuleBlock.h b/fuzzylite/fl/rule/RuleBlock.h
new file mode 100644
index 0000000..d4ccace
--- /dev/null
+++ b/fuzzylite/fl/rule/RuleBlock.h
@@ -0,0 +1,233 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_RULEBLOCK_H
+#define FL_RULEBLOCK_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/activation/Activation.h"
+#include "fl/Complexity.h"
+
+#include <string>
+#include <vector>
+
+
+namespace fl {
+
+ class Engine;
+ class Rule;
+ class TNorm;
+ class SNorm;
+
+ /**
+ The RuleBlock class contains a set of Rule%s and fuzzy logic
+ operators required to control an Engine.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Engine
+ @see Rule
+ @see Antecedent
+ @see Consequent
+ @since 4.0
+ */
+ class FL_API RuleBlock {
+ private:
+ bool _enabled;
+ std::string _name;
+ std::string _description;
+ std::vector<Rule*> _rules;
+ FL_unique_ptr<TNorm> _conjunction;
+ FL_unique_ptr<SNorm> _disjunction;
+ FL_unique_ptr<TNorm> _implication;
+ FL_unique_ptr<Activation> _activation;
+
+ void copyFrom(const RuleBlock& source);
+
+ public:
+ explicit RuleBlock(const std::string& name = "");
+ RuleBlock(const RuleBlock& other);
+ RuleBlock& operator=(const RuleBlock& other);
+ virtual ~RuleBlock();
+ FL_DEFAULT_MOVE(RuleBlock)
+
+ /**
+ Enables the rule block
+ @param enabled whether the rule block is enabled
+ */
+ virtual void setEnabled(bool enabled);
+ /**
+ Indicates whether the rule block is enabled
+ @return whether the rule block is enabled
+ */
+ virtual bool isEnabled() const;
+
+ /**
+ Activates the rule block
+ */
+ virtual void activate();
+
+ /**
+ Sets the name of the rule block
+ @param name is the name of the rule block
+ */
+ virtual void setName(std::string name);
+ /**
+ Gets the name of the rule block
+ @return the name of the rule block
+ */
+ virtual std::string getName() const;
+
+ /**
+ Gets the description of the rule block
+ @return the description of the rule block
+ */
+ virtual std::string getDescription() const;
+
+ /**
+ Sets the description of the rule block
+ @param description is the description of the rule block
+ */
+ virtual void setDescription(const std::string& description);
+ /**
+ Sets the conjunction operator
+ @param conjunction is the conjunction operator
+ */
+ virtual void setConjunction(TNorm* conjunction);
+ /**
+ Gets the conjunction operator
+ @return the conjunction operator
+ */
+ virtual TNorm* getConjunction() const;
+
+ /**
+ Sets the disjunction operator
+ @param disjunction is the disjunction operator
+ */
+ virtual void setDisjunction(SNorm* disjunction);
+ /**
+ Gets the disjunction operator
+ @return the disjunction operator
+ */
+ virtual SNorm* getDisjunction() const;
+
+ /**
+ Sets the implication operator
+ @param implication is the implication operator
+ */
+ virtual void setImplication(TNorm* implication);
+ /**
+ Gets the implication operator
+ @return the implication operator
+ */
+ virtual TNorm* getImplication() const;
+
+ /**
+ Sets the activation method
+ @param activation is the activation method
+ */
+ virtual void setActivation(Activation* activation);
+ /**
+ Gets the activation method
+ @return the activation method
+ */
+ virtual Activation* getActivation() const;
+
+ /**
+ Unloads all the rules in the rule block
+ */
+ virtual void unloadRules() const;
+ /**
+ Loads all the rules into the rule block
+ @param engine is the engine where this rule block is registered
+ */
+ virtual void loadRules(const Engine* engine);
+
+ /**
+ Unloads all the rules in the rule block and then loads each rule again
+ @param engine is the engine where this rule block is registered
+ */
+ virtual void reloadRules(const Engine* engine);
+
+ /**
+ Returns a string representation of the rule block in the FuzzyLite
+ Language
+ @return a string representation of the rule block in the FuzzyLite
+ Language
+ */
+ virtual std::string toString() const;
+
+ /**
+ Returns the estimated complexity of activating the rule block
+ @return the estimated complexity of activating the rule block
+ */
+ virtual Complexity complexity() const;
+
+ /**
+ Adds the given rule to the rule block
+ @param rule is the rule to add
+ */
+ virtual void addRule(Rule* rule);
+ /**
+ Inserts the rule at the specified index, shifting other rules to
+ the right
+ @param rule is the rule to insert
+ @param index is the index at which to insert the rule
+ */
+ virtual void insertRule(Rule* rule, std::size_t index);
+ /**
+ Gets the rule at the specified index
+ @param index is the index at which the rule is retrieved
+ @return the rule at the specified index
+ */
+ virtual Rule* getRule(std::size_t index) const;
+ /**
+ Removes the rule at the specified index
+ @param index is the index at which the rule will be removed,
+ shifting other rules to the left
+ @return the rule at the specified index
+ */
+ virtual Rule* removeRule(std::size_t index);
+ /**
+ Returns the number of rules added to the rule block
+ @return the number of rules added to the rule block
+ */
+ virtual std::size_t numberOfRules() const;
+ /**
+ Sets the rules of the rule block
+ @param rules is a vector of rules
+ */
+ virtual void setRules(const std::vector<Rule*>& rules);
+ /**
+ Returns an immutable vector of the rules added to the rule block
+ @return an immutable vector of the rules added to the rule block
+ */
+ virtual const std::vector<Rule*>& rules() const;
+ /**
+ Returns a mutable vector of the rules added to the rule block
+ @return a mutable vector of the rules added to the rule block
+ */
+ virtual std::vector<Rule*>& rules();
+
+ /**
+ Creates a clone of the rule block without the rules being loaded
+ @return a clone of the rule block without the rules being loaded
+ */
+ virtual RuleBlock* clone() const;
+
+ };
+}
+#endif /* RULEBLOCK_H */
diff --git a/fuzzylite/fl/term/Activated.h b/fuzzylite/fl/term/Activated.h
new file mode 100644
index 0000000..f122a25
--- /dev/null
+++ b/fuzzylite/fl/term/Activated.h
@@ -0,0 +1,107 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ACTIVATED_H
+#define FL_ACTIVATED_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+ class TNorm;
+
+ /**
+ The Activated class is a special Term that contains pointers to the
+ necessary information of a term that has been activated as part of the
+ Antecedent of a Rule. The ownership of the pointers is not transferred to
+ objects of this class. The Activated class was named
+ `Thresholded` in versions 4.0 and earlier.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see OutputVariable
+ @see Term
+ @since 5.0
+ */
+ class FL_API Activated : public Term {
+ private:
+ const Term* _term;
+ scalar _degree;
+ const TNorm* _implication;
+
+ public:
+ explicit Activated(const Term* term = fl::null, scalar degree = 1.0,
+ const TNorm* implication = fl::null);
+ virtual ~Activated() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Activated)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"degree implication term"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Does nothing.
+ @param parameters are irrelevant
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the implication of the activation degree and the membership
+ function value of @f$x@f$
+ @param x is a value
+ @return @f$d \otimes \mu(x)@f$, where @f$d@f$ is the activation degree
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+ virtual std::string toString() const FL_IOVERRIDE;
+
+ /**
+ Sets the activated term
+ @param term is the activated term
+ */
+ virtual void setTerm(const Term* term);
+ /**
+ Gets the activated term
+ @return the activated term
+ */
+ virtual const Term* getTerm() const;
+
+ /**
+ Sets the activation degree of the term
+ @param degree is the activation degree of the term
+ */
+ virtual void setDegree(scalar degree);
+ /**
+ Gets the activation degree of the term
+ @return the activation degree of the term
+ */
+ virtual scalar getDegree() const;
+
+ /**
+ Sets the implication operator
+ @param implication is the implication operator
+ */
+ virtual void setImplication(const TNorm* implication);
+ /**
+ Gets the implication operator
+ @return the implication operator
+ */
+ virtual const TNorm* getImplication() const;
+
+ virtual Activated* clone() const FL_IOVERRIDE;
+ };
+}
+#endif /* FL_ACTIVATED_H */
diff --git a/fuzzylite/fl/term/Aggregated.h b/fuzzylite/fl/term/Aggregated.h
new file mode 100644
index 0000000..af08c75
--- /dev/null
+++ b/fuzzylite/fl/term/Aggregated.h
@@ -0,0 +1,212 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_AGGREGATED_H
+#define FL_AGGREGATED_H
+
+#include "fl/term/Term.h"
+
+#include "fl/term/Activated.h"
+
+#include <vector>
+
+namespace fl {
+
+ class SNorm;
+ class TNorm;
+
+ /**
+ The Aggregated class is a special Term that stores a fuzzy set with the
+ Activated terms from the Antecedent%s of a Rule, thereby serving mainly
+ as the fuzzy output value of the OutputVariable%s. The ownership of the
+ activated terms will be transfered to objects of this class, and
+ therefore their destructors will be called upon destruction of this term
+ (or calling Aggregated::clear()).
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Antecedent
+ @see Rule
+ @see OutputVariable
+ @see Activated
+ @see Term
+ @since 6.0
+ */
+ class FL_API Aggregated : public Term {
+ private:
+ std::vector<Activated> _terms;
+ scalar _minimum, _maximum;
+ FL_unique_ptr<SNorm> _aggregation;
+
+ void copyFrom(const Aggregated& source);
+ public:
+ explicit Aggregated(const std::string& name = "",
+ scalar minimum = fl::nan,
+ scalar maximum = fl::nan,
+ SNorm* aggregation = fl::null);
+ Aggregated(const Aggregated& other);
+ Aggregated& operator=(const Aggregated& other);
+ virtual ~Aggregated() FL_IOVERRIDE;
+ FL_DEFAULT_MOVE(Aggregated)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"aggregation minimum maximum terms"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Does nothing
+ @param parameters are irrelevant
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Aggregated* clone() const FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ virtual Complexity complexityOfMembership() const;
+ virtual Complexity complexityOfActivationDegree() const;
+
+ /**
+ Aggregates the membership function values of @f$x@f$ utilizing the
+ aggregation operator
+ @param x is a value
+ @return @f$\sum_i{\mu_i(x)}, i \in \mbox{terms}@f$
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+ /**
+ Computes the aggregated activation degree for the given term.
+ If the same term is present multiple times, the aggregation operator
+ is utilized to sum the activation degrees of the term. If the
+ aggregation operator is fl::null, a regular sum is performed.
+ @param forTerm is the term for which to compute the aggregated
+ activation degree
+ @return the aggregated activation degree for the given term
+ */
+ virtual scalar activationDegree(const Term* forTerm) const;
+
+ /**
+ Iterates over the Activated terms to find the term with the maximum
+ activation degree
+ @return the term with the maximum activation degree
+ */
+ virtual const Activated* highestActivatedTerm() const;
+
+ virtual std::string toString() const FL_IOVERRIDE;
+
+ /**
+ Sets the minimum of the range of the fuzzy set
+ @param minimum is the minimum of the range of the fuzzy set
+ */
+ virtual void setMinimum(scalar minimum);
+ /**
+ Gets the minimum of the range of the fuzzy set
+ @return the minimum of the range of the fuzzy set
+ */
+ virtual scalar getMinimum() const;
+
+ /**
+ Sets the maximum of the range of the fuzzy set
+ @param maximum is the maximum of the range of the fuzzy set
+ */
+ virtual void setMaximum(scalar maximum);
+ /**
+ Gets the maximum of the range of the fuzzy set
+ @return the maximum of the range of the fuzzy set
+ */
+ virtual scalar getMaximum() const;
+
+ /**
+ Sets the range of the fuzzy set to `[minimum, maximum]`
+ @param minimum is the minimum of the range of the fuzzy set
+ @param maximum is the maximum of the range of the fuzzy set
+ */
+ virtual void setRange(scalar minimum, scalar maximum);
+ /**
+ Returns the magnitude of the range of the fuzzy set,
+ @return the magnitude of the range of the fuzzy set,
+ i.e., `maximum - minimum`
+ */
+ virtual scalar range() const;
+
+ /**
+ Sets the aggregation operator
+ @param aggregation is the aggregation operator
+ */
+ virtual void setAggregation(SNorm* aggregation);
+ /**
+ Gets the aggregation operator
+ @return the aggregation operator
+ */
+ virtual SNorm* getAggregation() const;
+
+ /**
+ Adds a new Activated term (from the parameters) to the fuzzy set
+ @param term is the activated term
+ @param degree is the activation degree
+ @param implication is the implication operator
+ */
+ virtual void addTerm(const Term* term, scalar degree, const TNorm* implication);
+ /**
+ Adds the activated term to the fuzzy set. The activated term
+ will be deleted when Aggregated::clear()
+ @param term is the activated term
+ */
+ virtual void addTerm(const Activated& term);
+ /**
+ Gets the term at the given index
+ @param index is the index of the term
+ @return the activated term at the given index
+ */
+ virtual const Activated& getTerm(std::size_t index) const;
+ /**
+ Removes the term at the given index without deleting the term
+ @param index is the index of the term
+ @return the removed term
+ */
+ virtual const Activated& removeTerm(std::size_t index);
+ /**
+ Returns the number of activated terms
+ @return the number of activated terms
+ */
+ virtual std::size_t numberOfTerms() const;
+
+ /**
+ Sets the activated terms
+ @param terms is the activated terms
+ */
+ virtual void setTerms(const std::vector<Activated>& terms);
+ /**
+ Returns an immutable vector of activated terms
+ @return an immutable vector of activated terms
+ */
+ virtual const std::vector<Activated>& terms() const;
+ /**
+ Returns a mutable vector of activated terms
+ @return a mutable vector of activated terms
+ */
+ virtual std::vector<Activated>& terms();
+ /**
+ Indicates whether the vector of activated terms is empty
+ @return whether the vector of activated terms is empty
+ */
+ virtual bool isEmpty() const;
+ /**
+ Clears and deletes the activated terms
+ */
+ virtual void clear();
+ };
+}
+#endif /* FL_AGGREGATED_H */
diff --git a/fuzzylite/fl/term/Bell.h b/fuzzylite/fl/term/Bell.h
new file mode 100644
index 0000000..e27d9c9
--- /dev/null
+++ b/fuzzylite/fl/term/Bell.h
@@ -0,0 +1,114 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_BELL_H
+#define FL_BELL_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Bell class is an extended Term that represents the generalized bell
+ curve membership function.
+
+ @image html bell.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Bell : public Term {
+ private:
+ scalar _center;
+ scalar _width;
+ scalar _slope;
+ public:
+ explicit Bell(const std::string& name = "",
+ scalar center = fl::nan,
+ scalar width = fl::nan,
+ scalar slope = fl::nan,
+ scalar height = 1.0);
+ virtual ~Bell() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Bell)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"center width slope [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"center width slope [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$h / (1 + \left(|x-c|/w\right)^{2s}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$c@f$ is the center of the Bell,
+ @f$w@f$ is the width of the Bell,
+ @f$s@f$ is the slope of the Bell
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the center of the bell curve
+ @param center is the center of the bell curve
+ */
+ virtual void setCenter(scalar center);
+ /**
+ Gets the center of the bell curve
+ @return the center of the bell curve
+ */
+ virtual scalar getCenter() const;
+
+ /**
+ Sets the width of the bell curve
+ @param width is the width of the bell curve
+ */
+ virtual void setWidth(scalar width);
+ /**
+ Gets the width of the bell curve
+ @return the width of the bell curve
+ */
+ virtual scalar getWidth() const;
+
+ /**
+ Sets the slope of the bell curve
+ @param slope is the slope of the bell curve
+ */
+ virtual void setSlope(scalar slope);
+ /**
+ Gets the slope of the bell curve
+ @return the slope of the bell curve
+ */
+ virtual scalar getSlope() const;
+
+ virtual Bell* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+
+ };
+}
+#endif /* FL_BELL_H */
diff --git a/fuzzylite/fl/term/Binary.h b/fuzzylite/fl/term/Binary.h
new file mode 100644
index 0000000..c22a9e1
--- /dev/null
+++ b/fuzzylite/fl/term/Binary.h
@@ -0,0 +1,132 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_BINARY_H
+#define FL_BINARY_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Binary class is an edge Term that represents the binary membership
+ function.
+
+ @image html binary.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 6.0
+ */
+ class FL_API Binary : public Term {
+ private:
+ scalar _start;
+ scalar _direction;
+ public:
+
+ /**
+ Direction is an enumerator that indicates the direction of the
+ edge.
+ */
+ enum Direction {
+ /** `(_|)` increases to the right (infinity)*/
+ Positive,
+ /** `(--)` direction is NaN */
+ Undefined,
+ /** `(|_)` increases to the left (-infinity)*/
+ Negative
+ };
+
+ explicit Binary(const std::string& name = "", scalar start = fl::nan,
+ scalar direction = fl::nan, scalar height = 1.0);
+ virtual ~Binary() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Binary)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"start direction [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"start direction [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 1h & \mbox{if $ \left(s < d \vedge x \in [s, d)\right) \wedge
+ \left( s > d \vedge x \in (d, s] \right) $} \cr
+ 0h & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$s@f$ is the start of the Binary edge,
+ @f$d@f$ is the direction of the Binary edge.
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the start of the binary edge
+ @param start is the start of the binary edge
+ */
+ virtual void setStart(scalar start);
+ /**
+ Gets the start of the binary edge
+ @return the start of the binary edge
+ */
+ virtual scalar getStart() const;
+
+ /**
+ Sets the direction of the binary edge.
+
+ @f$\begin{cases}
+ \text{Positive} & \mbox{if $ d > s $}\cr
+ \text{Negative} & \mbox{if $ d < s $}\cr
+ \mbox{\tt NaN} & \mbox{otherwise}
+ \end{cases}
+ @f$
+
+ where @f$d@f$ is the given direction, and
+ @f$s@f$ is the start of the Binary edge
+
+ @param direction is the direction of the binary edge
+ */
+ virtual void setDirection(scalar direction);
+ /**
+ Gets the direction of the binary edge
+ @return the direction of the binary edge
+ */
+ virtual scalar getDirection() const;
+
+ /**
+ Gets the Direction of the binary edge as an enumerator
+ @return the Direction of the binary edge as an enumerator
+ */
+ virtual Direction direction() const;
+
+ virtual Binary* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_BINARY_H */
diff --git a/fuzzylite/fl/term/Concave.h b/fuzzylite/fl/term/Concave.h
new file mode 100644
index 0000000..12d7160
--- /dev/null
+++ b/fuzzylite/fl/term/Concave.h
@@ -0,0 +1,110 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CONCAVE_H
+#define FL_CONCAVE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Concave class is an edge Term that represents the concave membership
+ function.
+
+ @image html concave.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 5.0
+ */
+ class FL_API Concave : public Term {
+ private:
+ scalar _inflection, _end;
+ public:
+ explicit Concave(const std::string& name = "",
+ scalar inflection = fl::nan,
+ scalar end = fl::nan,
+ scalar height = 1.0);
+ virtual ~Concave() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Concave)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term as
+ @return `"inflection end [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters given
+ @param parameters as `"inflection end [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ h \times (e - i) / (2e - i - x) & \mbox{if $i \leq e \wedge x < e$
+ (increasing concave)} \cr
+ h \times (i - e) / (-2e + i + x) & \mbox{if $i > e \wedge x > e$
+ (decreasing concave)} \cr
+ h & \mbox{otherwise} \cr
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$i@f$ is the inflection of the Concave,
+ @f$e@f$ is the end of the Concave
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ virtual scalar tsukamoto(scalar activationDegree,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+
+ virtual bool isMonotonic() const FL_IOVERRIDE;
+
+ /**
+ Sets the inflection of the curve
+ @param inflection is the inflection of the curve
+ */
+ virtual void setInflection(scalar inflection);
+ /**
+ Gets the inflection of the curve
+ @return the inflection of the curve
+ */
+ virtual scalar getInflection() const;
+
+ /**
+ Sets the end of the curve
+ @param end is the end of the curve
+ */
+ virtual void setEnd(scalar end);
+ /**
+ Gets the end of the curve
+ @return the end of the curve
+ */
+ virtual scalar getEnd() const;
+
+ virtual Concave* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_CONCAVE_H */
+
diff --git a/fuzzylite/fl/term/Constant.h b/fuzzylite/fl/term/Constant.h
new file mode 100644
index 0000000..40ba77b
--- /dev/null
+++ b/fuzzylite/fl/term/Constant.h
@@ -0,0 +1,81 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_CONSTANT_H
+#define FL_CONSTANT_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Constant class is a (zero) polynomial Term that represents a constant
+ value @f$ f(x) = k @f$
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Constant : public Term {
+ private:
+ scalar _value;
+
+ public:
+ explicit Constant(const std::string& name = "",
+ scalar value = fl::nan);
+ virtual ~Constant() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Constant)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"value"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"value"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x is irrelevant
+ @return @f$c@f$, where @f$c@f$ is the constant value
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the constant value
+ @param value is the constant value
+ */
+ virtual void setValue(scalar value);
+ /**
+ Gets the constant value
+ @return the constant value
+ */
+ virtual scalar getValue() const;
+
+ virtual Constant* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_CONSTANT_H */
+
diff --git a/fuzzylite/fl/term/Cosine.h b/fuzzylite/fl/term/Cosine.h
new file mode 100644
index 0000000..b45ab85
--- /dev/null
+++ b/fuzzylite/fl/term/Cosine.h
@@ -0,0 +1,101 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_COSINE_H
+#define FL_COSINE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Cosine class is an extended Term that represents the cosine
+ membership function.
+
+ @image html cosine.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 5.0
+ */
+
+ class FL_API Cosine : public Term {
+ private:
+ scalar _center, _width;
+ public:
+ explicit Cosine(const std::string& name = "",
+ scalar center = fl::nan,
+ scalar width = fl::nan,
+ scalar height = 1.0);
+ virtual ~Cosine() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Cosine)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"center width [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"center width [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 0h & \mbox{if $x < c - 0.5w \vee x > c + 0.5w$} \cr
+ 0.5h \times ( 1 + \cos(2.0 / w\pi(x-c))) & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$c@f$ is the center of the Cosine,
+ @f$w@f$ is the width of the Cosine
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+ /**
+ Sets the center of the cosine
+ @param center is the center of the cosine
+ */
+ virtual void setCenter(scalar center);
+ /**
+ Gets the center of the cosine
+ @return the center of the cosine
+ */
+ virtual scalar getCenter() const;
+
+ /**
+ Sets the width of the cosine
+ @param width is the width of the cosine
+ */
+ virtual void setWidth(scalar width);
+ /**
+ Gets the width of the cosine
+ @return the width of the cosine
+ */
+ virtual scalar getWidth() const;
+
+ virtual Cosine* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_COSINE_H */
+
diff --git a/fuzzylite/fl/term/Discrete.h b/fuzzylite/fl/term/Discrete.h
new file mode 100644
index 0000000..ba5ae70
--- /dev/null
+++ b/fuzzylite/fl/term/Discrete.h
@@ -0,0 +1,280 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_DISCRETE_H
+#define FL_DISCRETE_H
+
+#include "fl/term/Term.h"
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+#include <vector>
+#include <utility>
+
+namespace fl {
+
+ /**
+ The Discrete class is a basic Term that represents a discrete membership
+ function. The pairs of values in any Discrete term **must** be sorted
+ ascendently because the membership function is computed using binary search
+ to find the lower and upper bounds of @f$x@f$.
+
+ @image html discrete.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Discrete : public Term {
+ public:
+ typedef std::pair<scalar, scalar> Pair;
+ private:
+ std::vector<Pair> _xy;
+ public:
+ explicit Discrete(const std::string& name = "",
+ const std::vector<Pair>& xy = std::vector<Pair>(),
+ scalar height = 1.0);
+ virtual ~Discrete() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Discrete)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term as `x1 y1 xn yn [height]`
+ @return `x1 y1 xn yn [height]`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters given as `x1 y1 xn yn [height]`
+ @param parameters as `x1 y1 xn yn [height]`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Ascendantly sorts the given pairs of values by the @f$x@f$-value,
+ as it is required by the Discrete term.
+ @param pairs is a vector of pairs of values in the form @f$(x,y)@f$
+ */
+ static void sort(std::vector<Pair>& pairs);
+
+ /**
+ Ascendantly sorts the pairs of values in this Discrete term by the
+ @f$x@f$-coordinate
+ */
+ virtual void sort();
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$ by using binary
+ search to find the lower and upper bounds of @f$x@f$ and then linearly
+ interpolating the membership function between the bounds.
+ @param x
+ @return @f$ \dfrac{h (y_{\max} - y_{\min})}{(x_{\max}- x_{\min})} (x - x_{\min}) + y_{\min}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$x_{\min}@f$ and @f$x_{\max}@f$is are the lower and upper limits
+ of @f$x@f$ in `xy` (respectively),
+ @f$y_{\min}@f$ and @f$y_{\max}@f$is are the membership functions
+ of @f$\mu(x_{\min})@f$ and @f$\mu(x_{\max})@f$ (respectively)
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the vector of pairs defining the discrete membership function
+ @param pairs is the vector of pairs defining the discrete membership function
+ */
+ virtual void setXY(const std::vector<Pair>& pairs);
+ /**
+ Gets an immutable vector of pairs defining the discrete membership function
+ @return an immutable vector of pairs defining the discrete membership function
+ */
+ virtual const std::vector<Pair>& xy() const;
+ /**
+ Gets a mutable vector of pairs defining the discrete membership function
+ @return a mutable vector of pairs defining the discrete membership function
+ */
+ virtual std::vector<Pair>& xy();
+ /**
+ Gets the immutable pair @f$(x_i,y_i)@f$ at index @f$i@f$
+ @param index is the index @f$i@f$
+ @return the immutable pair @f$(x_i,y_i)@f$
+ */
+ virtual const Pair& xy(std::size_t index) const;
+ /**
+ Gets the mutable pair @f$(x_i,y_i)@f$ at index @f$i@f$
+ @param index is the index @f$i@f$
+ @return a mutable pair @f$(x_i,y_i)@f$
+ */
+ virtual Pair& xy(std::size_t index);
+
+ /**
+ Creates, fills and returns a vector containing the @f$x@f$ values
+ @return a vector containing the @f$x@f$ values
+ */
+ virtual std::vector<scalar> x() const;
+
+ /**
+ Gets the @f$x@f$ value at the given index
+ @return the @f$x@f$ value at the given index
+ */
+ virtual scalar x(std::size_t index) const;
+
+ /**
+ Gets the reference to the @f$x@f$ value at the given index
+ @return the reference to the @f$x@f$ value at the given index
+ */
+ virtual scalar& x(std::size_t index);
+
+ /**
+ Creates, fills and returns a vector containing the @f$y@f$ values
+ @return a vector containing the @f$y@f$ values
+ */
+ virtual std::vector<scalar> y() const;
+
+ /**
+ Gets the @f$y@f$ value at the given index
+ @param index is the index
+ @return the @f$y@f$ value at the given index
+ */
+ virtual scalar y(std::size_t index) const;
+
+ /**
+ Gets the reference to the @f$y@f$ value at the given index
+ @param index is the index
+ @return the reference to the @f$y@f$ value at the given index
+ */
+ virtual scalar& y(std::size_t index);
+ /**
+ Creates a vector of fl::scalar from a vector of Pair given in the
+ form @f$\left(\{x_1,y_1\},...,\{x_n,y_n\}\right)@f$
+ @param xy is the vector of Pair
+ @return a vector of fl::scalar as @f$(x_1,y_1,...,x_n,y_n)@f$
+ */
+ static std::vector<scalar> toVector(const std::vector<Pair>& xy);
+ /**
+ Creates a vector of Pair from a vector of fl::scalar given in the
+ form @f$(x_1,y_1,...,x_n,y_n)@f$
+ @param xy is a vector of fl::scalar given as
+ @f$(x_1,y_1,...,x_n,y_n)@f$
+ @return a vector of Pair in the form
+ @f$\left(\{x_1,y_1\},...,\{x_n,y_n\}\right)@f$
+ @throws fl::Exception if a value is missing, that is, if the length
+ of @f$xy@f$ is odd: @f$|xy|\mod 2 = 1@f$
+ */
+ static std::vector<Pair> toPairs(const std::vector<scalar>& xy);
+ /**
+ Creates a vector of Pair from a vector of fl::scalar given in the
+ form @f$(x_1,y_1,...,x_n,y_n)@f$
+ @param xy is a vector of fl::scalar given as
+ @f$(x_1,y_1,...,x_n,y_n)@f$ possibly missing a value
+ @param missingValue is the replacement in the case a value is missing
+ from @f$xy@f$
+ @return a vector of Pair in the form
+ @f$\left(\{x_1,y_1\},...,\{x_n,y_n\}\right)@f$
+ */
+ static std::vector<Pair> toPairs(const std::vector<scalar>& xy,
+ scalar missingValue) FL_INOEXCEPT;
+
+ /**
+ Formats a vector of Pair into a std::string in the form
+ @f$(x_1,y_1) ... (x_n,y_n)@f$
+ @param xy is the vector of Pair
+ @param prefix indicates the prefix of a Pair, e.g., `(` results in
+ @f$(x_i@f$
+ @param innerSeparator indicates the separator between
+ @f$x@f$ and @f$y@f$, e.g., `,` results in @f$x_i,y_i@f$
+ @param suffix indicates the postfix of a Pair, e.g., `]` results in
+ @f$y_i]@f$
+ @param outerSeparator indicates the separator between Pair, e.g.,
+ `;` results in @f$(x_i,y_i);(x_j,y_j)@f$
+ @return a formatted string containing the pairs of @f$(x,y)@f$ values
+ */
+ static std::string formatXY(const std::vector<Pair>& xy,
+ const std::string& prefix = "(", const std::string& innerSeparator = ",",
+ const std::string& suffix = ")", const std::string& outerSeparator = " ");
+
+ /**
+ Discretizes the given term
+ @param term is the term to discretize
+ @param start is the value from which discretization starts
+ @param end is the value at which discretization ends
+ @param resolution is the number of equally-distributed samples to
+ perform between start and end
+ @param boundedMembershipFunction indicates whether to ensure that
+ @f$\mu(x)\in[0.0,1.0]@f$
+ @return a Discrete term that approximates the given term
+ */
+ static Discrete* discretize(const Term* term, scalar start, scalar end,
+ int resolution = IntegralDefuzzifier::defaultResolution(),
+ bool boundedMembershipFunction = true);
+
+ virtual Discrete* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+
+ /**
+ Creates a Discrete term from a variadic set of values.
+ Beware: this method is unsafe and must be used with care by
+ ensuring:
+ - the value `argc` correctly and exactly determines the number of
+ values passed,
+ - the data type of each variadic arguments is the same, e.g.,
+ @f$(1.0, 2.0, 3.0)@f$ are all fl::scalar, whereas in
+ @f$(1.0, 2, 3.0)@f$ the second term is an integer, which will cause
+ memory access issues due to the difference in size between
+ `int` and `fl::scalar`.
+ @param name is the name of the resulting term
+ @param argc is the number of values passed
+ @param x1 is the @f$x@f$ value of the first Pair
+ @param y1 is the @f$y@f$ value of the first Pair
+ @param ... are the remaining pairs of values @f$x_i@f$ and @f$y_i@f$
+ @return a new Discrete term with the given parameters
+ */
+ template <typename T>
+ static Discrete* create(const std::string& name, int argc,
+ T x1, T y1, ...);
+ };
+}
+
+/**
+ Template implementation
+ */
+
+namespace fl {
+
+ template <typename T>
+ inline Discrete* Discrete::create(const std::string& name, int argc,
+ T x1, T y1, ...) {
+ std::vector<scalar> xy(argc);
+ xy.at(0) = x1;
+ xy.at(1) = y1;
+ va_list args;
+ va_start(args, y1);
+ for (int i = 2; i < argc; ++i) {
+ xy.at(i) = (scalar) va_arg(args, T);
+ }
+ va_end(args);
+
+ FL_unique_ptr<Discrete> result(new Discrete(name));
+ if (xy.size() % 2 != 0) {
+ result->setHeight(xy.back());
+ xy.pop_back();
+ }
+ result->setXY(toPairs(xy));
+ return result.release();
+ }
+}
+#endif /* FL_DISCRETE_H */
diff --git a/fuzzylite/fl/term/Function.h b/fuzzylite/fl/term/Function.h
new file mode 100644
index 0000000..14e3427
--- /dev/null
+++ b/fuzzylite/fl/term/Function.h
@@ -0,0 +1,399 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_FUNCTION_H
+#define FL_FUNCTION_H
+
+#include "fl/term/Term.h"
+
+#include <map>
+#include <string>
+
+namespace fl {
+
+ class Engine;
+
+ /**
+ The Function class is a polynomial Term that represents a generic
+ function @f$ f : x \mapsto f(x) @f$. Every Function object has a public
+ key-value map, namely Function::variables, that links variable names to
+ fl::scalar values, which are utilized to replace the variable names for
+ their respective values in the given formula whenever the function
+ @f$f@f$ is evaluated. Specifically, when the method
+ Function::membership() is called, the name and value of the variable
+ @f$x@f$ are automatically loaded into the map. Furthermore, if an Engine
+ is given, the names of its InputVariable%s and OutputVariable%s will also
+ be automatically loaded into the map linking to their respective input
+ values and (previously defuzzified) output values. The
+ Function::variables need to be manually loaded whenever variables other
+ than @f$x@f$, input variables, and output variables, are expressed in the
+ given formula, always having in mind that (a) the map replaces existing
+ keys, and (b) the variable @f$x@f$, and input variables and output
+ variables of an engine will automatically be replaced and will also take
+ precedence over previously loaded variables.
+
+ Besides the use of Function as a linguistic Term, it is also utilized to
+ convert the text of the Antecedent of a Rule, expressed in infix
+ notation, into postfix notation.
+
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @see FunctionFactory
+ @see Antecedent::load()
+ @since 4.0
+ */
+ class FL_API Function : public Term {
+ public:
+ typedef scalar(*Unary)(scalar);
+ typedef scalar(*Binary)(scalar, scalar);
+
+ /**
+ The Element class represents a single element in a formula, be that
+ either a function or an operator. If the Element represents a
+ function, the function can be Unary or Binary, that is, the function
+ take one or two parameters (respectively). Else, if the Element
+ represents an operator, the parameters to be defined are its `arity`,
+ its `precedence`, and its `associativity`.
+ */
+ struct FL_API Element {
+
+ /**
+ Determines the type of the element
+ */
+ enum Type {
+ Operator, Function
+ };
+ /**Name of the element*/
+ std::string name;
+ /**Description of the element*/
+ std::string description;
+ /**Type of the element*/
+ Type type;
+ /**Pointer to unary method*/
+ Unary unary;
+ /**Pointer to binary method*/
+ Binary binary;
+ /**Number of operands required*/
+ int arity;
+ /**Precedence of the element: clarifies which procedures should be
+ performed first in a given mathematical expression
+ (https://en.wikipedia.org/wiki/Order_of_operations)*/
+ int precedence;
+ /**Associativity of the element: determines how operators of the
+ same precedence are grouped in the absence of parentheses
+ (https://en.wikipedia.org/wiki/Operator_associativity)*/
+ int associativity;
+ Element(const std::string& name, const std::string& description, Type type);
+ Element(const std::string& name, const std::string& description,
+ Type type, Unary unary, int precedence = 0, int associativity = -1);
+ Element(const std::string& name, const std::string& description,
+ Type type, Binary binary, int precedence = 0, int associativity = -1);
+ virtual ~Element();
+ FL_DEFAULT_COPY_AND_MOVE(Element)
+
+ /**
+ Indicates whether the element is a Type::Operator
+ @return whether the element is a Type::Operator
+ */
+ virtual bool isOperator() const;
+ /**
+ Indicates whether the element is a Type::Function
+ @return whether the element is a Type::Function
+ */
+ virtual bool isFunction() const;
+ /**
+ Clones the element
+ @return a clone of the element
+ */
+ virtual Element* clone() const;
+
+ /**
+ Returns a description of the element and its members
+ @return a description of the element and its members
+ */
+ virtual std::string toString() const;
+
+ };
+
+ /**
+ The Node class structures a binary tree by storing pointers to a left
+ Node and a right Node, and storing its content as a
+ Function::Element, the name of an InputVariable or OutputVariable, or
+ a constant value.
+ */
+ struct FL_API Node {
+ /**The node takes an operation or a function*/
+ FL_unique_ptr<Element> element;
+ /**The node can have an expression tree on the left*/
+ FL_unique_ptr<Node> left;
+ /**The node can have an expression tree on the right*/
+ FL_unique_ptr<Node> right;
+ /**The node can refer to a variable by name*/
+ std::string variable;
+ /**The node can take an arbitrary floating-point value*/
+ scalar value;
+
+ explicit Node(Element* element, Node* left = fl::null, Node* right = fl::null);
+ explicit Node(const std::string& variable);
+ explicit Node(scalar value);
+ Node(const Node& source);
+ Node& operator=(const Node& rhs);
+ virtual ~Node();
+ FL_DEFAULT_MOVE(Node)
+
+ /**
+ Evaluates the node and substitutes the variables therein for the
+ values passed in the map. The expression tree is evaluated
+ recursively.
+
+ @param variables is a map of substitutions of variable names for
+ fl::scalar%s
+
+ @return a fl::scalar indicating the result of the evaluation of
+ the node
+ */
+ virtual scalar evaluate(const std::map<std::string, scalar>*
+ variables = fl::null) const;
+
+ /**
+ Computes the size of the subtree under the given node. The complexity
+ of calling this method is O(n).
+ @param node is the root of the subtree, which is this node if
+ fl::null is given
+ @return the size of the subtree under the given node
+ */
+ virtual std::size_t treeSize(const Node* node = fl::null) const;
+
+ /**
+ Computes the size of the subtree under the given node whose elements
+ are of the given type. The complexity of calling this method is O(n).
+ @param type is the type of elements to account for
+ @param node is the root of the subtree, which is this node if
+ fl::null is given
+ @return
+ */
+ virtual std::size_t treeSize(Element::Type type,
+ const Node* node = fl::null) const;
+
+ /**
+ Creates a clone of the node.
+ @return a clone of the node
+ */
+ virtual Node* clone() const;
+
+ /**
+ Returns a string with the name of the element, the name of the
+ variable, or the constant value, accordingly.
+ @return a string with the name of the element, the name of the
+ variable, or the constant value, accordingly.
+ */
+ virtual std::string toString() const;
+ /**
+ Returns a prefix representation of the expression tree under the
+ given node
+ @param node is the node to start the prefix representation from.
+ If the node is `fl::null`, then the starting point is `this` node
+ @return a prefix representation of the expression tree under the
+ given node
+ */
+ virtual std::string toPrefix(const Node* node = fl::null) const;
+ /**
+ Returns an infix representation of the expression tree under the
+ given node
+ @param node is the node to start the infix representation from.
+ If the node is `fl::null`, then the starting point is `this` node
+ @return an infix representation of the expression tree under the
+ given node
+ */
+ virtual std::string toInfix(const Node* node = fl::null) const;
+ /**
+ Returns a postfix representation of the expression tree under the
+ given node
+ @param node is the node to start the postfix representation from.
+ If the node is `fl::null`, then the starting point is `this` node
+ @return a postfix representation of the expression tree under the
+ given node
+ */
+ virtual std::string toPostfix(const Node* node = fl::null) const;
+ private:
+ void copyFrom(const Node& source);
+ };
+
+
+
+
+ /******************************
+ * Term
+ ******************************/
+
+ private:
+ FL_unique_ptr<Node> _root;
+ std::string _formula;
+ const Engine* _engine;
+ public:
+ /**A map of variables and substitution values**/
+ mutable std::map<std::string, scalar> variables;
+ explicit Function(const std::string& name = "",
+ const std::string& formula = "", const Engine* engine = fl::null);
+ Function(const Function& other);
+ Function& operator=(const Function& other);
+ virtual ~Function() FL_IOVERRIDE;
+ FL_DEFAULT_MOVE(Function)
+
+ /**
+ Creates a Function term with the given parameters
+ @param name is the name of the term
+ @param formula is the formula defining the membership function
+ @param engine is the engine to which the Function can have access
+ @return a Function term configured with the given parameters
+ @throws fl::Exception if the formula has a syntax error
+ */
+ static Function* create(const std::string& name,
+ const std::string& formula,
+ const Engine* engine = fl::null);
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function value of @f$x@f$ at the root node.
+ If the engine has been set, the current values of the input variables
+ and output variables are added to the map of Function::variables. In
+ addition, the variable @f$x@f$ will also be added to the map.
+ @param x
+ @return the membership function value of @f$x@f$ at the root node
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Computes the function value of this term using the given map of
+ variable substitutions.
+ @param variables is a map of substitution variables
+ @return the function value of this term using the given map of
+ variable substitutions.
+ */
+ virtual scalar evaluate(const std::map<std::string, scalar>* variables = fl::null) const;
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term as `formula`
+ @return `formula`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters given as `formula`
+ @param parameters as `formula`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ /**
+ Sets the formula of the function
+ @param formula is the formula of the function
+ */
+ virtual void setFormula(const std::string& formula);
+ /**
+ Gets the formula of the function
+ @return the formula of the function
+ */
+ virtual std::string getFormula() const;
+
+ /**
+ Sets the engine to which the formula can refer
+ @param engine is the engine to which the formula can refer
+ */
+ virtual void setEngine(const Engine* engine);
+ /**
+ Gets the engine to which the formula can refer
+ @return the engine to which the formula can refer
+ */
+ virtual const Engine* getEngine() const;
+
+ /**
+ Gets the root node of the expression tree defining the Function. The
+ root is `fl::null` if the formula has not been loaded.
+ @return the root node of the expression tree defining the Function,
+ or `fl::null` if the formula has not been loaded
+ */
+ virtual Node* root() const;
+
+ /**
+ Indicates whether the formula is loaded
+ @return whether the formula is loaded
+ */
+ virtual bool isLoaded() const;
+ /**
+ Unloads the formula and resets the map of substitution variables.
+ */
+ virtual void unload();
+ /**
+ Loads the current formula expressed in infix notation
+ */
+ virtual void load();
+ /**
+ Loads the given formula expressed in infix notation
+ @param formula is the right-hand side of a mathematical equation
+ @throws fl::Exception if the formula has syntax errors
+ */
+ virtual void load(const std::string& formula);
+ /**
+ Loads the given formula expressed in infix notation, and sets the
+ engine holding the variables to which the formula refers.
+ @param formula is the right-hand side of a mathematical equation
+ expressed in infix notation
+ @param engine is the engine to which the formula can refer
+ @throws fl::Exception if the formula has syntax errors
+ */
+ virtual void load(const std::string& formula, const Engine* engine);
+ /**
+ Creates a node representing a binary expression tree from the given formula
+ @param formula is the right-hand side of a mathematical equation
+ expressed in infix notation
+ @return a node representing a binary expression tree from the given formula
+ @throws fl::Exception if the formula has syntax errors
+ */
+ virtual Node* parse(const std::string& formula);
+
+ /**
+ Translates the given formula to postfix notation
+ @param formula is the right-hand side of a mathematical equation
+ expressed in infix notation
+ @return the formula represented in postfix notation
+ @throws fl::Exception if the formula has syntax errors
+ */
+ virtual std::string toPostfix(const std::string& formula) const;
+
+ /**
+ Adds spaces to the formula to separate parentheses, commas and
+ function operators such that these are treated as tokens when parsing
+ the function.
+ @param formula is the right-hand side of a mathematical equation
+ expressed in infix notation
+ @return the formula with spaces before and after parentheses, commas
+ and function operators
+ */
+ virtual std::string space(const std::string& formula) const;
+
+ virtual void updateReference(const Engine* engine) FL_IOVERRIDE;
+
+ virtual Function* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+
+ };
+}
+#endif /* FL_FUNCTION_H */
+
diff --git a/fuzzylite/fl/term/Gaussian.h b/fuzzylite/fl/term/Gaussian.h
new file mode 100644
index 0000000..9a7475d
--- /dev/null
+++ b/fuzzylite/fl/term/Gaussian.h
@@ -0,0 +1,99 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_GAUSSIAN_H
+#define FL_GAUSSIAN_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Gaussian class is an extended Term that represents the %Gaussian
+ curve membership function.
+
+ @image html gaussian.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Gaussian : public Term {
+ private:
+ scalar _mean;
+ scalar _standardDeviation;
+
+ public:
+ explicit Gaussian(const std::string& name = "",
+ scalar mean = fl::nan,
+ scalar standardDeviation = fl::nan,
+ scalar height = 1.0);
+ virtual ~Gaussian() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Gaussian)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"mean standardDeviation [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"mean standardDeviation [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$ h \times \exp(-(x-\mu)^2/(2\sigma^2))@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$\mu@f$ is the mean of the Gaussian,
+ @f$\sigma@f$ is the standard deviation of the Gaussian
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the mean of the Gaussian curve
+ @param mean is the mean of the Gaussian curve
+ */
+ virtual void setMean(scalar mean);
+ /**
+ Gets the mean of the Gaussian curve
+ @return the mean of the Gaussian curve
+ */
+ virtual scalar getMean() const;
+
+ /**
+ Sets the standard deviation of the Gaussian curve
+ @param standardDeviation is the standard deviation of the Gaussian curve
+ */
+ virtual void setStandardDeviation(scalar standardDeviation);
+ /**
+ Gets the standard deviation of the Gaussian curve
+ @return the standard deviation of the Gaussian curve
+ */
+ virtual scalar getStandardDeviation() const;
+
+ virtual Gaussian* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_GAUSSIAN_H */
diff --git a/fuzzylite/fl/term/GaussianProduct.h b/fuzzylite/fl/term/GaussianProduct.h
new file mode 100644
index 0000000..e4a500c
--- /dev/null
+++ b/fuzzylite/fl/term/GaussianProduct.h
@@ -0,0 +1,138 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_GAUSSIANPRODUCT_H
+#define FL_GAUSSIANPRODUCT_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The GaussianProduct class is an extended Term that represents the
+ two-sided %Gaussian membership function.
+
+ @image html gaussianProduct.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API GaussianProduct : public Term {
+ private:
+ scalar _meanA;
+ scalar _standardDeviationA;
+ scalar _meanB;
+ scalar _standardDeviationB;
+
+ public:
+ explicit GaussianProduct(const std::string& name = "",
+ scalar meanA = fl::nan,
+ scalar standardDeviationA = fl::nan,
+ scalar meanB = fl::nan,
+ scalar standardDeviationB = fl::nan,
+ scalar height = 1.0);
+ virtual ~GaussianProduct() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(GaussianProduct)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Provides the parameters of the term
+ @return `"meanA standardDeviationA meanB standardDeviationB [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"meanA standardDeviationA meanB
+ standardDeviationB [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$ h \left((1 - i) + i \times \exp(-(x - \mu_a)^2 /
+ (2\sigma_a^2))\right)
+ \left((1 - j) + j \times \exp(-(x - \mu_b)^2 / (2 \sigma_b)^2)\right)
+ @f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$\mu_a@f$ is the mean of the first GaussianProduct,
+ @f$\sigma_a@f$ is the standard deviation of the first
+ GaussianProduct,
+ @f$\mu_b@f$ is the mean of the second GaussianProduct,
+ @f$\sigma_b@f$ is the standard deviation of the second
+ GaussianProduct,
+ @f$i=\begin{cases}1 & \mbox{if $x \leq \mu_a$} \cr 0
+ &\mbox{otherwise}\end{cases}@f$,
+ @f$j=\begin{cases}1 & \mbox{if $x \geq \mu_b$} \cr 0
+ &\mbox{otherwise}\end{cases}@f$
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the mean of the first %Gaussian curve
+ @param meanA is the mean of the first %Gaussian curve
+ */
+ virtual void setMeanA(scalar meanA);
+ /**
+ Gets the mean of the first %Gaussian curve
+ @return the mean of the first %Gaussian curve
+ */
+ virtual scalar getMeanA() const;
+
+ /**
+ Sets the standard deviation of the first %Gaussian curve
+ @param standardDeviationA is the standard deviation of the first %Gaussian curve
+ */
+ virtual void setStandardDeviationA(scalar standardDeviationA);
+ /**
+ Gets the standard deviation of the first %Gaussian curve
+ @return the standard deviation of the first %Gaussian curve
+ */
+ virtual scalar getStandardDeviationA() const;
+
+ /**
+ Sets the mean of the second %Gaussian curve
+ @param meanB is the mean of the second %Gaussian curve
+ */
+ virtual void setMeanB(scalar meanB);
+ /**
+ Gets the mean of the second %Gaussian curve
+ @return the mean of the second %Gaussian curve
+ */
+ virtual scalar getMeanB() const;
+
+ /**
+ Sets the standard deviation of the second %Gaussian curve
+ @param standardDeviationB is the standard deviation of the second %Gaussian curve
+ */
+ virtual void setStandardDeviationB(scalar standardDeviationB);
+ /**
+ Gets the standard deviation of the second %Gaussian curve
+ @return the standard deviation of the second %Gaussian curve
+ */
+ virtual scalar getStandardDeviationB() const;
+
+ virtual GaussianProduct* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_GAUSSIANPRODUCT_H */
+
diff --git a/fuzzylite/fl/term/Linear.h b/fuzzylite/fl/term/Linear.h
new file mode 100644
index 0000000..1105a1d
--- /dev/null
+++ b/fuzzylite/fl/term/Linear.h
@@ -0,0 +1,179 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_LINEAR_H
+#define FL_LINEAR_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+ class Engine;
+
+ /**
+ The Linear class is a linear polynomial Term expressed as @f$f(x)=
+ \mathbf{c}\mathbf{v}+k = \sum_i c_iv_i + k@f$, where variable @f$x@f$ is
+ not utilized, @f$\mathbf{v}@f$ is a vector of values from the input
+ variables, @f$\mathbf{c}@f$ is a vector of coefficients, and @f$k@f$ is a
+ constant. Hereinafter, the vector @f$\mathbf{c}^\star=\{c_1, \ldots, c_i,
+ \ldots, c_n, k\}@f$ refers to a vector containing the coefficients of
+ @f$\mathbf{c}@f$ and the constant @f$k@f$.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Linear : public Term {
+ private:
+ /**Contains the coefficients @f$c_i@f$ and the constant @f$k@f$*/
+ std::vector<scalar> _coefficients;
+ const Engine* _engine;
+ public:
+ explicit Linear(const std::string& name = "",
+ const std::vector<scalar>& coefficients = std::vector<scalar>(),
+ const Engine* engine = fl::null);
+ virtual ~Linear() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Linear)
+
+ virtual std::string className() const FL_IOVERRIDE;
+
+ /**
+ Returns the vector @f$\mathbf{c}^\star@f$
+ @return `"c1 ... ci ... cn k"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the values of @f$\mathbf{c}^\star@f$
+ @param parameters as `"c1 ... ci ... cn k"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the linear function @f$f(x)=\sum_i c_iv_i +k@f$,
+ where @f$v_i@f$ is the value of the input variable @f$i@f$ registered
+ in the Linear::getEngine()
+ @param x is not utilized
+ @return @f$\sum_i c_ix_i +k@f$
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the vector @f$\mathbf{c}^\star@f$ and the Engine from which
+ vector @f$\mathbf{v}@f$ will be retrieved when necessary
+ @param coefficients is the vector @f$\mathbf{c}^\star@f$
+ @param engine is the engine from which @f$\mathbf{v}@f$ will be
+ retrieved when necessary
+ */
+ virtual void set(const std::vector<scalar>& coefficients, const Engine* engine);
+
+ /**
+ Sets the vector @f$\mathbf{c}^\star@f$ of the linear function
+ @param coefficients is the vector @f$\mathbf{c}^\star@f$
+ */
+ virtual void setCoefficients(const std::vector<scalar>& coefficients);
+ /**
+ Gets the immutable vector @f$\mathbf{c}^\star@f$
+ @return the immutable vector @f$\mathbf{c}^\star@f$
+ */
+ virtual const std::vector<scalar>& coefficients() const;
+ /**
+ Gets the mutable vector @f$\mathbf{c}^\star@f$
+ @return the mutable vector @f$\mathbf{c}^\star@f$
+ */
+ virtual std::vector<scalar>& coefficients();
+
+ /**
+ Sets the engine from which the vector @f$\mathbf{v}@f$ will be
+ obtained upon computing the Linear::membership()
+ @param engine is the engine from which the vector @f$\mathbf{v}@f$
+ will be obtained
+ */
+ virtual void setEngine(const Engine* engine);
+ /**
+ Gets the engine from which the vector @f$\mathbf{v}@f$ will be
+ obtained upon computing the Linear::membership()
+ @return the engine from which the vector @f$\mathbf{v}@f$ will be
+ obtained
+ */
+ virtual const Engine* getEngine() const;
+
+ virtual Linear* clone() const FL_IOVERRIDE;
+
+ virtual void updateReference(const Engine* engine) FL_IOVERRIDE;
+
+ static Term* constructor();
+
+ /**
+ Creates a Linear term from a variadic set of coefficients.
+ Beware: this method is unsafe and must be used with care by
+ ensuring:
+
+ - the data type of each variadic arguments is the same, e.g.,
+ @f$(1.0, 2.0, 3.0)@f$ are all fl::scalar%s. You *need* to avoid the
+ case of @f$(1.0, 2, 3.0)@f$, where the second term will be
+ considered as an `int` (different from the others) and cause memory
+ issues due to the difference in size between an `int` and
+ `fl::scalar`; and
+
+ - the number of variadic arguments is exactly the same as the number
+ of input variables in the engine plus one in order to match the
+ size of the vector @f$\mathbf{c}^\star@f$
+
+ @param name is the name of the term
+ @param engine is the engine from which the vector @f$\mathbf{v}@f$
+ will be obtained
+ @param firstCoefficient is the coefficient for the first input
+ variable, namely @f$c_1@f$
+ @param ... is a variadic number of coefficients whose type need to be
+ the same as the first coefficient
+ @return a new Linear term with the given parameters
+ */
+ template <typename T>
+ static Linear* create(const std::string& name, const Engine* engine,
+ T firstCoefficient, ...);
+ };
+}
+
+/**
+ Template implementation
+ */
+
+#include "fl/Engine.h"
+
+namespace fl {
+
+ template <typename T>
+ inline Linear* Linear::create(const std::string& name,
+ const Engine* engine, T firstCoefficient, ...) {
+ if (not engine) throw Exception("[linear error] cannot create term <" + name + "> "
+ "without a reference to the engine", FL_AT);
+ std::vector<scalar> coefficients;
+ coefficients.push_back((scalar) firstCoefficient);
+
+ va_list args;
+ va_start(args, firstCoefficient);
+ for (std::size_t i = 0; i < engine->inputVariables().size(); ++i) {
+ coefficients.push_back((scalar) va_arg(args, T));
+ }
+ va_end(args);
+
+ return new Linear(name, coefficients, engine);
+ }
+}
+#endif /* FL_LINEAR_H */
+
diff --git a/fuzzylite/fl/term/PiShape.h b/fuzzylite/fl/term/PiShape.h
new file mode 100644
index 0000000..24e98ed
--- /dev/null
+++ b/fuzzylite/fl/term/PiShape.h
@@ -0,0 +1,137 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_PISHAPE_H
+#define FL_PISHAPE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The PiShape class is an extended Term that represents the Pi-shaped curve
+ membership function.
+
+ @image html piShape.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API PiShape : public Term {
+ private:
+ scalar _bottomLeft;
+ scalar _topLeft;
+ scalar _topRight;
+ scalar _bottomRight;
+
+ public:
+ explicit PiShape(const std::string& name = "",
+ scalar bottomLeft = fl::nan,
+ scalar topLeft = fl::nan,
+ scalar topRight = fl::nan,
+ scalar bottomRight = fl::nan,
+ scalar height = 1.0);
+ virtual ~PiShape() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(PiShape)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"bottomLeft topLeft topRight bottomRight [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"bottomLeft topLeft topRight bottomRight
+ [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 0h & \mbox{if $x \leq b_l$}\cr
+ 2h \left((x - b_l) / (t_l-b_l)\right)^2 & \mbox{if $x \leq 0.5(a+b)$}\cr
+ h (1 - 2 \left((x - t_l) / (t_l-b_l)\right)^2) & \mbox{if $ x < t_l$}\cr
+ h & \mbox{if $x \leq t_r$}\cr
+ h (1 - 2\left((x - t_r) / (b_r - t_r)\right)^2) & \mbox{if $x \leq 0.5(t_r + b_r)$}\cr
+ 2h \left((x - b_r) / (b_r-t_r)\right)^2 & \mbox{if $x < b_r$} \cr
+ 0h & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$b_l@f$ is the bottom left of the PiShape,
+ @f$t_l@f$ is the top left of the PiShape,
+ @f$t_r@f$ is the top right of the PiShape
+ @f$b_r@f$ is the bottom right of the PiShape,
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the bottom-left value of the curve
+ @param bottomLeft is the bottom-left value of the curve
+ */
+ virtual void setBottomLeft(scalar bottomLeft);
+ /**
+ Gets the bottom-left value of the curve
+ @return the bottom-left value of the curve
+ */
+ virtual scalar getBottomLeft() const;
+
+ /**
+ Sets the top-left value of the curve
+ @param topLeft is the top-left value of the curve
+ */
+ virtual void setTopLeft(scalar topLeft);
+ /**
+ Gets the top-left value of the curve
+ @return the top-left value of the curve
+ */
+ virtual scalar getTopLeft() const;
+
+ /**
+ Sets the top-right value of the curve
+ @param topRight is the top-right value of the curve
+ */
+ virtual void setTopRight(scalar topRight);
+ /**
+ Gets the top-right value of the curve
+ @return the top-right value of the curve
+ */
+ virtual scalar getTopRight() const;
+
+ /**
+ Sets the bottom-right value of the curve
+ @param bottomRight is the bottom-right value of the curve
+ */
+ virtual void setBottomRight(scalar bottomRight);
+ /**
+ Gets the bottom-right value of the curve
+ @return the bottom-right value of the curve
+ */
+ virtual scalar getBottomRight() const;
+
+ virtual PiShape* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_PISHAPE_H */
+
diff --git a/fuzzylite/fl/term/Ramp.h b/fuzzylite/fl/term/Ramp.h
new file mode 100644
index 0000000..dc49301
--- /dev/null
+++ b/fuzzylite/fl/term/Ramp.h
@@ -0,0 +1,135 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_RAMP_H
+#define FL_RAMP_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Ramp class is an edge Term that represents the ramp membership
+ function.
+
+ @image html ramp.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Ramp : public Term {
+ private:
+ scalar _start, _end;
+
+ public:
+
+ /**
+ Direction is an enumerator that indicates the direction of the ramp.
+ */
+ enum Direction {
+ /** `(_/)` increases to the right */ Positive,
+ /** `(--)` slope is zero */ Zero,
+ /** `(\\_)` increases to the left */ Negative
+ };
+ explicit Ramp(const std::string& name = "",
+ scalar start = fl::nan,
+ scalar end = fl::nan,
+ scalar height = 1.0);
+ virtual ~Ramp() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Ramp)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"start end [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"start end [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return
+ @f$\begin{cases}
+
+ 0h & \mbox{if $x = e$}\cr
+
+ \begin{cases}
+ 0h & \mbox{if $x \leq s$}\cr
+ 1h & \mbox{if $x \geq e$}\cr
+ h (x - s) / (e - s) & \mbox{otherwise}\cr
+ \end{cases} & \mbox{if $s < e$}\cr
+
+ \begin{cases}
+ 0h & \mbox{if $x \geq s$}\cr
+ 1h & \mbox{if $x \leq e$}\cr
+ h (s - x) / (s - e) & \mbox{otherwise}
+ \end{cases} & \mbox{if $s > e$}\cr
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$s@f$ is the start of the Ramp,
+ @f$e@f$ is the end of the Ramp
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ virtual scalar tsukamoto(scalar activationDegree,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+
+ virtual bool isMonotonic() const FL_IOVERRIDE;
+
+ /**
+ Sets the start of the ramp
+ @param start is the start of the ramp
+ */
+ virtual void setStart(scalar start);
+ /**
+ Gets the start of the ramp
+ @return the start of the ramp
+ */
+ virtual scalar getStart() const;
+
+ /**
+ Sets the end of the ramp
+ @param end is the end of the ramp
+ */
+ virtual void setEnd(scalar end);
+ /**
+ Gets the end of the ramp
+ @return the end of the ramp
+ */
+ virtual scalar getEnd() const;
+
+ /**
+ Returns the direction of the ramp
+ @return the direction of the ramp
+ */
+ virtual Direction direction() const;
+
+ virtual Ramp* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_RAMP_H */
+
diff --git a/fuzzylite/fl/term/Rectangle.h b/fuzzylite/fl/term/Rectangle.h
new file mode 100644
index 0000000..0e29cd2
--- /dev/null
+++ b/fuzzylite/fl/term/Rectangle.h
@@ -0,0 +1,102 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_RECTANGLE_H
+#define FL_RECTANGLE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Rectangle class is a basic Term that represents the rectangle
+ membership function.
+
+ @image html rectangle.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Rectangle : public Term {
+ private:
+ scalar _start, _end;
+
+ public:
+ explicit Rectangle(const std::string& name = "",
+ scalar start = fl::nan,
+ scalar end = fl::nan,
+ scalar height = 1.0);
+ virtual ~Rectangle() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Rectangle)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"start end [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"start end [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 1h & \mbox{if $x \in [s, e]$} \cr
+ 0h & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$s@f$ is the start of the Rectangle,
+ @f$e@f$ is the end of the Rectangle.
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the start of the rectangle
+ @param start is the start of the rectangle
+ */
+ virtual void setStart(scalar start);
+ /**
+ Gets the start of the rectangle
+ @return the start of the rectangle
+ */
+ virtual scalar getStart() const;
+
+ /**
+ Sets the end of the rectangle
+ @param end is the end of the rectangle
+ */
+ virtual void setEnd(scalar end);
+ /**
+ Gets the end of the rectangle
+ @return the end of the rectangle
+ */
+ virtual scalar getEnd() const;
+
+ virtual Rectangle* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_RECTANGLE_H */
diff --git a/fuzzylite/fl/term/SShape.h b/fuzzylite/fl/term/SShape.h
new file mode 100644
index 0000000..1d107a5
--- /dev/null
+++ b/fuzzylite/fl/term/SShape.h
@@ -0,0 +1,109 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SSHAPE_H
+#define FL_SSHAPE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The SShape class is an edge Term that represents the S-shaped membership
+ function.
+
+ @image html sShape.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API SShape : public Term {
+ private:
+ scalar _start, _end;
+
+ public:
+ explicit SShape(const std::string& name = "",
+ scalar start = fl::nan,
+ scalar end = fl::nan,
+ scalar height = 1.0);
+ virtual ~SShape() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(SShape)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"start end [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"start end [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 0h & \mbox{if $x \leq s$} \cr
+ h(2 \left((x - s) / (e-s)\right)^2) & \mbox{if $x \leq 0.5(s+e)$}\cr
+ h(1 - 2\left((x - e) / (e-s)\right)^2) & \mbox{if $x < e$}\cr
+ 1h & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$s@f$ is the start of the SShape,
+ @f$e@f$ is the end of the SShape.
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ virtual scalar tsukamoto(scalar activationDegree,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+
+ virtual bool isMonotonic() const FL_IOVERRIDE;
+
+ /**
+ Sets the start of the edge
+ @param start is the start of the edge
+ */
+ virtual void setStart(scalar start);
+ /**
+ Gets the start of the edge
+ @return the start of the edge
+ */
+ virtual scalar getStart() const;
+
+ /**
+ Sets the end of the edge
+ @param end is the end of the edge
+ */
+ virtual void setEnd(scalar end);
+ /**
+ Gets the end of the edge
+ @return the end of the edge
+ */
+ virtual scalar getEnd() const;
+
+ virtual SShape* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_SSHAPE_H */
+
diff --git a/fuzzylite/fl/term/Sigmoid.h b/fuzzylite/fl/term/Sigmoid.h
new file mode 100644
index 0000000..bde9c2f
--- /dev/null
+++ b/fuzzylite/fl/term/Sigmoid.h
@@ -0,0 +1,120 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SIGMOID_H
+#define FL_SIGMOID_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Sigmoid class is an edge Term that represents the sigmoid membership
+ function.
+
+ @image html sigmoid.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Sigmoid : public Term {
+ private:
+ scalar _inflection;
+ scalar _slope;
+ public:
+
+ /**
+ Direction is an enumerator that indicates the direction of the
+ sigmoid.
+ */
+ enum Direction {
+ /** `(_/)` increases to the right */ Positive,
+ /** `(--)` slope is zero */ Zero,
+ /** `(\\_)` increases to the left */ Negative
+ };
+ explicit Sigmoid(const std::string& name = "",
+ scalar inflection = fl::nan,
+ scalar slope = fl::nan,
+ scalar height = 1.0);
+ virtual ~Sigmoid() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Sigmoid)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"inflection slope [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"inflection slope [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$ h / (1 + \exp(-s(x-i)))@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$s@f$ is the slope of the Sigmoid,
+ @f$i@f$ is the inflection of the Sigmoid
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ virtual scalar tsukamoto(scalar activationDegree,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+
+ virtual bool isMonotonic() const FL_IOVERRIDE;
+
+ /**
+ Sets the inflection of the sigmoid
+ @param inflection is the inflection of the sigmoid
+ */
+ virtual void setInflection(scalar inflection);
+ /**
+ Gets the inflection of the sigmoid
+ @return the inflection of the sigmoid
+ */
+ virtual scalar getInflection() const;
+
+ /**
+ Sets the slope of the sigmoid
+ @param slope is the slope of the sigmoid
+ */
+ virtual void setSlope(scalar slope);
+ /**
+ Gets the slope of the sigmoid
+ @return the slope of the sigmoid
+ */
+ virtual scalar getSlope() const;
+
+ /**
+ Returns the direction of the sigmoid
+ @return the direction of the sigmoid
+ */
+ virtual Direction direction() const;
+
+ virtual Sigmoid* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_SIGMOID_H */
diff --git a/fuzzylite/fl/term/SigmoidDifference.h b/fuzzylite/fl/term/SigmoidDifference.h
new file mode 100644
index 0000000..4861584
--- /dev/null
+++ b/fuzzylite/fl/term/SigmoidDifference.h
@@ -0,0 +1,131 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SIGMOIDDIFFERENCE_H
+#define FL_SIGMOIDDIFFERENCE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The SigmoidDifference class is an extended Term that represents the
+ difference between two sigmoidal membership functions.
+
+ @image html sigmoidDifference.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API SigmoidDifference : public Term {
+ private:
+ scalar _left;
+ scalar _rising;
+ scalar _falling;
+ scalar _right;
+
+ public:
+ explicit SigmoidDifference(const std::string& name = "",
+ scalar left = fl::nan,
+ scalar rising = fl::nan,
+ scalar falling = fl::nan,
+ scalar right = fl::nan,
+ scalar height = 1.0);
+ virtual ~SigmoidDifference() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(SigmoidDifference)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"left rising falling right [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"left rising falling right [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$ h (a-b)@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$a= 1 / (1 + \exp(-s_l \times (x - i_l))) @f$,
+ @f$b = 1 / (1 + \exp(-s_r \times (x - i_r)))@f$,
+ @f$i_l@f$ is the left inflection of the SigmoidDifference,
+ @f$s_l@f$ is the left slope of the SigmoidDifference,
+ @f$i_r@f$ is the right inflection of the SigmoidDifference,
+ @f$s_r@f$ is the right slope of the SigmoidDifference
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the inflection of the left sigmoidal curve
+ @param leftInflection is the inflection of the left sigmoidal curve
+ */
+ virtual void setLeft(scalar leftInflection);
+ /**
+ Gets the inflection of the left sigmoidal curve
+ @return the inflection of the left sigmoidal curve
+ */
+ virtual scalar getLeft() const;
+
+ /**
+ Sets the slope of the left sigmoidal curve
+ @param risingSlope is the slope of the left sigmoidal curve
+ */
+ virtual void setRising(scalar risingSlope);
+ /**
+ Gets the slope of the left sigmoidal curve
+ @return the slope of the left sigmoidal curve
+ */
+ virtual scalar getRising() const;
+
+ /**
+ Sets the slope of the right sigmoidal curve
+ @param fallingSlope is the slope of the right sigmoidal curve
+ */
+ virtual void setFalling(scalar fallingSlope);
+ /**
+ Gets the slope of the right sigmoidal curve
+ @return the slope of the right sigmoidal curve
+ */
+ virtual scalar getFalling() const;
+
+ /**
+ Sets the inflection of the right sigmoidal curve
+ @param rightInflection is the inflection of the right sigmoidal curve
+ */
+ virtual void setRight(scalar rightInflection);
+ /**
+ Gets the inflection of the right sigmoidal curve
+ @return the inflection of the right sigmoidal curve
+ */
+ virtual scalar getRight() const;
+
+ virtual SigmoidDifference* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_SIGMOIDDIFFERENCE_H */
+
diff --git a/fuzzylite/fl/term/SigmoidProduct.h b/fuzzylite/fl/term/SigmoidProduct.h
new file mode 100644
index 0000000..19cd4d7
--- /dev/null
+++ b/fuzzylite/fl/term/SigmoidProduct.h
@@ -0,0 +1,132 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SIGMOIDPRODUCT_H
+#define FL_SIGMOIDPRODUCT_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The SigmoidProduct class is an extended Term that represents the product
+ of two sigmoidal membership functions.
+
+ @image html sigmoidProduct.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API SigmoidProduct : public Term {
+ private:
+ scalar _left;
+ scalar _rising;
+ scalar _falling;
+ scalar _right;
+
+ public:
+ explicit SigmoidProduct(const std::string& name = "",
+ scalar left = fl::nan,
+ scalar rising = fl::nan,
+ scalar falling = fl::nan,
+ scalar right = fl::nan,
+ scalar height = 1.0);
+ virtual ~SigmoidProduct() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(SigmoidProduct)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"left rising falling right [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"left rising falling right [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$ h (a \times b)@f$
+
+ where @f$h@f$ is the height,
+ @f$a= 1 / (1 + \exp(-s_l *\times (x - i_l))) @f$,
+ @f$b = 1 / (1 + \exp(-s_r \times (x - i_r)))@f$,
+ @f$i_l@f$ is the left inflection of the SigmoidProduct,
+ @f$s_l@f$ is the left slope of the SigmoidProduct,
+ @f$i_r@f$ is the right inflection of the SigmoidProduct,
+ @f$s_r@f$ is the right slope of the SigmoidProduct
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the inflection of the left sigmoidal curve
+ @param leftInflection is the inflection of the left sigmoidal curve
+ */
+ virtual void setLeft(scalar leftInflection);
+ /**
+ Gets the inflection of the left sigmoidal curve
+ @return the inflection of the left sigmoidal curve
+ */
+ virtual scalar getLeft() const;
+
+ /**
+ Sets the slope of the left sigmoidal curve
+ @param risingSlope is the slope of the left sigmoidal curve
+ */
+ virtual void setRising(scalar risingSlope);
+ /**
+ Gets the slope of the left sigmoidal curve
+ @return the slope of the left sigmoidal curve
+ */
+ virtual scalar getRising() const;
+
+ /**
+ Sets the slope of the right sigmoidal curve
+ @param fallingSlope is the slope of the right sigmoidal curve
+ */
+ virtual void setFalling(scalar fallingSlope);
+ /**
+ Gets the slope of the right sigmoidal curve
+ @return the slope of the right sigmoidal curve
+ */
+ virtual scalar getFalling() const;
+
+ /**
+ Sets the inflection of the right sigmoidal curve
+ @param rightInflection is the inflection of the right sigmoidal curve
+ */
+ virtual void setRight(scalar rightInflection);
+ /**
+ Gets the inflection of the right sigmoidal curve
+ @return the inflection of the right sigmoidal curve
+ */
+ virtual scalar getRight() const;
+
+
+ virtual SigmoidProduct* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_SIGMOIDPRODUCT_H */
+
diff --git a/fuzzylite/fl/term/Spike.h b/fuzzylite/fl/term/Spike.h
new file mode 100644
index 0000000..7349307
--- /dev/null
+++ b/fuzzylite/fl/term/Spike.h
@@ -0,0 +1,98 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_SPIKE_H
+#define FL_SPIKE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Spike class is an extended Term that represents the spike membership
+ function.
+
+ @image html spike.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 5.0
+ */
+ class FL_API Spike : public Term {
+ private:
+ scalar _center, _width;
+ public:
+ explicit Spike(const std::string& name = "",
+ scalar center = fl::nan,
+ scalar width = fl::nan,
+ scalar height = 1.0);
+ virtual ~Spike() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Spike)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"center width [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"center width [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$h \times \exp(-|10 / w (x - c)|)@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$w@f$ is the width of the Spike,
+ @f$c@f$ is the center of the Spike
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the center of the spike
+ @param center is the center of the spike
+ */
+ virtual void setCenter(scalar center);
+ /**
+ Gets the center of the spike
+ @return the center of the spike
+ */
+ virtual scalar getCenter() const;
+
+ /**
+ Sets the width of the spike
+ @param width is the width of the spike
+ */
+ virtual void setWidth(scalar width);
+ /**
+ Gets the width of the spike
+ @return the width of the spike
+ */
+ virtual scalar getWidth() const;
+
+ virtual Spike* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_SPIKE_H */
+
diff --git a/fuzzylite/fl/term/Term.h b/fuzzylite/fl/term/Term.h
new file mode 100644
index 0000000..31dcabd
--- /dev/null
+++ b/fuzzylite/fl/term/Term.h
@@ -0,0 +1,165 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TERM_H
+#define FL_TERM_H
+
+#include "fl/fuzzylite.h"
+
+#include "fl/Operation.h"
+#include "fl/Complexity.h"
+
+#include <cmath>
+#include <string>
+#include <vector>
+
+namespace fl {
+ class Engine;
+
+ /**
+ The Term class is the abstract class for linguistic terms. The linguistic
+ terms in this library can be divided in four groups as: `basic`,
+ `extended`, `edge`, and `function`. The `basic` terms are Triangle,
+ Trapezoid, Rectangle, and Discrete. The `extended` terms are Bell,
+ Binary, Cosine, Gaussian, GaussianProduct, PiShape, SigmoidDifference,
+ SigmoidProduct, and Spike. The `edge` terms are Concave, Ramp, Sigmoid,
+ SShape, and ZShape. The `function` terms are Constant, Linear, and
+ Function.
+
+ In the figure below, the `basic` terms are represented in the first
+ column, and the `extended` terms in the second and third columns. The
+ `edge` terms are represented in the fifth and sixth rows, and the
+ `function` terms in the last row.
+
+ @image html terms.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Variable
+ @see InputVariable
+ @see OutputVariable
+ @since 4.0
+ */
+ class FL_API Term {
+ private:
+ std::string _name;
+ protected:
+ scalar _height;
+ public:
+
+ explicit Term(const std::string& name = "", scalar height = 1.0);
+ virtual ~Term();
+ FL_DEFAULT_COPY_AND_MOVE(Term)
+
+ /**
+ Sets the name of the term
+ @param name is the name of term
+ */
+ virtual void setName(const std::string& name);
+ /**
+ Gets the name of the term
+ @return the name of the term
+ */
+ virtual std::string getName() const;
+
+ /**
+ Sets the height of the term
+ @param height is the height of the term
+ */
+ virtual void setHeight(scalar height);
+ /**
+ Gets the height of the term
+ @return the height of the term
+ */
+ virtual scalar getHeight() const;
+
+ /**
+ Returns the representation of the term in the FuzzyLite Language
+ @return the representation of the term in FuzzyLite Language
+ @see FllExporter
+ */
+ virtual std::string toString() const;
+
+ /**
+ Returns the name of the class of the term
+ @return the name of the class of the term
+ */
+ virtual std::string className() const = 0;
+ /**
+ Returns the parameters to configure the term. The parameters are
+ separated by spaces. If there is one additional parameter, the
+ parameter will be considered as the height of the term; otherwise,
+ the height will be set to @f$1.0@f$
+ @return the parameters to configure the term (@see Term::configure())
+ */
+ virtual std::string parameters() const = 0;
+ /**
+ Configures the term with the given parameters. The parameters are
+ separated by spaces. If there is one additional parameter, the
+ parameter will be considered as the height of the term; otherwise,
+ the height will be set to @f$1.0@f$
+ @param parameters is the parameters to configure the term
+ */
+ virtual void configure(const std::string& parameters) = 0;
+
+ /**
+ Computes the estimated complexity of evaluating the membership function
+ @return the estimated complexity of evaluating the membership function
+ */
+ virtual Complexity complexity() const = 0;
+
+ /**
+ Computes the membership function value at @f$x@f$
+ @param x
+ @return the membership function value @f$\mu(x)@f$
+ */
+ virtual scalar membership(scalar x) const = 0;
+
+ /**
+ Creates a clone of the term
+ @return a clone of the term
+ */
+ virtual Term* clone() const = 0;
+
+ /**
+ Updates the references (if any) to point to the current engine (useful
+ when cloning engines or creating terms within Importer objects
+ @param engine is the engine to which this term belongs to
+ */
+ virtual void updateReference(const Engine* engine);
+
+ /**
+ For monotonic terms, computes the tsukamoto value of the term for the
+ given activation degree @f$\alpha@f$, that is,
+ @f$ g_j(\alpha) = \{ z \in\mathbb{R} : \mu_j(z) = \alpha \} $@f. If
+ the term is not monotonic (or does not override this method) the
+ method computes the membership function @f$\mu(\alpha)@f$.
+ @param activationDegree is the activationDegree
+ @param minimum is the minimum value of the range of the term
+ @param maximum is the maximum value of the range of the term
+ @return the tsukamoto value of the term for the given activation degree
+ if the term is monotonic (or overrides this method), or
+ the membership function for the activation degree otherwise.
+ */
+ virtual scalar tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const;
+
+ /**
+ Indicates whether the term is monotonic.
+ @return whether the term is monotonic.
+ */
+ virtual bool isMonotonic() const;
+ };
+}
+#endif /* FL_TERM_H */
diff --git a/fuzzylite/fl/term/Trapezoid.h b/fuzzylite/fl/term/Trapezoid.h
new file mode 100644
index 0000000..ebf5ed8
--- /dev/null
+++ b/fuzzylite/fl/term/Trapezoid.h
@@ -0,0 +1,129 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TRAPEZOID_H
+#define FL_TRAPEZOID_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Trapezoid class is a basic Term that represents the trapezoidal
+ membership function.
+
+ @image html trapezoid.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Trapezoid : public Term {
+ private:
+ scalar _vertexA, _vertexB, _vertexC, _vertexD;
+ public:
+ explicit Trapezoid(const std::string& name = "",
+ scalar vertexA = fl::nan,
+ scalar vertexB = fl::nan,
+ scalar vertexC = fl::nan,
+ scalar vertexD = fl::nan,
+ scalar height = 1.0);
+ virtual ~Trapezoid() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Trapezoid)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"vertexA vertexB vertexC vertexD [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"vertexA vertexB vertexC vertexD [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 0h & \mbox{if $x \not\in[a,d]$}\cr
+ h \times \min(1, (x - a) / (b - a)) & \mbox{if $x < b$}\cr
+ 1h & \mbox{if $x \leq c$}\cr
+ h (d - x) / (d - c) & \mbox{if $x < d$}\cr
+ 0h & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$a@f$ is the first vertex of the Trapezoid,
+ @f$b@f$ is the second vertex of the Trapezoid,
+ @f$c@f$ is the third vertex of the Trapezoid,
+ @f$d@f$ is the fourth vertex of the Trapezoid
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the first vertex of the trapezoid
+ @param a is the first vertex of the trapezoid
+ */
+ virtual void setVertexA(scalar a);
+ /**
+ Gets the first vertex of the trapezoid
+ @return the first vertex of the trapezoid
+ */
+ virtual scalar getVertexA() const;
+
+ /**
+ Sets the second vertex of the trapezoid
+ @param b is the second vertex of the trapezoid
+ */
+ virtual void setVertexB(scalar b);
+ /**
+ Gets the second vertex of the trapezoid
+ @return the second vertex of the trapezoid
+ */
+ virtual scalar getVertexB() const;
+
+ /**
+ Sets the third vertex of the trapezoid
+ @param c is the third vertex of the trapezoid
+ */
+ virtual void setVertexC(scalar c);
+ /**
+ Gets the third vertex of the trapezoid
+ @return the third vertex of the trapezoid
+ */
+ virtual scalar getVertexC() const;
+
+ /**
+ Sets the fourth vertex of the trapezoid
+ @param d is the fourth vertex of the trapezoid
+ */
+ virtual void setVertexD(scalar d);
+ /**
+ Gets the fourth vertex of the trapezoid
+ @return the fourth vertex of the trapezoid
+ */
+ virtual scalar getVertexD() const;
+
+ virtual Trapezoid* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+ };
+}
+#endif /* FL_TRAPEZOID_H */
diff --git a/fuzzylite/fl/term/Triangle.h b/fuzzylite/fl/term/Triangle.h
new file mode 100644
index 0000000..8b16fa9
--- /dev/null
+++ b/fuzzylite/fl/term/Triangle.h
@@ -0,0 +1,118 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_TRIANGLE_H
+#define FL_TRIANGLE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The Triangle class is a basic Term that represents the triangular
+ membership function.
+
+ @image html triangle.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+ class FL_API Triangle : public Term {
+ private:
+ scalar _vertexA;
+ scalar _vertexB;
+ scalar _vertexC;
+ public:
+ explicit Triangle(const std::string& name = "",
+ scalar vertexA = fl::nan,
+ scalar vertexB = fl::nan,
+ scalar vertexC = fl::nan,
+ scalar height = 1.0);
+ virtual ~Triangle() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(Triangle)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"vertexA vertexB vertexC [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"vertexA vertexB vertexC [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$\begin{cases}
+ 0h & \mbox{if $x \not\in [a,c]$}\cr
+ 1h & \mbox{if $x = b$}\cr
+ h (x - a) / (b - a) & \mbox{if $x < b$} \cr
+ h (c - x) / (c - b) & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$a@f$ is the first vertex of the Triangle,
+ @f$b@f$ is the second vertex of the Triangle,
+ @f$c@f$ is the third vertex of the Triangle
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ /**
+ Sets the first vertex of the triangle
+ @param a is the first vertex of the triangle
+ */
+ virtual void setVertexA(scalar a);
+ /**
+ Gets the first vertex of the triangle
+ @return the first vertex of the triangle
+ */
+ virtual scalar getVertexA() const;
+
+ /**
+ Sets the second vertex of the triangle
+ @param b is the second vertex of the triangle
+ */
+ virtual void setVertexB(scalar b);
+ /**
+ Gets the second vertex of the triangle
+ @return the second vertex of the triangle
+ */
+ virtual scalar getVertexB() const;
+
+ /**
+ Sets the third vertex of the triangle
+ @param c is the third vertex of the triangle
+ */
+ virtual void setVertexC(scalar c);
+ /**
+ Gets the third vertex of the triangle
+ @return the third vertex of the triangle
+ */
+ virtual scalar getVertexC() const;
+
+ virtual Triangle* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+
+ };
+}
+#endif /* FL_TRIANGLE_H */
diff --git a/fuzzylite/fl/term/ZShape.h b/fuzzylite/fl/term/ZShape.h
new file mode 100644
index 0000000..1737891
--- /dev/null
+++ b/fuzzylite/fl/term/ZShape.h
@@ -0,0 +1,111 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_ZSHAPE_H
+#define FL_ZSHAPE_H
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ /**
+ The ZShape class is an edge Term that represents the Z-shaped membership
+ function.
+
+ @image html zShape.svg
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Term
+ @see Variable
+ @since 4.0
+ */
+
+ class FL_API ZShape : public Term {
+ private:
+ scalar _start, _end;
+
+ public:
+ explicit ZShape(const std::string& name = "",
+ scalar _start = fl::nan,
+ scalar _end = fl::nan,
+ scalar _height = 1.0);
+ virtual ~ZShape() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(ZShape)
+
+ virtual std::string className() const FL_IOVERRIDE;
+ /**
+ Returns the parameters of the term
+ @return `"start end [height]"`
+ */
+ virtual std::string parameters() const FL_IOVERRIDE;
+ /**
+ Configures the term with the parameters
+ @param parameters as `"start end [height]"`
+ */
+ virtual void configure(const std::string& parameters) FL_IOVERRIDE;
+
+ virtual Complexity complexity() const FL_IOVERRIDE;
+ /**
+ Computes the membership function evaluated at @f$x@f$
+ @param x
+ @return @f$ \begin{cases}
+ 1h & \mbox{if $x \leq s$} \cr
+ h(1 - 2\left((x - s) / (e-s)\right)^2) & \mbox{if $x \leq 0.5(s+e)$}\cr
+ h(2 \left((x - e) / (e-s)\right)^2) & \mbox{if $x < e$}\cr
+ 0h & \mbox{otherwise}
+ \end{cases}@f$
+
+ where @f$h@f$ is the height of the Term,
+ @f$s@f$ is the start of the ZShape,
+ @f$e@f$ is the end of the ZShape.
+ */
+ virtual scalar membership(scalar x) const FL_IOVERRIDE;
+
+ virtual scalar tsukamoto(scalar activationDegree,
+ scalar minimum, scalar maximum) const FL_IOVERRIDE;
+
+ virtual bool isMonotonic() const FL_IOVERRIDE;
+
+ /**
+ Sets the start of the edge
+ @param start is the start of the edge
+ */
+ virtual void setStart(scalar start);
+ /**
+ Gets the start of the edge
+ @return the start of the edge
+ */
+ virtual scalar getStart() const;
+
+ /**
+ Sets the end of the edge
+ @param end is the end of the edge
+ */
+ virtual void setEnd(scalar end);
+ /**
+ Gets the end of the edge
+ @return the end of the edge
+ */
+ virtual scalar getEnd() const;
+
+ virtual ZShape* clone() const FL_IOVERRIDE;
+
+ static Term* constructor();
+
+ };
+}
+#endif /* ZSHAPE_H */
+
diff --git a/fuzzylite/fl/variable/InputVariable.h b/fuzzylite/fl/variable/InputVariable.h
new file mode 100644
index 0000000..3201e3d
--- /dev/null
+++ b/fuzzylite/fl/variable/InputVariable.h
@@ -0,0 +1,60 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_INPUTVARIABLE_H
+#define FL_INPUTVARIABLE_H
+
+#include "fl/variable/Variable.h"
+
+namespace fl {
+
+ /**
+ The InputVariable class is a Variable that represents an input of the
+ fuzzy logic controller.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Variable
+ @see OutputVariable
+ @see Term
+ @since 4.0
+ */
+ class FL_API InputVariable : public Variable {
+ public:
+ explicit InputVariable(const std::string& name = "",
+ scalar minimum = -fl::inf,
+ scalar maximum = fl::inf);
+ virtual ~InputVariable() FL_IOVERRIDE;
+ FL_DEFAULT_COPY_AND_MOVE(InputVariable)
+
+ /**
+ Evaluates the membership function of the current input value @f$x@f$
+ for each term @f$i@f$, resulting in a fuzzy input value in the form
+ @f$\tilde{x}=\sum_i{\mu_i(x)/i}@f$. This is equivalent to a call to
+ Variable::fuzzify() passing @f$x@f$ as input value
+
+ @return the fuzzy input value expressed as @f$\sum_i{\mu_i(x)/i}@f$
+ */
+ virtual std::string fuzzyInputValue() const;
+
+ virtual Variable::Type type() const FL_IOVERRIDE;
+
+ virtual std::string toString() const FL_IOVERRIDE;
+
+ virtual InputVariable* clone() const FL_IOVERRIDE;
+
+ };
+}
+#endif /* FL_INPUTVARIABLE_H */
diff --git a/fuzzylite/fl/variable/OutputVariable.h b/fuzzylite/fl/variable/OutputVariable.h
new file mode 100644
index 0000000..b79b13c
--- /dev/null
+++ b/fuzzylite/fl/variable/OutputVariable.h
@@ -0,0 +1,226 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_OUTPUTVARIABLE_H
+#define FL_OUTPUTVARIABLE_H
+
+#include "fl/variable/Variable.h"
+
+#include "fl/term/Activated.h"
+#include "fl/term/Aggregated.h"
+
+#include "fl/defuzzifier/Defuzzifier.h"
+
+namespace fl {
+
+ /**
+ The OutputVariable class is a Variable that represents an output of the
+ fuzzy logic controller. During the activation of a RuleBlock, the
+ Activated terms of each Rule will be Aggregated in the
+ OutputVariable::fuzzyOutput(), which represents a fuzzy set hereinafter
+ referred to as @f$\tilde{y}@f$. The defuzzification of @f$\tilde{y}@f$
+ translates the fuzzy output value @f$\tilde{y}@f$ into a crisp output
+ value @f$y@f$, which can be retrieved using Variable::getValue(). The
+ value of the OutputVariable is computed and automatically stored when
+ calling OutputVariable::defuzzify(), but the value depends on the
+ following properties (expressed in the FuzzyLite Language):
+
+ - Property `default: scalar` overrides the output value @f$y@f$ with
+ the given fl::scalar whenever the defuzzification process results in
+ a non-finite value (i.e., fl::nan and fl::inf). For example,
+ considering `default: 0.0`, if RuleBlock::activate() does not
+ activate any rules whose Consequent contribute to the OutputVariable,
+ then the fuzzy output value is empty, the Defuzzifier does not
+ operate, and hence @f$y=0.0@f$. By default, `default: NaN`. Relevant
+ methods are OutputVariable::getDefaultValue() and
+ OutputVariable::setDefaultValue().
+
+ - Property `lock-previous: boolean`, if enabled, overrides the output
+ value @f$y^t@f$ at time @f$t@f$ with the previously defuzzified valid
+ output value @f$y^{t-1}@f$ if defuzzification process results in a
+ non-finite value (i.e., fl::nan and fl::inf). When enabled, the
+ property takes precedence over `default` if @f$y^{t-1}@f$ is a finite
+ value. By default, `lock-previous: false`, @f$y^{t-1}=\mbox{NaN}@f$
+ for @f$t=0@f$, and @f$y^{t-1}=\mbox{NaN}@f$ when
+ OutputVariable::clear(). Relevant methods are
+ OutputVariable::lockPreviousValue(),
+ OutputVariable::isLockPreviousValue,
+ OutputVariable::getPreviousValue(), and
+ OutputVariable::setPreviousValue().
+
+ - Property `lock-range: boolean` overrides the output value @f$y@f$ to
+ enforce it lies within the range of the variable determined by
+ Variable::getMinimum() and Variable::getMaximum(). When enabled, this
+ property takes precedence over `lock-previous` and `default`. For
+ example, considering `range: -1.0 1.0` and `lock-range: true`,
+ @f$y=-1.0@f$ if the result from the Defuzzifier is smaller than
+ `-1.0`, and @f$y=1.0@f$ if the result from the Defuzzifier is greater
+ than `1.0`. The property `lock-range` was introduced in version 5.0
+ to substitute the property `lock-valid` in version 4.0. By default,
+ `lock-range: false`. Relevant methods are
+ Variable::lockValueInRange(), Variable::isLockValueInRange(),
+ Variable::getMinimum(), and Variable::getMaximum()
+
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see Variable
+ @see InputVariable
+ @see RuleBlock::activate()
+ @see Term
+ @since 4.0
+ */
+ class FL_API OutputVariable : public Variable {
+ private:
+ FL_unique_ptr<Aggregated> _fuzzyOutput;
+ FL_unique_ptr<Defuzzifier> _defuzzifier;
+ scalar _previousValue;
+ scalar _defaultValue;
+ bool _lockPreviousValue;
+
+ void copyFrom(const OutputVariable& other);
+
+ public:
+ explicit OutputVariable(const std::string& name = "",
+ scalar minimum = -fl::inf, scalar maximum = fl::inf);
+ explicit OutputVariable(const OutputVariable& other);
+ OutputVariable& operator=(const OutputVariable& other);
+ virtual ~OutputVariable() FL_IOVERRIDE;
+ FL_DEFAULT_MOVE(OutputVariable)
+
+ /**
+ Gets the fuzzy output value @f$\tilde{y}@f$
+ @return the fuzzy output value @f$\tilde{y}@f$
+ @todo rename to fuzzyValue
+ */
+ virtual Aggregated* fuzzyOutput() const;
+
+ virtual void setName(const std::string& name) FL_IOVERRIDE;
+
+ virtual void setMinimum(scalar minimum) FL_IOVERRIDE;
+ virtual void setMaximum(scalar maximum) FL_IOVERRIDE;
+
+ /**
+ Sets the defuzzifier of the output variable
+ @param defuzzifier is the defuzzifier of the output variable
+ */
+ virtual void setDefuzzifier(Defuzzifier* defuzzifier);
+ /**
+ Gets the defuzzifier of the output variable
+ @return the defuzzifier of the output variable
+ */
+ virtual Defuzzifier* getDefuzzifier() const;
+
+ /**
+ Sets the aggregation operator
+ @param aggregation is the aggregation
+ */
+ virtual void setAggregation(SNorm* aggregation);
+
+ /**
+ Gets the aggregation operator
+ @return the aggregation operator
+ */
+ virtual SNorm* getAggregation() const;
+
+ /**
+ Sets the previous value of the output variable
+ @param previousValue is the previous value of the output variable
+ */
+ virtual void setPreviousValue(scalar previousValue);
+ /**
+ Gets the previous value of the output variable
+ @return the previous value of the output variable
+ */
+ virtual scalar getPreviousValue() const;
+
+ /**
+ Sets the default value of the output variable
+ @param defaultValue is the default value of the output variable
+ */
+ virtual void setDefaultValue(scalar defaultValue);
+ /**
+ Gets the default value of the output variable
+ @return the default value of the output variable
+ */
+ virtual scalar getDefaultValue() const;
+
+ /**
+ Sets whether to lock the previous value of the output variable
+ @param lockPreviousValue indicates whether to lock the previous value
+ of the output variable
+ */
+ virtual void setLockPreviousValue(bool lockPreviousValue);
+ /**
+ Gets whether to lock the previous value of the output variable
+ @return whether the previous output value of the output variable is
+ locked
+ */
+ virtual bool isLockPreviousValue() const;
+
+ using Variable::complexity;
+ /**
+ Computes the estimated complexity of defuzzifying the activated term
+ with the current configuration of the variable (namely aggregation and
+ defuzzifier
+ @param term is the activated term
+ @return the estimated complexity of defuzzifying the activated term
+ with the current configuration of the variable
+ */
+ virtual Complexity complexity(const Activated& term) const;
+ /**
+ Computes the estimated complexity of aggregating and defuzzifying all
+ the terms in the variable.
+ @return the estimated complexity of aggregating and defuzzifying all
+ the terms in the variable.
+ */
+ virtual Complexity complexityOfDefuzzification() const;
+
+ /**
+ Computes the estimated complexity of aggregating and defuzzifying the
+ terms currently found in the fuzzy output variable.
+ @return the estimated complexity of aggregating and defuzzifying the
+ terms currently found in the fuzzy output variable
+ */
+ virtual Complexity currentComplexity() const;
+
+ /**
+ Defuzzifies the output variable and stores the output value and the
+ previous output value
+ */
+ virtual void defuzzify();
+
+ /**
+ Gets a string representation of the fuzzy output value @f$\tilde{y}@f$
+ @return a string representation of the fuzzy output value
+ @f$\tilde{y}@f$
+ */
+ virtual std::string fuzzyOutputValue() const;
+
+ /**
+ Clears the output variable by setting @f$\tilde{y}=\{\}@f$,
+ @f$y^{t}=\mbox{NaN}@f$, @f$y^{t-1}=\mbox{NaN}@f$
+ */
+ virtual void clear();
+
+ virtual Variable::Type type() const FL_IOVERRIDE;
+
+ virtual std::string toString() const FL_IOVERRIDE;
+
+ virtual OutputVariable* clone() const FL_IOVERRIDE;
+
+ };
+}
+#endif /* FL_OUTPUTVARIABLE_H */
diff --git a/fuzzylite/fl/variable/Variable.h b/fuzzylite/fl/variable/Variable.h
new file mode 100644
index 0000000..47530c0
--- /dev/null
+++ b/fuzzylite/fl/variable/Variable.h
@@ -0,0 +1,298 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#ifndef FL_VARIABLE_H
+#define FL_VARIABLE_H
+
+#include "fl/fuzzylite.h"
+#include "fl/defuzzifier/Centroid.h"
+
+#include <string>
+#include <vector>
+
+namespace fl {
+
+ class Term;
+
+ /**
+ The Variable class is the base class for linguistic variables.
+
+ @author Juan Rada-Vilela, Ph.D.
+ @see InputVariable
+ @see OutputVariable
+ @see Term
+ @since 4.0
+ */
+ class FL_API Variable {
+ public:
+
+ /**
+ Indicates the type of the variable to avoid costly `dynamic_casts`
+ */
+ enum Type {
+ None,
+ Input,
+ Output
+ };
+ protected:
+ std::string _name;
+ std::string _description;
+ std::vector<Term*> _terms;
+ scalar _value;
+ scalar _minimum, _maximum;
+ bool _enabled;
+ bool _lockValueInRange;
+
+ private:
+ void copyFrom(const Variable& source);
+
+ public:
+ explicit Variable(const std::string& name = "",
+ scalar minimum = -fl::inf,
+ scalar maximum = fl::inf);
+ explicit Variable(const Variable& other);
+ Variable& operator=(const Variable& other);
+ virtual ~Variable();
+ FL_DEFAULT_MOVE(Variable)
+
+ /**
+ Sets the name of the variable
+ @param name is the name of the variable
+ */
+ virtual void setName(const std::string& name);
+
+ /**
+ Gets the name of the variable
+ @return the name of the variable
+ */
+ virtual std::string getName() const;
+
+ /**
+ Gets the description of the variable
+ @return the description of the variable
+ */
+ virtual std::string getDescription() const;
+
+ /**
+ Sets the description of the variable
+ @param description is the description of the variable
+ */
+ virtual void setDescription(const std::string& description);
+
+ /**
+ Sets the value of the variable
+ @param value is the input value of an InputVariable, or the output
+ value of an OutputVariable
+ */
+ virtual void setValue(scalar value);
+
+ /**
+ Gets the value of the variable
+ @return the input value of an InputVariable, or the output value of
+ an OutputVariable
+ */
+ virtual scalar getValue() const;
+
+ /**
+ Sets the range of the variable between `[minimum, maximum]`
+ @param minimum is the minimum value in range
+ @param maximum is the maximum value in range
+ */
+ virtual void setRange(scalar minimum, scalar maximum);
+ /**
+ Gets the magnitude of the range of the variable
+ @return `maximum - minimum`
+ */
+ virtual scalar range() const;
+
+ /**
+ Sets the minimum value of the range of the variable
+ @param minimum is the minimum value of the range
+ */
+ virtual void setMinimum(scalar minimum);
+ /**
+ Gets the minimum value of the range of the variable
+ @return the minimum value of the range of the variable
+ */
+ virtual scalar getMinimum() const;
+
+ /**
+ Sets the maximum value of the range of the variable
+ @param maximum is the maximum value of the range
+ */
+ virtual void setMaximum(scalar maximum);
+ /**
+ Gets the maximum value of the range of the variable
+ @return the maximum value of the range of the variable
+ */
+ virtual scalar getMaximum() const;
+
+ /**
+ Sets whether the variable is enabled
+ @param enabled determines whether to enable the variable
+ */
+ virtual void setEnabled(bool enabled);
+ /**
+ Gets whether the variable is enabled
+ @return whether the variable is enabled
+ */
+ virtual bool isEnabled() const;
+
+ /**
+ Sets whether the variable locks the current value to the range of the
+ variable.
+
+ If enabled in an InputVariable @f$i@f$, the input value @f$x_i@f$
+ will be used when computing the Antecedent::activationDegree() as
+ long as @f$x_i \in [\mbox{min}, \mbox{max}]@f$. Else, for the case of
+ @f$x_i \not\in [\mbox{min}, \mbox{max}]@f$, the range values will be
+ used instead but without changing the input value @f$x_i@f$.
+
+ If enabled in an OutputVariable @f$j@f$, the output value @f$y_j@f$
+ will be overriden by the range values when @f$y_j \not\in
+ [\mbox{min}, \mbox{max}]@f$. See OutputVariable for more information.
+
+ @param lockValueInRange indicates whether to lock the value to the
+ range of the variable
+ */
+ virtual void setLockValueInRange(bool lockValueInRange);
+
+ /**
+ Gets whether the variable locks the current value to the
+ range of the variable
+
+ If enabled in an InputVariable @f$i@f$, the input value @f$x_i@f$
+ will be used when computing the Antecedent::activationDegree() as
+ long as @f$x_i \in [\mbox{min}, \mbox{max}]@f$. Else, for the case of
+ @f$x_i \not\in [\mbox{min}, \mbox{max}]@f$, the range values will be
+ used instead but without changing the input value @f$x_i@f$.
+
+ If enabled in an OutputVariable @f$j@f$, the output value @f$y_j@f$
+ will be overriden by the range values when @f$y_j \not\in
+ [\mbox{min}, \mbox{max}]@f$. See OutputVariable for more information.
+
+ @return whether the variable locks the current value to the range of
+ the variable
+ */
+ virtual bool isLockValueInRange() const;
+
+ /**
+ Computes the aggregated complexity of the underlying terms
+ @return the aggregated complexity of the underlying terms
+ */
+ virtual Complexity complexity() const;
+
+ /**
+ Evaluates the membership function of value @f$x@f$ for each
+ term @f$i@f$, resulting in a fuzzy value in the form
+ @f$\tilde{x}=\sum_i{\mu_i(x)/i}@f$
+ @param x is the value to fuzzify
+ @return the fuzzy value expressed as @f$\sum_i{\mu_i(x)/i}@f$
+ */
+ virtual std::string fuzzify(scalar x) const;
+
+ /**
+ Gets the term which has the highest membership function value for
+ @f$x@f$.
+ @param x is the value of interest
+ @param[out] yhighest is a pointer where the highest membership
+ function value will be stored
+ @return the term @f$i@f$ which maximimizes @f$\mu_i(x)@f$
+ */
+ virtual Term* highestMembership(scalar x, scalar* yhighest = fl::null) const;
+
+ /**
+ Returns the type of the variable
+ @return the type of the variable
+ */
+ virtual Type type() const;
+
+ /**
+ Gets a string representation of the variable in the FuzzyLite Language
+ @return a string representation of the variable in the FuzzyLite
+ Language
+ @see FllExporter
+ */
+ virtual std::string toString() const;
+
+ /**
+ Sorts the terms in ascending order according to their centroids
+ */
+ virtual void sort();
+ /**
+ Adds a term to the variable
+ @param term is the term to add
+ */
+ virtual void addTerm(Term* term);
+ /**
+ Inserts the term in the variable
+ @param term is the term to insert
+ @param index is the index where the term will be inserted
+ */
+ virtual void insertTerm(Term* term, std::size_t index);
+ /**
+ Gets the term at the given index
+ @param index is the position of the term in the vector
+ @return the term at the given index
+ */
+ virtual Term* getTerm(std::size_t index) const;
+ /**
+ Gets the term of the given name.
+ @param name is the name of the term to retrieve
+ @return the term of the given name
+ @throws Exception if the term is not found
+ */
+ virtual Term* getTerm(const std::string& name) const;
+ /**
+ Gets whether a term of the given name has been added
+ @param name the name of the term
+ @return whether the term of the given name is found
+ */
+ virtual bool hasTerm(const std::string& name) const;
+ /**
+ Removes the term at the given index
+ @param index the index of the term to remove
+ @return the removed term
+ */
+ virtual Term* removeTerm(std::size_t index);
+ /**
+ Gets the number of terms added to the variable
+ @return the number of terms in the variable
+ */
+ virtual std::size_t numberOfTerms() const;
+ /**
+ Sets the terms of the variable
+ @param terms is a vector of terms
+ */
+ virtual void setTerms(const std::vector<Term*>& terms);
+ /**
+ Gets an immutable vector of the terms
+ @return an immutable vector of terms
+ */
+ virtual const std::vector<Term*>& terms() const;
+ /**
+ Gets a mutable vector of the terms
+ @return a mutable vector of terms
+ */
+ virtual std::vector<Term*>& terms();
+ /**
+ Creates a clone of the variable
+ @return a clone of the variable
+ */
+ virtual Variable* clone() const;
+ };
+}
+#endif /* FL_VARIABLE_H */
diff --git a/fuzzylite/fuzzylite.1 b/fuzzylite/fuzzylite.1
new file mode 100644
index 0000000..22d08d0
--- /dev/null
+++ b/fuzzylite/fuzzylite.1
@@ -0,0 +1,39 @@
+.TH fuzzylite 1 "October 26, 2014" "version 5.0" "USER COMMANDS"
+.SH NAME
+fuzzylite \- a fuzzy logic control library
+.SH SYNOPSIS
+.B fuzzylite
+[\-i inputfile] [\-if format] [\-o outputfile] [\-of format] [\-example letter] [\-decimals number] [\-d datafile] [\-dmaximum number] [\-dheader boolean] [\-dinputs boolean]
+.SH OPTIONS
+.TP
+\-i inputfile
+file to import your engine from
+.TP
+\-if format
+format of the file to import (fll | fis | fcl)
+.TP
+\-o outputfile
+file to export your engine to
+.TP
+\-of format
+format of the file to export (fll | fld | cpp | java | fis | fcl)
+.TP
+\-example letter
+if not inputfile, built\-in example to use as engine: (m)amdani or (t)akagi\-sugeno
+.TP
+\-decimals number
+number of decimals to write floating\-poing values
+.TP
+\-d datafile
+if exporting to fld, file of input values to evaluate your engine on
+.TP
+\-dmaximum number
+if exporting to fld without datafile, maximum number of results to export
+.TP
+\-dheader boolean
+if true and exporting to fld, include headers
+.TP
+\-dinputs boolean
+if true and exporting to fld, include input values
+.SH AUTHOR
+Juan Rada\-Vilela
diff --git a/fuzzylite/fuzzylite.pc.in b/fuzzylite/fuzzylite.pc.in
new file mode 100644
index 0000000..f6f7bee
--- /dev/null
+++ b/fuzzylite/fuzzylite.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+includedir=${exec_prefix}/include
+libdir=${exec_prefix}/lib
+
+Name: fuzzylite
+Description: A fuzzy logic control library in C++
+Version: @FL_VERSION@
+Libs: -L${libdir} -lfuzzylite
+Cflags: -I${includedir}
diff --git a/fuzzylite/src/Benchmark.cpp b/fuzzylite/src/Benchmark.cpp
new file mode 100644
index 0000000..9d318df
--- /dev/null
+++ b/fuzzylite/src/Benchmark.cpp
@@ -0,0 +1,460 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Benchmark.h"
+
+#include "fl/Engine.h"
+#include "fl/Operation.h"
+#include "fl/rule/Rule.h"
+#include "fl/rule/RuleBlock.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#ifdef FL_CPP98
+//timing is only available in C++11
+#else
+#include <chrono>
+#endif
+
+namespace fl {
+
+ Benchmark::Benchmark(const std::string& name, Engine* engine, scalar tolerance)
+ : _name(name), _engine(engine), _tolerance(tolerance) { }
+
+ Benchmark::~Benchmark() { }
+
+ void Benchmark::setName(const std::string& name) {
+ this->_name = name;
+ }
+
+ std::string Benchmark::getName() const {
+ return this->_name;
+ }
+
+ void Benchmark::setEngine(Engine* engine) {
+ this->_engine = engine;
+ }
+
+ Engine* Benchmark::getEngine() const {
+ return this->_engine;
+ }
+
+ void Benchmark::setExpected(const std::vector<std::vector<scalar> >& expected) {
+ this->_expected = expected;
+ }
+
+ const std::vector<std::vector<scalar> >& Benchmark::getExpected() const {
+ return this->_expected;
+ }
+
+ void Benchmark::setObtained(const std::vector<std::vector<scalar> >& obtained) {
+ this->_obtained = obtained;
+ }
+
+ const std::vector<std::vector<scalar> >& Benchmark::getObtained() const {
+ return this->_obtained;
+ }
+
+ void Benchmark::setTimes(const std::vector<scalar> nanoSeconds) {
+ this->_times = nanoSeconds;
+ }
+
+ const std::vector<scalar>& Benchmark::getTimes() const {
+ return this->_times;
+ }
+
+ void Benchmark::setTolerance(scalar tolerance) {
+ this->_tolerance = tolerance;
+ }
+
+ scalar Benchmark::getTolerance() const {
+ return this->_tolerance;
+ }
+
+ void Benchmark::prepare(int values, FldExporter::ScopeOfValues scope) {
+ if (not _engine) {
+ throw Exception("[benchmark error] engine not set before preparing for values and scope", FL_AT);
+ }
+ int resolution;
+ if (scope == FldExporter::AllVariables)
+ resolution = -1 + (int) std::max(1.0, std::pow(
+ values, 1.0 / _engine->numberOfInputVariables()));
+ else //if (scope == EachVariable)
+ resolution = values - 1;
+
+ std::vector<int> sampleValues, minSampleValues, maxSampleValues;
+ for (std::size_t i = 0; i < _engine->numberOfInputVariables(); ++i) {
+ sampleValues.push_back(0);
+ minSampleValues.push_back(0);
+ maxSampleValues.push_back(resolution);
+ }
+
+ _expected = std::vector<std::vector<scalar> >();
+ do {
+ std::vector<scalar> expectedValues(_engine->numberOfInputVariables());
+ for (std::size_t i = 0; i < _engine->numberOfInputVariables(); ++i) {
+ InputVariable* inputVariable = _engine->getInputVariable(i);
+ expectedValues.at(i) = inputVariable->getMinimum()
+ + sampleValues.at(i) * inputVariable->range() / std::max(1, resolution);
+ }
+ _expected.push_back(expectedValues);
+ } while (Op::increment(sampleValues, minSampleValues, maxSampleValues));
+ }
+
+ void Benchmark::prepare(std::istream& reader, long numberOfLines) {
+ _expected = std::vector<std::vector<scalar> >();
+ std::string line;
+ int lineNumber = 0;
+ while (lineNumber != numberOfLines and std::getline(reader, line)) {
+ ++lineNumber;
+ line = Op::trim(line);
+ if (line.empty() or line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> expectedValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ expectedValues = Op::toScalars(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ expectedValues = Op::toScalars(line);
+ }
+ _expected.push_back(expectedValues);
+ }
+ }
+
+ scalar Benchmark::runOnce() {
+ return run(1).front();
+ }
+
+ std::vector<scalar> Benchmark::run(int times) {
+ if (not _engine) {
+ throw Exception("[benchmark error] engine not set for benchmark", FL_AT);
+ }
+ std::vector<scalar> runTimes(times, fl::nan);
+ const std::size_t offset(_engine->inputVariables().size());
+ for (int t = 0; t < times; ++t) {
+ _obtained = std::vector<std::vector<scalar> >(_expected.size(),
+ std::vector<scalar>(_engine->variables().size()));
+ _engine->restart();
+
+#ifdef FL_CPP98
+ //ignore timing
+#else
+ auto start = std::chrono::high_resolution_clock::now();
+#endif
+
+ for (std::size_t evaluation = 0; evaluation < _expected.size(); ++evaluation) {
+ const std::vector<scalar>& expectedValues = _expected[evaluation];
+ std::vector<scalar>& obtainedValues = _obtained[evaluation];
+
+ if (expectedValues.size() < _engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[benchmark error] the number of input values given <" <<
+ expectedValues.size() << "> at line <" << (evaluation + 1) << "> "
+ "must be at least the same number of input variables "
+ "<" << _engine->inputVariables().size() << "> in the engine";
+ throw Exception(ex.str());
+ }
+ for (std::size_t i = 0; i < _engine->inputVariables().size(); ++i) {
+ _engine->getInputVariable(i)->setValue(expectedValues[i]);
+ obtainedValues[i] = expectedValues[i];
+ }
+
+ _engine->process();
+
+ for (std::size_t i = 0; i < _engine->outputVariables().size(); ++i) {
+ obtainedValues[i + offset] = _engine->getOutputVariable(i)->getValue();
+ }
+ }
+
+#ifdef FL_CPP98
+ //ignore timing
+#else
+ auto end = std::chrono::high_resolution_clock::now();
+ runTimes.at(t) = std::chrono::duration<scalar, std::nano>(end - start).count();
+#endif
+ }
+ _times.insert(_times.end(), runTimes.begin(), runTimes.end());
+ return runTimes;
+ }
+
+ void Benchmark::reset() {
+ this->_obtained.clear();
+ this->_times.clear();
+ }
+
+ bool Benchmark::canComputeErrors() const {
+ return not (_engine == fl::null or _expected.empty() or _obtained.empty()
+ or _expected.size() != _obtained.size()
+ or _expected.front().size() != _obtained.front().size()
+ or _expected.front().size() != _engine->variables().size());
+ }
+
+ scalar Benchmark::meanSquaredError() const {
+ return meanSquaredError(fl::null);
+ }
+
+ scalar Benchmark::meanSquaredError(const OutputVariable* outputVariable) const {
+ if (not canComputeErrors()) {
+ return fl::nan;
+ }
+
+ scalar mse = 0.0;
+ int errors = 0;
+ const std::size_t offset = _engine->numberOfInputVariables();
+ for (std::size_t i = 0; i < _expected.size(); ++i) {
+ const std::vector<scalar>& e = _expected.at(i);
+ const std::vector<scalar>& o = _obtained.at(i);
+
+ for (std::size_t y = 0; y < _engine->numberOfOutputVariables(); ++y) {
+ if (outputVariable == fl::null
+ or outputVariable == _engine->getOutputVariable(y)) {
+ scalar difference = e.at(offset + y) - o.at(offset + y);
+ if (Op::isFinite(difference)
+ and not Op::isEq(difference, 0.0, _tolerance)) {
+ mse += difference * difference;
+ ++errors;
+ }
+ }
+ }
+ }
+
+ if (errors > 0) {
+ mse /= errors;
+ }
+ return mse;
+ }
+
+ int Benchmark::allErrors() const {
+ return allErrors(fl::null);
+ }
+
+ int Benchmark::allErrors(const OutputVariable* outputVariable) const {
+ return numberOfErrors(All, outputVariable);
+ }
+
+ int Benchmark::nonFiniteErrors() const {
+ return nonFiniteErrors(fl::null);
+ }
+
+ int Benchmark::nonFiniteErrors(const OutputVariable* outputVariable) const {
+ return numberOfErrors(NonFinite, outputVariable);
+ }
+
+ int Benchmark::accuracyErrors() const {
+ return accuracyErrors(fl::null);
+ }
+
+ int Benchmark::accuracyErrors(const OutputVariable* outputVariable) const {
+ return numberOfErrors(Accuracy, outputVariable);
+ }
+
+ int Benchmark::numberOfErrors(ErrorType errorType) const {
+ return numberOfErrors(errorType, fl::null);
+ }
+
+ int Benchmark::numberOfErrors(ErrorType errorType,
+ const OutputVariable* outputVariable) const {
+ if (not canComputeErrors()) {
+ return -1;
+ }
+
+ int errors = 0;
+ const std::size_t offset = _engine->numberOfInputVariables();
+ for (std::size_t i = 0; i < _expected.size(); ++i) {
+ const std::vector<scalar>& e = _expected.at(i);
+ const std::vector<scalar>& o = _obtained.at(i);
+
+ for (std::size_t y = 0; y < _engine->numberOfOutputVariables(); ++y) {
+ if (outputVariable == fl::null
+ or outputVariable == _engine->getOutputVariable(y)) {
+ if (not Op::isEq(e.at(y + offset), o.at(y + offset), _tolerance)) {
+ scalar difference = e.at(y + offset) - o.at(y + offset);
+ if (errorType == Accuracy and Op::isFinite(difference)) {
+ ++errors;
+ } else if (errorType == NonFinite and not Op::isFinite(difference)) {
+ ++errors;
+ } else if (errorType == All) {
+ ++errors;
+ }
+ }
+ }
+ }
+ }
+
+ return errors;
+ }
+
+ std::string Benchmark::stringOf(TimeUnit unit) {
+ if (unit == NanoSeconds) return "nanoseconds";
+ if (unit == MicroSeconds) return "microseconds";
+ if (unit == MilliSeconds) return "milliseconds";
+ if (unit == Seconds) return "seconds";
+ if (unit == Minutes) return "minutes";
+ if (unit == Hours) return "hours";
+ return "undefined";
+ }
+
+ scalar Benchmark::factorOf(TimeUnit unit) {
+ if (unit == NanoSeconds) return 1.0;
+ else if (unit == MicroSeconds) return 1.0e-3;
+ else if (unit == MilliSeconds) return 1.0e-6;
+ else if (unit == Seconds) return 1.0e-9;
+ else if (unit == Minutes) return 1.0e-9 / 60;
+ else if (unit == Hours) return 1.0e-9 / 3600;
+ return fl::nan;
+ }
+
+ scalar Benchmark::convert(scalar x, TimeUnit from, TimeUnit to) {
+ return x * factorOf(to) / factorOf(from);
+ }
+
+ std::vector<std::string> Benchmark::header(int runs, bool includeErrors) {
+ Benchmark result;
+
+ Engine dummy;
+ dummy.addOutputVariable(new OutputVariable); //canCompute() == true
+ result.setEngine(&dummy);
+
+ result.setTimes(std::vector<scalar>(runs, fl::nan));
+
+ if (includeErrors) {
+ std::vector<std::vector<scalar> > dummyVector(1,
+ std::vector<scalar>(1, fl::nan));
+ result.setExpected(dummyVector);
+ result.setObtained(dummyVector);
+ }
+ std::vector<Benchmark::Result> dummyResults = result.results();
+
+ std::vector<std::string> names;
+ for (std::size_t i = 0; i < dummyResults.size(); ++i) {
+ names.push_back(dummyResults.at(i).first);
+ }
+ return names;
+ }
+
+ std::vector<Benchmark::Result> Benchmark::results(TimeUnit timeUnit, bool includeTimes) const {
+ return results(fl::null, timeUnit, includeTimes);
+ }
+
+ std::vector<Benchmark::Result> Benchmark::results(
+ const OutputVariable* outputVariable, TimeUnit unit, bool includeTimes) const {
+ if (not _engine) {
+ throw Exception("[benchmark error] engine not set for benchmark", FL_AT);
+ }
+
+ std::vector<scalar> time = _times;
+
+ std::vector<Result> result;
+ result.push_back(Result("library", fuzzylite::library()));
+ result.push_back(Result("name", _name));
+ result.push_back(Result("inputs", Op::str(_engine->numberOfInputVariables())));
+ result.push_back(Result("outputs", Op::str(_engine->numberOfOutputVariables())));
+ result.push_back(Result("ruleBlocks", Op::str(_engine->numberOfRuleBlocks())));
+ std::size_t rules = 0;
+ for (std::size_t i = 0; i < _engine->ruleBlocks().size(); ++i) {
+ rules += _engine->ruleBlocks().at(i)->rules().size();
+ }
+ result.push_back(Result("rules", Op::str(rules)));
+ result.push_back(Result("runs", Op::str(_times.size())));
+ result.push_back(Result("evaluations", Op::str(_expected.size())));
+ if (canComputeErrors()) {
+ std::vector<std::string> names;
+ scalar meanRange = 0.0;
+ scalar rmse = std::sqrt(meanSquaredError(outputVariable));
+ scalar nrmse = 0.0;
+ scalar weights = 0.0;
+ for (std::size_t i = 0; i < _engine->outputVariables().size(); ++i) {
+ const OutputVariable* y = _engine->outputVariables().at(i);
+ if (outputVariable == fl::null or outputVariable == y) {
+ names.push_back(y->getName());
+ meanRange += y->range();
+ nrmse += std::sqrt(meanSquaredError(y)) * 1.0 / y->range();
+ weights += 1.0 / y->range();
+ }
+ }
+ meanRange /= names.size();
+ nrmse /= weights;
+
+ result.push_back(Result("outputVariable", Op::join(names, ",")));
+ result.push_back(Result("range", Op::str(meanRange)));
+
+ result.push_back(Result("tolerance", Op::str(getTolerance(), -1, std::ios_base::fmtflags(0x0))));
+ result.push_back(Result("errors", Op::str(allErrors(outputVariable))));
+
+ result.push_back(Result("nfErrors", Op::str(nonFiniteErrors(outputVariable))));
+ result.push_back(Result("accErrors", Op::str(accuracyErrors(outputVariable))));
+
+ result.push_back(Result("rmse", Op::str(rmse, 6, std::ios_base::scientific)));
+ result.push_back(Result("nrmse", Op::str(nrmse, 6, std::ios_base::scientific)));
+ }
+ result.push_back(Result("units", stringOf(unit)));
+ result.push_back(Result("sum(t)", Op::str(convert(Op::sum(time), NanoSeconds, unit),
+ unit == NanoSeconds ? 0 : fuzzylite::decimals())));
+ result.push_back(Result("mean(t)", Op::str(convert(Op::mean(time), NanoSeconds, unit))));
+ result.push_back(Result("sd(t)", Op::str(convert(Op::standardDeviation(time), NanoSeconds, unit))));
+
+ if (includeTimes) {
+ for (std::size_t i = 0; i < time.size(); ++i) {
+ result.push_back(Result("t" + Op::str(i + 1),
+ Op::str(time.at(i), unit == NanoSeconds ? 0 : fuzzylite::decimals())));
+ }
+ }
+ return result;
+ }
+
+ std::string Benchmark::format(std::vector<Result> results, TableShape shape,
+ TableContents contents, const std::string& delimiter) const {
+ std::ostringstream os;
+
+ if (shape == Vertical) {
+ for (std::size_t i = 0; i < results.size(); ++i) {
+ Result pair = results.at(i);
+ if (contents bitand Header) {
+ os << pair.first;
+ }
+ if (contents == HeaderAndBody) {
+ os << delimiter;
+ }
+ if (contents bitand Body) {
+ os << pair.second;
+ }
+ if (i + 1 < results.size()) os << "\n";
+ }
+
+ } else if (shape == Horizontal) {
+ std::ostringstream header;
+ std::ostringstream body;
+ for (std::size_t i = 0; i < results.size(); ++i) {
+ Result pair = results.at(i);
+ if (contents bitand Header) {
+ header << pair.first;
+ if (i + 1 < results.size()) header << delimiter;
+ }
+ if (contents bitand Body) {
+ body << pair.second;
+ if (i + 1 < results.size()) body << delimiter;
+ }
+ }
+ if (contents bitand Header) os << header.str();
+ if (contents == HeaderAndBody) os << "\n";
+ if (contents bitand Body) os << body.str();
+ }
+ return os.str();
+ }
+}
diff --git a/fuzzylite/src/Complexity.cpp b/fuzzylite/src/Complexity.cpp
new file mode 100644
index 0000000..8a91c60
--- /dev/null
+++ b/fuzzylite/src/Complexity.cpp
@@ -0,0 +1,283 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Complexity.h"
+
+#include "fl/Engine.h"
+
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+
+namespace fl {
+
+ Complexity::Complexity(scalar all) :
+ _comparison(all), _arithmetic(all), _function(all) { }
+
+ Complexity::Complexity(scalar comparison, scalar arithmetic,
+ scalar function)
+ : _comparison(comparison), _arithmetic(arithmetic), _function(function) { }
+
+ Complexity::~Complexity() { }
+
+ Complexity& Complexity::operator+=(const Complexity& other) {
+ return this->plus(other);
+ }
+
+ Complexity& Complexity::operator-=(const Complexity& other) {
+ return this->minus(other);
+ }
+
+ Complexity& Complexity::operator*=(const Complexity& other) {
+ return this->multiply(other);
+ }
+
+ Complexity& Complexity::operator/=(const Complexity& other) {
+ return this->divide(other);
+ }
+
+ Complexity Complexity::operator+(const Complexity& rhs) const {
+ return Complexity(*this).plus(rhs);
+ }
+
+ Complexity Complexity::operator-(const Complexity& rhs) const {
+ return Complexity(*this).minus(rhs);
+ }
+
+ Complexity Complexity::operator*(const Complexity& rhs) const {
+ return Complexity(*this).multiply(rhs);
+ }
+
+ Complexity Complexity::operator/(const Complexity& rhs) const {
+ return Complexity(*this).divide(rhs);
+ }
+
+ bool Complexity::operator==(const Complexity& rhs) const {
+ return equals(rhs);
+ }
+
+ bool Complexity::operator!=(const Complexity& rhs) const {
+ return not equals(rhs);
+ }
+
+ bool Complexity::operator<(const Complexity& rhs) const {
+ return lessThan(rhs);
+ }
+
+ bool Complexity::operator<=(const Complexity& rhs) const {
+ return lessThanOrEqualsTo(rhs);
+ }
+
+ bool Complexity::operator>(const Complexity& rhs) const {
+ return greaterThan(rhs);
+ }
+
+ bool Complexity::operator>=(const Complexity& rhs) const {
+ return greaterThanOrEqualsTo(rhs);
+ }
+
+ Complexity& Complexity::plus(const Complexity& other) {
+ this->_arithmetic += other._arithmetic;
+ this->_comparison += other._comparison;
+ this->_function += other._function;
+ return *this;
+ }
+
+ Complexity& Complexity::plus(scalar x) {
+ return this->plus(Complexity().arithmetic(x).comparison(x).function(x));
+ }
+
+ Complexity& Complexity::minus(const Complexity& other) {
+ this->_comparison -= other._comparison;
+ this->_arithmetic -= other._arithmetic;
+ this->_function -= other._function;
+ return *this;
+ }
+
+ Complexity& Complexity::minus(scalar x) {
+ return this->minus(Complexity().arithmetic(x).comparison(x).function(x));
+ }
+
+ Complexity& Complexity::multiply(const Complexity& other) {
+ this->_comparison *= other._comparison;
+ this->_arithmetic *= other._arithmetic;
+ this->_function *= other._function;
+ return *this;
+ }
+
+ Complexity& Complexity::multiply(scalar x) {
+ return this->multiply(Complexity().arithmetic(x).comparison(x).function(x));
+ }
+
+ Complexity& Complexity::divide(const Complexity& other) {
+ this->_comparison /= other._comparison;
+ this->_arithmetic /= other._arithmetic;
+ this->_function /= other._function;
+ return *this;
+ }
+
+ Complexity& Complexity::divide(scalar x) {
+ return this->divide(Complexity().arithmetic(x).comparison(x).function(x));
+ }
+
+ bool Complexity::equals(const Complexity& x, scalar macheps) const {
+ return Op::isEq(_comparison, x._comparison, macheps) and
+ Op::isEq(_arithmetic, x._arithmetic, macheps) and
+ Op::isEq(_function, x._function, macheps);
+ }
+
+ bool Complexity::lessThan(const Complexity& x, scalar macheps) const {
+ return Op::isLt(_comparison, x._comparison, macheps) and
+ Op::isLt(_arithmetic, x._arithmetic, macheps) and
+ Op::isLt(_function, x._function, macheps);
+ }
+
+ bool Complexity::lessThanOrEqualsTo(const Complexity& x, scalar macheps) const {
+ return Op::isLE(_comparison, x._comparison, macheps) and
+ Op::isLE(_arithmetic, x._arithmetic, macheps) and
+ Op::isLE(_function, x._function, macheps);
+ }
+
+ bool Complexity::greaterThan(const Complexity& x, scalar macheps) const {
+ return Op::isGt(_comparison, x._comparison, macheps) and
+ Op::isGt(_arithmetic, x._arithmetic, macheps) and
+ Op::isGt(_function, x._function, macheps);
+ }
+
+ bool Complexity::greaterThanOrEqualsTo(const Complexity& x, scalar macheps) const {
+ return Op::isGE(_comparison, x._comparison, macheps) and
+ Op::isGE(_arithmetic, x._arithmetic, macheps) and
+ Op::isGE(_function, x._function, macheps);
+ }
+
+ Complexity& Complexity::comparison(scalar comparison) {
+ this->_comparison += comparison;
+ return *this;
+ }
+
+ void Complexity::setComparison(scalar comparison) {
+ this->_comparison = comparison;
+ }
+
+ scalar Complexity::getComparison() const {
+ return _comparison;
+ }
+
+ Complexity& Complexity::arithmetic(scalar arithmetic) {
+ this->_arithmetic += arithmetic;
+ return *this;
+ }
+
+ void Complexity::setArithmetic(scalar arithmetic) {
+ this->_arithmetic = arithmetic;
+ }
+
+ scalar Complexity::getArithmetic() const {
+ return _arithmetic;
+ }
+
+ Complexity& Complexity::function(scalar trigonometric) {
+ this->_function += trigonometric;
+ return *this;
+ }
+
+ void Complexity::setFunction(scalar trigonometric) {
+ this->_function = trigonometric;
+ }
+
+ scalar Complexity::getFunction() const {
+ return _function;
+ }
+
+ std::vector<Complexity::Measure> Complexity::measures() const {
+ std::vector<Measure> result;
+ result.push_back(Measure("arithmetic", _arithmetic));
+ result.push_back(Measure("comparison", _comparison));
+ result.push_back(Measure("function", _function));
+ return result;
+ }
+
+ scalar Complexity::sum() const {
+ return _arithmetic + _comparison + _function;
+ }
+
+ scalar Complexity::norm() const {
+ return std::sqrt(Complexity(*this).multiply(*this).sum());
+ }
+
+ std::string Complexity::toString() const {
+ std::vector<std::string> result;
+ result.push_back("a=" + Op::str(_arithmetic));
+ result.push_back("c=" + Op::str(_comparison));
+ result.push_back("f=" + Op::str(_function));
+ return "C[" + Op::join(result, ", ") + "]";
+ }
+
+ Complexity Complexity::compute(const Engine* engine) const {
+ return engine->complexity();
+ }
+
+ Complexity Complexity::compute(const InputVariable* inputVariable) const {
+ return inputVariable->complexity();
+ }
+
+ Complexity Complexity::compute(const OutputVariable* outputVariable) const {
+ return outputVariable->complexity();
+ }
+
+ Complexity Complexity::compute(const RuleBlock* ruleBlock) const {
+ return ruleBlock->complexity();
+ }
+
+ Complexity Complexity::compute(const std::vector<InputVariable*>& inputVariables) const {
+ Complexity result;
+ for (std::size_t i = 0; i < inputVariables.size(); ++i) {
+ result += inputVariables.at(i)->complexity();
+ }
+ return result;
+ }
+
+ Complexity Complexity::compute(const std::vector<OutputVariable*>& outputVariables,
+ bool complexityOfDefuzzification) const {
+ Complexity result;
+ for (std::size_t i = 0; i < outputVariables.size(); ++i) {
+ if (complexityOfDefuzzification)
+ result += outputVariables.at(i)->complexityOfDefuzzification();
+ else
+ result += outputVariables.at(i)->complexity();
+ }
+ return result;
+ }
+
+ Complexity Complexity::compute(const std::vector<Variable*>& variables) const {
+ Complexity result;
+ for (std::size_t i = 0; i < variables.size(); ++i) {
+ result += variables.at(i)->complexity();
+ }
+ return result;
+ }
+
+ Complexity Complexity::compute(const std::vector<RuleBlock*>& ruleBlocks) const {
+ Complexity result;
+ for (std::size_t i = 0; i < ruleBlocks.size(); ++i) {
+ result += ruleBlocks.at(i)->complexity();
+ }
+ return result;
+ }
+
+}
diff --git a/fuzzylite/src/Console.cpp b/fuzzylite/src/Console.cpp
new file mode 100644
index 0000000..5a00c50
--- /dev/null
+++ b/fuzzylite/src/Console.cpp
@@ -0,0 +1,1023 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Console.h"
+
+#include "fl/Headers.h"
+
+#include <fstream>
+
+#ifdef FL_UNIX
+#include <termios.h>
+#include <unistd.h>
+#elif defined(FL_WINDOWS)
+#include <conio.h>
+#endif
+
+
+namespace fl {
+ const std::string Console::KW_INPUT_FILE = "-i";
+ const std::string Console::KW_INPUT_FORMAT = "-if";
+ const std::string Console::KW_OUTPUT_FILE = "-o";
+ const std::string Console::KW_OUTPUT_FORMAT = "-of";
+ const std::string Console::KW_EXAMPLE = "-example";
+ const std::string Console::KW_DECIMALS = "-decimals";
+ const std::string Console::KW_DATA_INPUT_FILE = "-d";
+ const std::string Console::KW_DATA_VALUES = "-values";
+ const std::string Console::KW_DATA_VALUES_SCOPE = "-scope";
+
+ const std::string Console::KW_DATA_EXPORT_HEADER = "-dheader";
+ const std::string Console::KW_DATA_EXPORT_INPUTS = "-dinputs";
+
+ Console::Option::Option(const std::string& key, const std::string& value, const std::string& description) :
+ key(key), value(value), description(description) { }
+
+ std::vector<Console::Option> Console::availableOptions() {
+ std::vector<Console::Option> options;
+ options.push_back(Option(KW_INPUT_FILE, "inputfile", "file to import your engine from"));
+ options.push_back(Option(KW_INPUT_FORMAT, "format", "format of the file to import (fll | fis | fcl)"));
+ options.push_back(Option(KW_OUTPUT_FILE, "outputfile", "file to export your engine to"));
+ options.push_back(Option(KW_OUTPUT_FORMAT, "format", "format of the file to export (fll | fld | cpp | java | fis | fcl)"));
+ options.push_back(Option(KW_EXAMPLE, "letter", "if not inputfile, built-in example to use as engine: (m)amdani or (t)akagi-sugeno"));
+ options.push_back(Option(KW_DECIMALS, "number", "number of decimals to write floating-poing values"));
+ options.push_back(Option(KW_DATA_INPUT_FILE, "file", "if exporting to fld, FLD file of input values to evaluate your engine on"));
+ options.push_back(Option(KW_DATA_VALUES, "number", "if exporting to fld without datafile, number of results to export within scope (default: EachVariable)"));
+ options.push_back(Option(KW_DATA_VALUES_SCOPE, "scope", "if exporting to fld without datafile, scope of " + KW_DATA_VALUES + ": [EachVariable|AllVariables]"));
+ options.push_back(Option(KW_DATA_EXPORT_HEADER, "boolean", "if true and exporting to fld, include headers"));
+ options.push_back(Option(KW_DATA_EXPORT_INPUTS, "boolean", "if true and exporting to fld, include input values"));
+ return options;
+ }
+
+ std::string Console::usage() {
+ std::vector<Console::Option> options = availableOptions();
+ std::ostringstream ss;
+
+ ss << "========================================\n";
+ ss << "fuzzylite: a fuzzy logic control library\n";
+ ss << "version: " << fuzzylite::version() << "\n";
+ ss << "author: " << fuzzylite::author() << "\n";
+ ss << "license: " << fuzzylite::license() << "\n";
+ ss << "========================================\n\n";
+ ss << "usage: fuzzylite inputfile outputfile\n";
+ ss << " or: fuzzylite benchmark engine.fll input.fld runs [output.tsv]\n";
+ ss << " or: fuzzylite benchmarks fllFiles.txt fldFiles.txt runs [output.tsv]\n";
+ ss << " or: fuzzylite ";
+ for (std::size_t i = 0; i < options.size(); ++i) {
+ ss << "[" << options.at(i).key << " " << options.at(i).value << "] ";
+ }
+ ss << "\n\nwhere:\n";
+ for (std::size_t i = 0; i < options.size(); ++i) {
+ std::string spacedKey(12, ' ');
+ std::string key = options.at(i).key;
+ std::copy(key.begin(), key.end(), spacedKey.begin());
+
+ std::string spacedValue(13, ' ');
+ std::string value = options.at(i).value;
+ std::copy(value.begin(), value.end(), spacedValue.begin());
+
+ std::string description = options.at(i).description;
+
+ ss << spacedKey << spacedValue << description << "\n";
+ }
+
+ ss << "\n";
+ ss << "Visit " << fuzzylite::website() << " for more information.\n\n";
+ ss << "Copyright (C) 2010-2017 by FuzzyLite Limited.\n";
+ ss << "All rights reserved.";
+
+ return ss.str();
+ }
+
+ std::map<std::string, std::string> Console::parse(int argc, const char* argv[]) {
+ if ((argc - 1) % 2 != 0) {
+ throw Exception("[option error] incomplete number of parameters [key value]", FL_AT);
+ }
+ std::map<std::string, std::string> options;
+ for (int i = 1; i < argc - 1; i += 2) {
+ std::string key = std::string(argv[i]);
+ std::string value = std::string(argv[i + 1]);
+ options[key] = value;
+ }
+ if (options.size() == 1) {
+ std::map<std::string, std::string>::const_iterator it = options.begin();
+ if (it->first.at(0) != '-') {
+ options[KW_INPUT_FILE] = it->first;
+ options[KW_OUTPUT_FILE] = it->second;
+ }
+ } else {
+ std::vector<Console::Option> validOptions = availableOptions();
+
+ for (std::map<std::string, std::string>::const_iterator it = options.begin();
+ it != options.end(); ++it) {
+ bool isValid = false;
+ for (std::size_t i = 0; i < validOptions.size(); ++i) {
+ std::string key = validOptions.at(i).key;
+ if (key == it->first) {
+ isValid = true;
+ break;
+ }
+ }
+ if (not isValid) {
+ throw Exception("[option error] option <" + it->first + "> not recognized", FL_AT);
+ }
+ }
+ }
+ return options;
+ }
+
+ void Console::process(const std::map<std::string, std::string>& options) {
+ std::map<std::string, std::string>::const_iterator it;
+
+ it = options.find(KW_DECIMALS);
+ if (it != options.end()) {
+ fuzzylite::setDecimals((int) Op::toScalar(it->second));
+ }
+
+ std::string example;
+ std::string inputFormat;
+ std::ostringstream textEngine;
+
+ it = options.find(KW_EXAMPLE);
+
+ bool isExample = (it != options.end());
+
+ if (isExample) {
+ example = it->second;
+ Engine* engine;
+ if (example == "m" or example == "mamdani") {
+ engine = mamdani();
+ } else if (example == "t" or example == "ts" or example == "takagi-sugeno") {
+ engine = takagiSugeno();
+ } else {
+ throw Exception("[option error] example <" + example + "> not available", FL_AT);
+ }
+ inputFormat = "fll";
+ textEngine << FllExporter().toString(engine);
+ delete engine;
+
+ } else {
+ it = options.find(KW_INPUT_FILE);
+ if (it == options.end()) {
+ throw Exception("[option error] no input file specified", FL_AT);
+ }
+ std::string inputFilename = it->second;
+ std::ifstream inputFile(inputFilename.c_str());
+ if (not inputFile.is_open()) {
+ throw Exception("[file error] file <" + inputFilename + "> could not be opened", FL_AT);
+ }
+ std::string line;
+ while (std::getline(inputFile, line)) {
+ textEngine << line << std::endl;
+ }
+ inputFile.close();
+
+ it = options.find(KW_INPUT_FORMAT);
+ if (it != options.end()) {
+ inputFormat = it->second;
+ } else {
+ std::size_t extensionIndex = inputFilename.find_last_of(".");
+ if (extensionIndex != std::string::npos) {
+ inputFormat = inputFilename.substr(extensionIndex + 1);
+ } else {
+ throw Exception("[format error] unspecified format of input file", FL_AT);
+ }
+ }
+ }
+
+ std::string outputFilename;
+ it = options.find(KW_OUTPUT_FILE);
+ if (it != options.end()) {
+ outputFilename = it->second;
+ }
+
+ std::string outputFormat;
+ it = options.find(KW_OUTPUT_FORMAT);
+ if (it != options.end()) {
+ outputFormat = it->second;
+ } else {
+ std::size_t extensionIndex = outputFilename.find_last_of(".");
+ if (extensionIndex != std::string::npos) {
+ outputFormat = outputFilename.substr(extensionIndex + 1);
+ } else {
+ throw Exception("[format error] unspecified format of output file", FL_AT);
+ }
+ }
+
+
+ if (outputFilename.empty()) {
+ process(textEngine.str(), std::cout, inputFormat, outputFormat, options);
+ } else {
+ std::ofstream writer(outputFilename.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + outputFilename + "> could not be created", FL_AT);
+ }
+ process(textEngine.str(), writer, inputFormat, outputFormat, options);
+ writer.flush();
+ writer.close();
+ }
+ }
+
+ void Console::process(const std::string& input, std::ostream& writer,
+ const std::string& inputFormat, const std::string& outputFormat,
+ const std::map<std::string, std::string>& options) {
+ FL_unique_ptr<Importer> importer;
+ FL_unique_ptr<Exporter> exporter;
+ FL_unique_ptr<Engine> engine;
+
+ if ("fll" == inputFormat) {
+ importer.reset(new FllImporter);
+ } else if ("fcl" == inputFormat) {
+ importer.reset(new FclImporter);
+ } else if ("fis" == inputFormat) {
+ importer.reset(new FisImporter);
+ } else {
+ throw Exception("[import error] format <" + inputFormat + "> "
+ "not supported", FL_AT);
+ }
+
+ engine.reset(importer->fromString(input));
+
+ if ("fld" == outputFormat) {
+ std::map<std::string, std::string>::const_iterator it;
+
+ FldExporter fldExporter;
+ fldExporter.setSeparator(" ");
+ bool exportHeaders = true;
+ if ((it = options.find(KW_DATA_EXPORT_HEADER)) != options.end()) {
+ exportHeaders = ("true" == it->second);
+ }
+ fldExporter.setExportHeader(exportHeaders);
+ bool exportInputValues = true;
+ if ((it = options.find(KW_DATA_EXPORT_INPUTS)) != options.end()) {
+ exportInputValues = ("true" == it->second);
+ }
+ fldExporter.setExportInputValues(exportInputValues);
+ if ((it = options.find(KW_DATA_INPUT_FILE)) != options.end()) {
+ std::ifstream dataFile(it->second.c_str());
+ if (not dataFile.is_open()) {
+ throw Exception("[export error] file <" + it->second + "> could not be opened", FL_AT);
+ }
+ try {
+ fldExporter.write(engine.get(), writer, dataFile);
+ } catch (std::exception& ex) {
+ FL_IUNUSED(ex);
+ dataFile.close();
+ throw;
+ }
+
+ } else {
+ if ((it = options.find(KW_DATA_VALUES)) != options.end()) {
+ int values = (int) Op::toScalar(it->second);
+ FldExporter::ScopeOfValues scope = FldExporter::EachVariable;
+ if ((it = options.find(KW_DATA_VALUES_SCOPE)) != options.end()) {
+ if ("AllVariables" == it->second)
+ scope = FldExporter::AllVariables;
+ else if ("EachVariable" == it->second)
+ scope = FldExporter::EachVariable;
+ else throw Exception("[export error] unknown scope of values <"
+ + it->second + ">", FL_AT);
+ }
+ fldExporter.write(engine.get(), writer, values, scope);
+ } else {
+ std::ostringstream buffer;
+ buffer << "#FuzzyLite Interactive Console (press H for help)\n";
+ buffer << fldExporter.header(engine.get()) << "\n";
+ bool showCout = &writer != &std::cout;
+ writer << buffer.str();
+ if (showCout) std::cout << buffer.str();
+ else writer.flush();
+ interactive(writer, engine.get());
+ }
+ }
+ } else {
+ if ("fll" == outputFormat) {
+ exporter.reset(new FllExporter);
+ } else if ("fcl" == outputFormat) {
+ exporter.reset(new FclExporter);
+ } else if ("fis" == outputFormat) {
+ exporter.reset(new FisExporter);
+ } else if ("cpp" == outputFormat) {
+ exporter.reset(new CppExporter);
+ } else if ("java" == outputFormat) {
+ exporter.reset(new JavaExporter);
+ } else throw Exception("[export error] format <" + outputFormat + "> "
+ "not supported", FL_AT);
+ writer << exporter->toString(engine.get());
+ }
+ }
+
+ int Console::readCharacter() {
+ int ch = 0;
+#ifdef FL_UNIX
+ struct termios oldt, newt;
+ ::tcgetattr(STDIN_FILENO, &oldt);
+ newt = oldt;
+ newt.c_lflag &= ~(ICANON | ECHO);
+ ::tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+ ch = ::getchar();
+ ::tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+#elif defined(FL_WINDOWS)
+ ch = ::_getch();
+#endif
+ return ch;
+ }
+
+ void Console::interactive(std::ostream& writer, Engine* engine) {
+ std::ostringstream buffer;
+ buffer << ">";
+ bool showCout = &writer != &std::cout;
+ const std::string space("\t");
+ std::vector<scalar> inputValues;
+ std::ostringstream inputValue;
+ int ch = 0;
+ do {
+ writer << buffer.str();
+ if (showCout) std::cout << buffer.str();
+ else writer.flush();
+ buffer.str("");
+
+ ch = readCharacter();
+
+ if (ch == EOF) {
+ break;
+ }
+
+ if (std::isspace(ch)) {
+ scalar value = engine->getInputVariable(inputValues.size())->getValue();
+ try {
+ value = Op::toScalar(inputValue.str());
+ } catch (std::exception& ex) {
+ FL_IUNUSED(ex);
+ buffer << "[" << Op::str(value) << "]";
+ }
+ buffer << space;
+ inputValue.str("");
+ inputValues.push_back(value);
+ if (inputValues.size() == engine->inputVariables().size()) {
+ ch = 'P'; //fall through to process;
+ } else continue;
+ }
+
+ if (not std::isgraph(ch)) continue;
+
+ switch (ch) {
+ default:
+ inputValue << char(ch);
+ buffer << char(ch);
+ break;
+ case 'r':
+ case 'R': engine->restart();
+ buffer << "#[Restart]";
+ continue; //fall through
+ case 'd':
+ case 'D': inputValues.clear();
+ buffer << "#[Discard]\n>";
+ inputValue.str("");
+ break;
+ case 'p':
+ case 'P': //Process
+ {
+ inputValue.str("");
+
+ for (std::size_t i = 0; i < inputValues.size(); ++i) {
+ InputVariable* inputVariable = engine->inputVariables().at(i);
+ inputVariable->setValue(inputValues.at(i));
+ }
+ std::vector<scalar> missingInputs;
+ for (std::size_t i = inputValues.size(); i < engine->inputVariables().size(); ++i) {
+ InputVariable* inputVariable = engine->inputVariables().at(i);
+ missingInputs.push_back(inputVariable->getValue());
+ }
+ inputValues.clear();
+ buffer << Op::join(missingInputs, space);
+ if (not missingInputs.empty()) buffer << space;
+ buffer << "=" << space;
+ try {
+ engine->process();
+ std::vector<scalar> outputValues;
+ for (std::size_t i = 0; i < engine->outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = engine->outputVariables().at(i);
+ outputVariable->defuzzify();
+ outputValues.push_back(outputVariable->getValue());
+ }
+ buffer << Op::join(outputValues, space) << "\n>";
+
+ } catch (std::exception& ex) {
+ buffer << "#[Error: " << ex.what() << "]";
+ }
+ break;
+ }
+ case 'q':
+ case 'Q': buffer << "#[Quit]\n";
+ break;
+ case 'h':
+ case 'H': buffer << "\n>" << interactiveHelp() << "\n>";
+ inputValue.str("");
+ break;
+ }
+ } while (not (ch == 'Q' or ch == 'q' or ch == 4));
+ writer << std::endl;
+ }
+
+ std::string Console::interactiveHelp() {
+ return
+ "#Special Keys\n"
+ "#=============\n"
+ "#\tR\tRestart engine and discard current inputs\n"
+ "#\tD\tDiscard current inputs\n"
+ "#\tP\tProcess engine\n"
+ "#\tQ\tQuit interactive console\n"
+ "#\tH\tShow this help\n"
+ "#=============\n";
+ }
+
+ Engine* Console::mamdani() {
+ Engine* engine = new Engine;
+ engine->setName("simple-dimmer");
+ engine->setDescription("");
+
+ InputVariable* ambient = new InputVariable;
+ ambient->setName("ambient");
+ ambient->setDescription("");
+ ambient->setEnabled(true);
+ ambient->setRange(0.000, 1.000);
+ ambient->setLockValueInRange(false);
+ ambient->addTerm(new Triangle("DARK", 0.000, 0.250, 0.500));
+ ambient->addTerm(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+ ambient->addTerm(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+ engine->addInputVariable(ambient);
+
+ OutputVariable* power = new OutputVariable;
+ power->setName("power");
+ power->setDescription("");
+ power->setEnabled(true);
+ power->setRange(0.000, 2.000);
+ power->setLockValueInRange(false);
+ power->setAggregation(new Maximum);
+ power->setDefuzzifier(new Centroid(200));
+ power->setDefaultValue(fl::nan);
+ power->setLockPreviousValue(false);
+ power->addTerm(new Triangle("LOW", 0.000, 0.500, 1.000));
+ power->addTerm(new Triangle("MEDIUM", 0.500, 1.000, 1.500));
+ power->addTerm(new Triangle("HIGH", 1.000, 1.500, 2.000));
+ engine->addOutputVariable(power);
+
+ RuleBlock* ruleBlock = new RuleBlock;
+ ruleBlock->setName("");
+ ruleBlock->setDescription("");
+ ruleBlock->setEnabled(true);
+ ruleBlock->setConjunction(fl::null);
+ ruleBlock->setDisjunction(fl::null);
+ ruleBlock->setImplication(new Minimum);
+ ruleBlock->setActivation(new General);
+ ruleBlock->addRule(Rule::parse("if ambient is DARK then power is HIGH", engine));
+ ruleBlock->addRule(Rule::parse("if ambient is MEDIUM then power is MEDIUM", engine));
+ ruleBlock->addRule(Rule::parse("if ambient is BRIGHT then power is LOW", engine));
+ engine->addRuleBlock(ruleBlock);
+
+ return engine;
+ }
+
+ Engine* Console::takagiSugeno() {
+ Engine* engine = new Engine;
+ engine->setName("approximation");
+ engine->setDescription("approximation of sin(x)/x");
+
+ InputVariable* inputX = new InputVariable;
+ inputX->setName("inputX");
+ inputX->setDescription("value of x");
+ inputX->setEnabled(true);
+ inputX->setRange(0.000, 10.000);
+ inputX->setLockValueInRange(false);
+ inputX->addTerm(new Triangle("NEAR_1", 0.000, 1.000, 2.000));
+ inputX->addTerm(new Triangle("NEAR_2", 1.000, 2.000, 3.000));
+ inputX->addTerm(new Triangle("NEAR_3", 2.000, 3.000, 4.000));
+ inputX->addTerm(new Triangle("NEAR_4", 3.000, 4.000, 5.000));
+ inputX->addTerm(new Triangle("NEAR_5", 4.000, 5.000, 6.000));
+ inputX->addTerm(new Triangle("NEAR_6", 5.000, 6.000, 7.000));
+ inputX->addTerm(new Triangle("NEAR_7", 6.000, 7.000, 8.000));
+ inputX->addTerm(new Triangle("NEAR_8", 7.000, 8.000, 9.000));
+ inputX->addTerm(new Triangle("NEAR_9", 8.000, 9.000, 10.000));
+ engine->addInputVariable(inputX);
+
+ OutputVariable* outputFx = new OutputVariable;
+ outputFx->setName("outputFx");
+ outputFx->setDescription("value of the approximation of x");
+ outputFx->setEnabled(true);
+ outputFx->setRange(-1.000, 1.000);
+ outputFx->setLockValueInRange(false);
+ outputFx->setAggregation(fl::null);
+ outputFx->setDefuzzifier(new WeightedAverage("Automatic"));
+ outputFx->setDefaultValue(fl::nan);
+ outputFx->setLockPreviousValue(true);
+ outputFx->addTerm(new Constant("f1", 0.840));
+ outputFx->addTerm(new Constant("f2", 0.450));
+ outputFx->addTerm(new Constant("f3", 0.040));
+ outputFx->addTerm(new Constant("f4", -0.180));
+ outputFx->addTerm(new Constant("f5", -0.190));
+ outputFx->addTerm(new Constant("f6", -0.040));
+ outputFx->addTerm(new Constant("f7", 0.090));
+ outputFx->addTerm(new Constant("f8", 0.120));
+ outputFx->addTerm(new Constant("f9", 0.040));
+ engine->addOutputVariable(outputFx);
+
+ OutputVariable* trueValue = new OutputVariable;
+ trueValue->setName("trueValue");
+ trueValue->setDescription("value of f(x)=sin(x)/x");
+ trueValue->setEnabled(true);
+ trueValue->setRange(-1.060, 1.000);
+ trueValue->setLockValueInRange(false);
+ trueValue->setAggregation(fl::null);
+ trueValue->setDefuzzifier(new WeightedAverage("Automatic"));
+ trueValue->setDefaultValue(fl::nan);
+ trueValue->setLockPreviousValue(true);
+ trueValue->addTerm(Function::create("fx", "sin(inputX)/inputX", engine));
+ engine->addOutputVariable(trueValue);
+
+ OutputVariable* difference = new OutputVariable;
+ difference->setName("difference");
+ difference->setDescription("error e=f(x) - f'(x)");
+ difference->setEnabled(true);
+ difference->setRange(-1.000, 1.000);
+ difference->setLockValueInRange(false);
+ difference->setAggregation(fl::null);
+ difference->setDefuzzifier(new WeightedAverage("Automatic"));
+ difference->setDefaultValue(fl::nan);
+ difference->setLockPreviousValue(false);
+ difference->addTerm(Function::create("error", "outputFx-trueValue", engine));
+ engine->addOutputVariable(difference);
+
+ RuleBlock* ruleBlock = new RuleBlock;
+ ruleBlock->setName("");
+ ruleBlock->setDescription("");
+ ruleBlock->setEnabled(true);
+ ruleBlock->setConjunction(fl::null);
+ ruleBlock->setDisjunction(fl::null);
+ ruleBlock->setImplication(new AlgebraicProduct);
+ ruleBlock->setActivation(new General);
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_1 then outputFx is f1", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_2 then outputFx is f2", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_3 then outputFx is f3", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_4 then outputFx is f4", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_5 then outputFx is f5", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_6 then outputFx is f6", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_7 then outputFx is f7", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_8 then outputFx is f8", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is NEAR_9 then outputFx is f9", engine));
+ ruleBlock->addRule(Rule::parse("if inputX is any then trueValue is fx and difference is error", engine));
+ engine->addRuleBlock(ruleBlock);
+
+ return engine;
+ }
+
+ Engine* Console::hybrid() {
+ Engine* engine = new Engine;
+ engine->setName("tipper");
+ engine->setDescription("(service and food) -> (tip)");
+
+ InputVariable* service = new InputVariable;
+ service->setName("service");
+ service->setDescription("quality of service");
+ service->setEnabled(true);
+ service->setRange(0.000, 10.000);
+ service->setLockValueInRange(true);
+ service->addTerm(new Trapezoid("poor", 0.000, 0.000, 2.500, 5.000));
+ service->addTerm(new Triangle("good", 2.500, 5.000, 7.500));
+ service->addTerm(new Trapezoid("excellent", 5.000, 7.500, 10.000, 10.000));
+ engine->addInputVariable(service);
+
+ InputVariable* food = new InputVariable;
+ food->setName("food");
+ food->setDescription("quality of food");
+ food->setEnabled(true);
+ food->setRange(0.000, 10.000);
+ food->setLockValueInRange(true);
+ food->addTerm(new Trapezoid("rancid", 0.000, 0.000, 2.500, 7.500));
+ food->addTerm(new Trapezoid("delicious", 2.500, 7.500, 10.000, 10.000));
+ engine->addInputVariable(food);
+
+ OutputVariable* mTip = new OutputVariable;
+ mTip->setName("mTip");
+ mTip->setDescription("tip based on Mamdani inference");
+ mTip->setEnabled(true);
+ mTip->setRange(0.000, 30.000);
+ mTip->setLockValueInRange(false);
+ mTip->setAggregation(new Maximum);
+ mTip->setDefuzzifier(new Centroid(100));
+ mTip->setDefaultValue(fl::nan);
+ mTip->setLockPreviousValue(false);
+ mTip->addTerm(new Triangle("cheap", 0.000, 5.000, 10.000));
+ mTip->addTerm(new Triangle("average", 10.000, 15.000, 20.000));
+ mTip->addTerm(new Triangle("generous", 20.000, 25.000, 30.000));
+ engine->addOutputVariable(mTip);
+
+ OutputVariable* tsTip = new OutputVariable;
+ tsTip->setName("tsTip");
+ tsTip->setDescription("tip based on Takagi-Sugeno inference");
+ tsTip->setEnabled(true);
+ tsTip->setRange(0.000, 30.000);
+ tsTip->setLockValueInRange(false);
+ tsTip->setAggregation(fl::null);
+ tsTip->setDefuzzifier(new WeightedAverage("TakagiSugeno"));
+ tsTip->setDefaultValue(fl::nan);
+ tsTip->setLockPreviousValue(false);
+ tsTip->addTerm(new Constant("cheap", 5.000));
+ tsTip->addTerm(new Constant("average", 15.000));
+ tsTip->addTerm(new Constant("generous", 25.000));
+ engine->addOutputVariable(tsTip);
+
+ RuleBlock* mamdaniRuleBlock = new RuleBlock;
+ mamdaniRuleBlock->setName("mamdani");
+ mamdaniRuleBlock->setDescription("Mamdani inference");
+ mamdaniRuleBlock->setEnabled(true);
+ mamdaniRuleBlock->setConjunction(new AlgebraicProduct);
+ mamdaniRuleBlock->setDisjunction(new AlgebraicSum);
+ mamdaniRuleBlock->setImplication(new Minimum);
+ mamdaniRuleBlock->setActivation(new General);
+ mamdaniRuleBlock->addRule(Rule::parse("if service is poor or food is rancid then mTip is cheap", engine));
+ mamdaniRuleBlock->addRule(Rule::parse("if service is good then mTip is average", engine));
+ mamdaniRuleBlock->addRule(Rule::parse("if service is excellent or food is delicious then mTip is generous with 0.5", engine));
+ mamdaniRuleBlock->addRule(Rule::parse("if service is excellent and food is delicious then mTip is generous with 1.0", engine));
+ engine->addRuleBlock(mamdaniRuleBlock);
+
+ RuleBlock* takagiSugenoRuleBlock = new RuleBlock;
+ takagiSugenoRuleBlock->setName("takagiSugeno");
+ takagiSugenoRuleBlock->setDescription("Takagi-Sugeno inference");
+ takagiSugenoRuleBlock->setEnabled(true);
+ takagiSugenoRuleBlock->setConjunction(new AlgebraicProduct);
+ takagiSugenoRuleBlock->setDisjunction(new AlgebraicSum);
+ takagiSugenoRuleBlock->setImplication(fl::null);
+ takagiSugenoRuleBlock->setActivation(new General);
+ takagiSugenoRuleBlock->addRule(Rule::parse("if service is poor or food is rancid then tsTip is cheap", engine));
+ takagiSugenoRuleBlock->addRule(Rule::parse("if service is good then tsTip is average", engine));
+ takagiSugenoRuleBlock->addRule(Rule::parse("if service is excellent or food is delicious then tsTip is generous with 0.5", engine));
+ takagiSugenoRuleBlock->addRule(Rule::parse("if service is excellent and food is delicious then tsTip is generous with 1.0", engine));
+ engine->addRuleBlock(takagiSugenoRuleBlock);
+
+ return engine;
+ }
+
+ void Console::exportAllExamples(const std::string& from, const std::string& to) {
+ Console::exportAllExamples(from, to, "./", "/tmp/");
+ }
+
+ void Console::exportAllExamples(const std::string& from, const std::string& to,
+ const std::string& sourcePath, const std::string& targetPath) {
+ std::vector<std::string> examples;
+ examples.push_back("mamdani/AllTerms");
+ examples.push_back("mamdani/SimpleDimmer");
+ examples.push_back("mamdani/Laundry");
+ examples.push_back("mamdani/ObstacleAvoidance");
+ examples.push_back("mamdani/SimpleDimmerChained");
+ examples.push_back("mamdani/SimpleDimmerInverse");
+ examples.push_back("mamdani/matlab/mam21");
+ examples.push_back("mamdani/matlab/mam22");
+ examples.push_back("mamdani/matlab/shower");
+ examples.push_back("mamdani/matlab/tank");
+ examples.push_back("mamdani/matlab/tank2");
+ examples.push_back("mamdani/matlab/tipper");
+ examples.push_back("mamdani/matlab/tipper1");
+ examples.push_back("mamdani/octave/investment_portfolio");
+ examples.push_back("mamdani/octave/mamdani_tip_calculator");
+ examples.push_back("takagi-sugeno/approximation");
+ examples.push_back("takagi-sugeno/ObstacleAvoidance");
+ examples.push_back("takagi-sugeno/SimpleDimmer");
+ examples.push_back("takagi-sugeno/matlab/fpeaks");
+ examples.push_back("takagi-sugeno/matlab/invkine1");
+ examples.push_back("takagi-sugeno/matlab/invkine2");
+ examples.push_back("takagi-sugeno/matlab/juggler");
+ examples.push_back("takagi-sugeno/matlab/membrn1");
+ examples.push_back("takagi-sugeno/matlab/membrn2");
+ examples.push_back("takagi-sugeno/matlab/slbb");
+ examples.push_back("takagi-sugeno/matlab/slcp");
+ examples.push_back("takagi-sugeno/matlab/slcp1");
+ examples.push_back("takagi-sugeno/matlab/slcpp1");
+ examples.push_back("takagi-sugeno/matlab/sltbu_fl");
+ examples.push_back("takagi-sugeno/matlab/sugeno1");
+ examples.push_back("takagi-sugeno/matlab/tanksg");
+ examples.push_back("takagi-sugeno/matlab/tippersg");
+ examples.push_back("takagi-sugeno/octave/cubic_approximator");
+ examples.push_back("takagi-sugeno/octave/heart_disease_risk");
+ examples.push_back("takagi-sugeno/octave/linear_tip_calculator");
+ examples.push_back("takagi-sugeno/octave/sugeno_tip_calculator");
+ examples.push_back("tsukamoto/tsukamoto");
+ examples.push_back("hybrid/tipper");
+ examples.push_back("hybrid/ObstacleAvoidance");
+
+ FL_unique_ptr<Importer> importer;
+ if (from == "fll") importer.reset(new FllImporter);
+ else if (from == "fis") importer.reset(new FisImporter);
+ else if (from == "fcl") importer.reset(new FclImporter);
+ else throw Exception("[examples error] unrecognized format <" + from + "> to import", FL_AT);
+
+ FL_unique_ptr<Exporter> exporter;
+ if (to == "fll") exporter.reset(new FllExporter);
+ else if (to == "fld") exporter.reset(new FldExporter(" "));
+ else if (to == "fcl") exporter.reset(new FclExporter);
+ else if (to == "fis") exporter.reset(new FisExporter);
+ else if (to == "cpp") exporter.reset(new CppExporter);
+ else if (to == "java") exporter.reset(new JavaExporter);
+ else if (to == "R") exporter.reset(new RScriptExporter());
+ else throw Exception("[examples error] unrecognized format <" + to + "> to export", FL_AT);
+
+ std::vector<std::pair<Exporter*, Importer*> > tests;
+ tests.push_back(std::pair<Exporter*, Importer*>(new FllExporter, new FllImporter));
+ tests.push_back(std::pair<Exporter*, Importer*>(new FisExporter, new FisImporter));
+ tests.push_back(std::pair<Exporter*, Importer*>(new FclExporter, new FclImporter));
+ for (std::size_t i = 0; i < examples.size(); ++i) {
+ std::string example = examples.at(i);
+ FL_LOG((i + 1) << "/" << examples.size());
+ FL_LOG("Importing from: " << sourcePath << "/" << example << "." << from);
+ std::ostringstream ss;
+ std::string input = sourcePath + "/" + example + "." + from;
+ std::ifstream source(input.c_str());
+ if (source.is_open()) {
+ std::string line;
+ while (source.good()) {
+ std::getline(source, line);
+ ss << line << "\n";
+ }
+ source.close();
+ } else throw Exception("[examples error] file not found: " + input, FL_AT);
+
+ FL_unique_ptr<Engine> engine(importer->fromString(ss.str()));
+
+ for (std::size_t t = 0; t < tests.size(); ++t) {
+ if ("mamdani/Laundry" == example
+ or "mamdani/SimpleDimmerInverse" == example
+ or "mamdani/SimpleDimmerChained" == example
+ or "hybrid/tipper" == example
+ or "hybrid/ObstacleAvoidance" == example) {
+ if (tests.at(t).second->name() == FisImporter().name()) {
+ continue;
+ }
+ }
+
+ std::string exported = tests.at(t).first->toString(engine.get());
+ FL_unique_ptr<Engine> engineFromExport(tests.at(t).second->fromString(exported));
+ std::string imported = tests.at(t).first->toString(engineFromExport.get());
+
+ if (exported != imported) {
+ std::ostringstream msg;
+ msg << "[imex error] different results <"
+ << tests.at(t).first->name() << "," << tests.at(t).second->name() << "> "
+ "at " << example << "." << from << ":\n";
+ msg << "<Engine A>\n" << exported << "\n\n" <<
+ "================================\n\n" <<
+ "<Engine B>\n" << imported;
+ throw Exception(msg.str(), FL_AT);
+ }
+ }
+
+ std::string output = targetPath + "/" + example + "." + to;
+ std::ofstream target(output.c_str());
+ FL_LOG("Exporting to: " << output << "\n");
+ if (target.is_open()) {
+ if (to == "cpp") {
+ target << "#include <fl/Headers.h>\n\n"
+ << "int main(int argc, char** argv){\n"
+ << exporter->toString(engine.get())
+ << "\n}\n";
+ } else if (to == "java") {
+ std::string className = example.substr(example.find_last_of('/') + 1);
+ target << "import com.fuzzylite.*;\n"
+ << "import com.fuzzylite.activation.*\n"
+ << "import com.fuzzylite.defuzzifier.*;\n"
+ << "import com.fuzzylite.factory.*;\n"
+ << "import com.fuzzylite.hedge.*;\n"
+ << "import com.fuzzylite.imex.*;\n"
+ << "import com.fuzzylite.norm.*;\n"
+ << "import com.fuzzylite.norm.s.*;\n"
+ << "import com.fuzzylite.norm.t.*;\n"
+ << "import com.fuzzylite.rule.*;\n"
+ << "import com.fuzzylite.term.*;\n"
+ << "import com.fuzzylite.variable.*;\n\n"
+ << "public class " << Op::validName(className) << "{\n"
+ << "public static void main(String[] args){\n"
+ << exporter->toString(engine.get())
+ << "\n}\n}\n";
+ } else if (to == "R") {
+ RScriptExporter* rScript = dynamic_cast<RScriptExporter*> (exporter.get());
+ InputVariable* a = engine->getInputVariable(0);
+ InputVariable* b = engine->getInputVariable(1 % engine->numberOfInputVariables());
+ std::string pathToDF = example.substr(example.find_last_of('/') + 1) + ".fld";
+ rScript->writeScriptImportingDataFrame(engine.get(), target,
+ a, b, pathToDF, engine->outputVariables());
+ } else {
+ target << exporter->toString(engine.get());
+ }
+ target.close();
+ }
+ Engine copyConstructor(*engine.get());
+ FL_IUNUSED(copyConstructor);
+ Engine assignmentOperator = *engine.get();
+ FL_IUNUSED(assignmentOperator);
+ }
+ FL_LOG("Please, make sure the output contains the following structure:\n"
+ "mkdir -p " << targetPath << "mamdani/matlab; "
+ "mkdir -p " << targetPath << "mamdani/octave; "
+ "mkdir -p " << targetPath << "takagi-sugeno/matlab; "
+ "mkdir -p " << targetPath << "takagi-sugeno/octave; "
+ "mkdir -p " << targetPath << "tsukamoto; "
+ "mkdir -p " << targetPath << "hybrid;");
+ for (std::size_t i = 0; i < tests.size(); ++i) {
+ delete tests.at(i).first;
+ delete tests.at(i).second;
+ }
+ }
+
+ void Console::benchmark(const std::string& fllFile, const std::string& fldFile,
+ int runs, std::ofstream* writer) const {
+ FL_unique_ptr<Engine> engine(FllImporter().fromFile(fllFile));
+ std::ifstream reader(fldFile.c_str());
+ if (not reader.is_open()) {
+ throw Exception("File <" + fldFile + "> could not be opened");
+ }
+ Benchmark benchmark(engine->getName(), engine.get());
+ benchmark.prepare(reader);
+ if (writer) {
+ FL_LOG("\tEvaluating on " << benchmark.getExpected().size() <<
+ " values read from " << fldFile << " ...");
+ }
+ for (int i = 0; i < runs; ++i) {
+ benchmark.runOnce();
+ }
+ if (writer) {
+ FL_LOG("\tMean(t)=" << Op::mean(benchmark.getTimes()) << " nanoseconds");
+ *writer << benchmark.format(benchmark.results(),
+ Benchmark::Horizontal, Benchmark::Body) << "\n";
+ } else {
+ FL_LOGP(benchmark.format(benchmark.results(),
+ Benchmark::Horizontal, Benchmark::Body));
+ }
+ }
+
+ void Console::benchmarks(const std::string& fllFileList,
+ const std::string& fldFileList, int runs, std::ofstream* writer) const {
+ std::vector<std::string> fllFiles, fldFiles;
+
+ {
+ std::ifstream fllReader(fllFileList.c_str());
+ if (not fllReader.is_open()) {
+ throw Exception("[error] file <" + fllFileList + "> could not be opened");
+ }
+ std::ifstream fldReader(fldFileList.c_str());
+ if (not fldReader.is_open()) {
+ throw Exception("[error] file <" + fldFileList + "> could not be opened");
+ }
+
+ std::string fllLine, fldLine;
+ while (std::getline(fllReader, fllLine) and std::getline(fldReader, fldLine)) {
+ fllLine = Op::trim(fllLine);
+ fldLine = Op::trim(fldLine);
+ if (fllLine.empty() or fllLine[0] == '#')
+ continue;
+ fllFiles.push_back(fllLine);
+ fldFiles.push_back(fldLine);
+ }
+ }
+
+ if (writer) {
+ *writer << Op::join(Benchmark().header(runs, true), "\t") << "\n";
+ } else {
+ FL_LOGP(Op::join(Benchmark().header(runs, true), "\t"));
+ }
+
+ for (std::size_t i = 0; i < fllFiles.size(); ++i) {
+ if (writer) {
+ FL_LOG("Benchmark " << (i + 1) << "/" << fllFiles.size() << ": "
+ << fllFiles.at(i));
+ }
+ benchmark(fllFiles.at(i), fldFiles.at(i), runs, writer);
+ }
+ }
+
+ int Console::main(int argc, const char* argv[]) {
+ fuzzylite::setLogging(true);
+
+ Console console;
+ if (argc <= 2) {
+ FL_LOGP(console.usage() << "\n");
+ return EXIT_SUCCESS;
+ }
+
+ const std::string firstArgument(argv[1]);
+ if (firstArgument == "export-examples") {
+ std::string path = ".";
+ if (argc > 2) {
+ path = std::string(argv[2]);
+ }
+ std::string outputPath = "/tmp/";
+ if (argc > 3) {
+ outputPath = std::string(argv[3]);
+ }
+ FL_LOG("Origin=" << path);
+ FL_LOG("Target=" << outputPath);
+ fuzzylite::setDecimals(3);
+ try {
+ FL_LOG("Processing fll->fll");
+ console.exportAllExamples("fll", "fll", path, outputPath);
+ FL_LOG("Processing fll->fcl");
+ console.exportAllExamples("fll", "fcl", path, outputPath);
+ FL_LOG("Processing fll->fis");
+ console.exportAllExamples("fll", "fis", path, outputPath);
+ FL_LOG("Processing fll->cpp");
+ console.exportAllExamples("fll", "cpp", path, outputPath);
+ FL_LOG("Processing fll->java");
+ console.exportAllExamples("fll", "java", path, outputPath);
+ FL_LOG("Processing fll->R");
+ console.exportAllExamples("fll", "R", path, outputPath);
+ fuzzylite::setDecimals(9);
+ FL_LOG("Processing fll->fld");
+ console.exportAllExamples("fll", "fld", path, outputPath);
+ FL_LOG("Origin=" << path);
+ FL_LOG("Target=" << outputPath);
+ } catch (std::exception& ex) {
+ FL_LOGP(ex.what() << "\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+
+ } else if (firstArgument == "benchmark") {
+ if (argc < 5) {
+ FL_LOG("[error] not enough parameters");
+ return EXIT_FAILURE;
+ }
+ std::string fllFile(argv[2]);
+ std::string fldFile(argv[3]);
+ try {
+ int runs = (int) Op::toScalar(argv[4]);
+ if (argc > 5) {
+ std::string filename(argv[5]);
+ std::ofstream outputFile;
+ outputFile.open(filename.c_str());
+ if (not outputFile.is_open()) {
+ FL_LOG("[error] cannot create file <" << filename << ">");
+ return EXIT_FAILURE;
+ }
+ outputFile << Op::join(Benchmark().header(runs, true), "\t") << "\n";
+ console.benchmark(fllFile, fldFile, runs, &outputFile);
+ } else {
+ FL_LOGP(Op::join(Benchmark().header(runs, true), "\t"));
+ console.benchmark(fllFile, fldFile, runs, fl::null);
+ }
+ } catch (std::exception& ex) {
+ FL_LOGP(ex.what() << "\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+
+ } else if (firstArgument == "benchmarks") {
+ if (argc < 5) {
+ FL_LOG("[error] not enough parameters");
+ return EXIT_FAILURE;
+ }
+ std::string fllFiles(argv[2]);
+ std::string fldFiles(argv[3]);
+ try {
+ int runs = (int) Op::toScalar(argv[4]);
+ if (argc > 5) {
+ std::string filename(argv[5]);
+ std::ofstream outputFile;
+ outputFile.open(filename.c_str());
+ if (not outputFile.is_open()) {
+ FL_LOG("[error] cannot create file <" << filename << ">");
+ return EXIT_FAILURE;
+ }
+ console.benchmarks(fllFiles, fldFiles, runs, &outputFile);
+ } else {
+ console.benchmarks(fllFiles, fldFiles, runs, fl::null);
+ }
+ } catch (std::exception& ex) {
+ FL_LOGP(ex.what() << "\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+
+ //MAIN:
+ try {
+ std::map<std::string, std::string> options = console.parse(argc, argv);
+ console.process(options);
+
+ } catch (std::exception& ex) {
+ FL_LOGP(ex.what() << "\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+
+}
diff --git a/fuzzylite/src/Engine.cpp b/fuzzylite/src/Engine.cpp
new file mode 100644
index 0000000..dbe4b17
--- /dev/null
+++ b/fuzzylite/src/Engine.cpp
@@ -0,0 +1,716 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Engine.h"
+
+#include "fl/activation/General.h"
+#include "fl/defuzzifier/WeightedAverage.h"
+#include "fl/defuzzifier/WeightedSum.h"
+#include "fl/factory/DefuzzifierFactory.h"
+#include "fl/factory/FactoryManager.h"
+#include "fl/imex/FllExporter.h"
+#include "fl/norm/t/AlgebraicProduct.h"
+#include "fl/rule/Consequent.h"
+#include "fl/rule/Expression.h"
+#include "fl/rule/Rule.h"
+#include "fl/rule/RuleBlock.h"
+#include "fl/term/Aggregated.h"
+#include "fl/term/Constant.h"
+#include "fl/term/Linear.h"
+#include "fl/term/Ramp.h"
+#include "fl/term/Sigmoid.h"
+#include "fl/term/SShape.h"
+#include "fl/term/ZShape.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+namespace fl {
+
+ Engine::Engine(const std::string& name) : _name(name) { }
+
+ Engine::Engine(const Engine& other) : _name(""), _description("") {
+ copyFrom(other);
+ }
+
+ Engine& Engine::operator=(const Engine& other) {
+ if (this != &other) {
+ for (std::size_t i = 0; i < _ruleBlocks.size(); ++i)
+ delete _ruleBlocks.at(i);
+ _ruleBlocks.clear();
+ for (std::size_t i = 0; i < _outputVariables.size(); ++i)
+ delete _outputVariables.at(i);
+ _outputVariables.clear();
+ for (std::size_t i = 0; i < _inputVariables.size(); ++i)
+ delete _inputVariables.at(i);
+ _inputVariables.clear();
+
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ void Engine::copyFrom(const Engine& other) {
+ _name = other._name;
+ _description = other._description;
+ for (std::size_t i = 0; i < other._inputVariables.size(); ++i)
+ _inputVariables.push_back(new InputVariable(*other._inputVariables.at(i)));
+ for (std::size_t i = 0; i < other._outputVariables.size(); ++i)
+ _outputVariables.push_back(new OutputVariable(*other._outputVariables.at(i)));
+
+ updateReferences();
+
+ for (std::size_t i = 0; i < other._ruleBlocks.size(); ++i) {
+ RuleBlock* ruleBlock = new RuleBlock(*other._ruleBlocks.at(i));
+ try {
+ ruleBlock->loadRules(this);
+ } catch (...) {
+ //ignore
+ }
+ _ruleBlocks.push_back(ruleBlock);
+ }
+ }
+
+ void Engine::updateReferences() const {
+ std::vector<Variable*> myVariables = variables();
+ for (std::size_t i = 0; i < myVariables.size(); ++i) {
+ Variable* variable = myVariables.at(i);
+ for (std::size_t t = 0; t < variable->numberOfTerms(); ++t) {
+ variable->getTerm(t)->updateReference(this);
+ }
+ }
+ }
+
+ Engine::~Engine() {
+ for (std::size_t i = 0; i < _ruleBlocks.size(); ++i)
+ delete _ruleBlocks.at(i);
+ for (std::size_t i = 0; i < _outputVariables.size(); ++i)
+ delete _outputVariables.at(i);
+ for (std::size_t i = 0; i < _inputVariables.size(); ++i)
+ delete _inputVariables.at(i);
+ }
+
+ void Engine::configure(const std::string& conjunction, const std::string& disjunction,
+ const std::string& implication, const std::string& aggregation,
+ const std::string& defuzzifier, const std::string& activation) {
+ TNormFactory* tnormFactory = FactoryManager::instance()->tnorm();
+ SNormFactory* snormFactory = FactoryManager::instance()->snorm();
+ DefuzzifierFactory* defuzzFactory = FactoryManager::instance()->defuzzifier();
+ ActivationFactory* activationFactory = FactoryManager::instance()->activation();
+
+ TNorm* conjunctionObject = tnormFactory->constructObject(conjunction);
+ SNorm* disjunctionObject = snormFactory->constructObject(disjunction);
+ TNorm* implicationObject = tnormFactory->constructObject(implication);
+ SNorm* aggregationObject = snormFactory->constructObject(aggregation);
+ Defuzzifier* defuzzifierObject = defuzzFactory->constructObject(defuzzifier);
+ Activation* activationObject = activationFactory->constructObject(activation);
+
+ configure(conjunctionObject, disjunctionObject,
+ implicationObject, aggregationObject, defuzzifierObject,
+ activationObject);
+ }
+
+ void Engine::configure(TNorm* conjunction, SNorm* disjunction,
+ TNorm* implication, SNorm* aggregation, Defuzzifier* defuzzifier,
+ Activation* activation) {
+ for (std::size_t i = 0; i < numberOfRuleBlocks(); ++i) {
+ RuleBlock* ruleBlock = ruleBlocks().at(i);
+ ruleBlock->setConjunction(conjunction ? conjunction->clone() : fl::null);
+ ruleBlock->setDisjunction(disjunction ? disjunction->clone() : fl::null);
+ ruleBlock->setImplication(implication ? implication->clone() : fl::null);
+ ruleBlock->setActivation(activation ? activation->clone() : new General);
+ }
+
+ for (std::size_t i = 0; i < numberOfOutputVariables(); ++i) {
+ OutputVariable* outputVariable = getOutputVariable(i);
+ outputVariable->setDefuzzifier(defuzzifier ? defuzzifier->clone() : fl::null);
+ outputVariable->setAggregation(aggregation ? aggregation->clone() : fl::null);
+ }
+ if (defuzzifier) delete defuzzifier;
+ if (aggregation) delete aggregation;
+ if (implication) delete implication;
+ if (disjunction) delete disjunction;
+ if (conjunction) delete conjunction;
+ if (activation) delete activation;
+ }
+
+ bool Engine::isReady(std::string* status) const {
+ std::ostringstream ss;
+ if (inputVariables().empty()) {
+ ss << "- Engine <" << getName() << "> has no input variables\n";
+ }
+ for (std::size_t i = 0; i < inputVariables().size(); ++i) {
+ InputVariable* inputVariable = inputVariables().at(i);
+ if (not inputVariable) {
+ ss << "- Engine <" << getName() << "> has a fl::null input variable at index <" << i << ">\n";
+ }
+ /*else if (inputVariable->terms().empty()) {
+ ignore because sometimes inputs can be empty: takagi-sugeno/matlab/slcpp1.fis
+ ss << "- Input variable <" << _inputVariables.at(i)->getName() << ">"
+ << " has no terms\n";
+ }*/
+ }
+
+ if (outputVariables().empty()) {
+ ss << "- Engine <" << _name << "> has no output variables\n";
+ }
+ for (std::size_t i = 0; i < outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = outputVariables().at(i);
+ if (not outputVariable) {
+ ss << "- Engine <" << getName() << "> has a fl::null output variable at index <" << i << ">\n";
+ } else {
+ if (outputVariable->terms().empty()) {
+ ss << "- Output variable <" << outputVariable->getName() << ">"
+ << " has no terms\n";
+ }
+ Defuzzifier* defuzzifier = outputVariable->getDefuzzifier();
+ if (not defuzzifier) {
+ ss << "- Output variable <" << outputVariable->getName() << ">"
+ << " has no defuzzifier\n";
+ }
+ SNorm* aggregation = outputVariable->fuzzyOutput()->getAggregation();
+ if (not aggregation and dynamic_cast<IntegralDefuzzifier*> (defuzzifier)) {
+ ss << "- Output variable <" << outputVariable->getName() << ">"
+ << " has no aggregation operator\n";
+ }
+ }
+ }
+
+ if (ruleBlocks().empty()) {
+ ss << "- Engine <" << getName() << "> has no rule blocks\n";
+ }
+ for (std::size_t i = 0; i < ruleBlocks().size(); ++i) {
+ RuleBlock* ruleblock = ruleBlocks().at(i);
+ if (not ruleblock) {
+ ss << "- Engine <" << getName() << "> has a fl::null rule block at index <" << i << ">\n";
+ } else {
+ if (ruleblock->rules().empty()) {
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no rules\n";
+ }
+ int requiresConjunction = 0;
+ int requiresDisjunction = 0;
+ int requiresImplication = 0;
+ for (std::size_t r = 0; r < ruleblock->numberOfRules(); ++r) {
+ Rule* rule = ruleblock->getRule(r);
+ if (not rule) {
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName()
+ << "> has a fl::null rule at index <" << r << ">\n";
+ } else {
+ std::size_t thenIndex = rule->getText().find(" " + Rule::thenKeyword() + " ");
+ std::size_t andIndex = rule->getText().find(" " + Rule::andKeyword() + " ");
+ std::size_t orIndex = rule->getText().find(" " + Rule::orKeyword() + " ");
+ if (andIndex != std::string::npos and andIndex < thenIndex) {
+ ++requiresConjunction;
+ }
+ if (orIndex != std::string::npos and orIndex < thenIndex) {
+ ++requiresDisjunction;
+ }
+ if (rule->isLoaded()) {
+ Consequent* consequent = rule->getConsequent();
+ for (std::size_t c = 0; c < consequent->conclusions().size(); ++c) {
+ Proposition* proposition = consequent->conclusions().at(c);
+ const OutputVariable* outputVariable =
+ dynamic_cast<const OutputVariable*> (proposition->variable);
+ if (outputVariable and dynamic_cast<IntegralDefuzzifier*> (outputVariable->getDefuzzifier())) {
+ ++requiresImplication;
+ break;
+ }
+ }
+ }
+ }
+ }
+ const TNorm* conjunction = ruleblock->getConjunction();
+ if (requiresConjunction > 0 and not conjunction) {
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no conjunction operator\n";
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has "
+ << requiresConjunction << " rules that require conjunction operator\n";
+ }
+ const SNorm* disjunction = ruleblock->getDisjunction();
+ if (requiresDisjunction > 0 and not disjunction) {
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no disjunction operator\n";
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has "
+ << requiresDisjunction << " rules that require disjunction operator\n";
+ }
+ const TNorm* implication = ruleblock->getImplication();
+ if (requiresImplication > 0 and not implication) {
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no implication operator\n";
+ ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has "
+ << requiresImplication << " rules that require implication operator\n";
+ }
+ }
+ }
+ if (status) *status = ss.str();
+ return ss.str().empty();
+ }
+
+ void Engine::restart() {
+ for (std::size_t i = 0; i < inputVariables().size(); ++i) {
+ inputVariables().at(i)->setValue(fl::nan);
+ }
+ for (std::size_t i = 0; i < outputVariables().size(); ++i) {
+ outputVariables().at(i)->clear();
+ }
+ }
+
+ Complexity Engine::complexity() const {
+ Complexity result;
+ for (std::size_t i = 0; i < _ruleBlocks.size(); ++i) {
+ const RuleBlock* ruleBlock = _ruleBlocks.at(i);
+ if (ruleBlock->isEnabled()) {
+ result += ruleBlock->complexity();
+ }
+ }
+ return result;
+ }
+
+ void Engine::process() {
+ for (std::size_t i = 0; i < _outputVariables.size(); ++i) {
+ _outputVariables.at(i)->fuzzyOutput()->clear();
+ }
+
+ FL_DEBUG_BEGIN;
+ FL_DBG("===============");
+ FL_DBG("CURRENT INPUTS:");
+ for (std::size_t i = 0; i < _inputVariables.size(); ++i) {
+ InputVariable* inputVariable = _inputVariables.at(i);
+ scalar inputValue = inputVariable->getValue();
+ if (inputVariable->isEnabled()) {
+ FL_DBG(inputVariable->getName() << ".input = " << Op::str(inputValue));
+ FL_DBG(inputVariable->getName() << ".fuzzy = " << inputVariable->fuzzify(inputValue));
+ } else {
+ FL_DBG(inputVariable->getName() << ".enabled = false");
+ }
+ }
+ FL_DEBUG_END;
+
+
+ for (std::size_t i = 0; i < _ruleBlocks.size(); ++i) {
+ RuleBlock* ruleBlock = _ruleBlocks.at(i);
+ if (ruleBlock->isEnabled()) {
+ FL_DBG("===============");
+ FL_DBG("RULE BLOCK: " << ruleBlock->getName());
+ ruleBlock->activate();
+ }
+ }
+
+ for (std::size_t i = 0; i < _outputVariables.size(); ++i) {
+ _outputVariables.at(i)->defuzzify();
+ }
+
+ FL_DEBUG_BEGIN;
+ FL_DBG("===============");
+ FL_DBG("CURRENT OUTPUTS:");
+ for (std::size_t i = 0; i < _outputVariables.size(); ++i) {
+ OutputVariable* outputVariable = _outputVariables.at(i);
+ if (outputVariable->isEnabled()) {
+ FL_DBG(outputVariable->getName() << ".default = "
+ << outputVariable->getDefaultValue());
+
+ FL_DBG(outputVariable->getName() << ".lockValueInRange = "
+ << outputVariable->isLockValueInRange());
+
+ FL_DBG(outputVariable->getName() << ".lockPreviousValue= "
+ << outputVariable->isLockPreviousValue());
+
+ scalar output = outputVariable->getValue();
+ FL_DBG(outputVariable->getName() << ".output = " << output);
+ FL_DBG(outputVariable->getName() << ".fuzzy = " <<
+ outputVariable->fuzzify(output));
+ FL_DBG(outputVariable->fuzzyOutput()->toString());
+ } else {
+ FL_DBG(outputVariable->getName() << ".enabled = false");
+ }
+ }
+ FL_DBG("==============");
+ FL_DEBUG_END;
+ }
+
+ void Engine::setName(const std::string& name) {
+ this->_name = name;
+ }
+
+ std::string Engine::getName() const {
+ return this->_name;
+ }
+
+ void Engine::setDescription(const std::string& description) {
+ this->_description = description;
+ }
+
+ std::string Engine::getDescription() const {
+ return this->_description;
+ }
+
+ std::string Engine::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ Engine::Type Engine::type(std::string* name, std::string* reason) const {
+ if (outputVariables().empty()) {
+ if (name) *name = "Unknown";
+ if (reason) *reason = "- Engine has no output variables";
+ return Engine::Unknown;
+ }
+
+ //Mamdani
+ bool mamdani = true;
+ for (std::size_t i = 0; mamdani and i < outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = outputVariables().at(i);
+ //Defuzzifier must be integral
+ mamdani = mamdani and dynamic_cast<IntegralDefuzzifier*> (outputVariable->getDefuzzifier());
+ }
+ //Larsen
+ bool larsen = mamdani and not ruleBlocks().empty();
+ //Larsen is Mamdani with AlgebraicProduct as Implication
+ if (mamdani) {
+ for (std::size_t i = 0; larsen and i < ruleBlocks().size(); ++i) {
+ RuleBlock* ruleBlock = ruleBlocks().at(i);
+ larsen = larsen and dynamic_cast<const AlgebraicProduct*> (ruleBlock->getImplication());
+ }
+ }
+ if (larsen) {
+ if (name) *name = "Larsen";
+ if (reason) *reason = "- Output variables have integral defuzzifiers\n"
+ "- Implication in rule blocks is the algebraic product T-Norm";
+ return Engine::Larsen;
+ }
+ if (mamdani) {
+ if (name) *name = "Mamdani";
+ if (reason) *reason = "-Output variables have integral defuzzifiers";
+ return Engine::Mamdani;
+ }
+ //Else, keep checking
+
+ //TakagiSugeno
+ bool takagiSugeno = true;
+ for (std::size_t i = 0; takagiSugeno and i < outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = outputVariables().at(i);
+ //Defuzzifier is Weighted
+ WeightedDefuzzifier* weightedDefuzzifier =
+ dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier());
+
+ takagiSugeno = takagiSugeno and weightedDefuzzifier and
+ (weightedDefuzzifier->getType() == WeightedDefuzzifier::Automatic or
+ weightedDefuzzifier->getType() == WeightedDefuzzifier::TakagiSugeno);
+
+ if (takagiSugeno) {
+ //Takagi-Sugeno has only Constant, Linear or Function terms
+ for (std::size_t t = 0; takagiSugeno and t < outputVariable->numberOfTerms(); ++t) {
+ Term* term = outputVariable->getTerm(t);
+ takagiSugeno = takagiSugeno and
+ weightedDefuzzifier->inferType(term) == WeightedDefuzzifier::TakagiSugeno;
+ }
+ }
+ }
+ if (takagiSugeno) {
+ if (name) *name = "Takagi-Sugeno";
+ if (reason) *reason = "- Output variables have weighted defuzzifiers\n"
+ "- Output variables have constant, linear or function terms";
+ return Engine::TakagiSugeno;
+ }
+
+ //Tsukamoto
+ bool tsukamoto = true;
+ for (std::size_t i = 0; tsukamoto and i < outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = outputVariables().at(i);
+ //Defuzzifier is Weighted
+ WeightedDefuzzifier* weightedDefuzzifier =
+ dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier());
+
+ tsukamoto = tsukamoto and weightedDefuzzifier and
+ (weightedDefuzzifier->getType() == WeightedDefuzzifier::Automatic or
+ weightedDefuzzifier->getType() == WeightedDefuzzifier::Tsukamoto);
+ if (tsukamoto) {
+ //Tsukamoto has only monotonic terms: Concave, Ramp, Sigmoid, SShape, or ZShape
+ for (std::size_t t = 0; tsukamoto and t < outputVariable->numberOfTerms(); ++t) {
+ Term* term = outputVariable->getTerm(t);
+ tsukamoto = tsukamoto and term->isMonotonic();
+ }
+ }
+ }
+ if (tsukamoto) {
+ if (name) *name = "Tsukamoto";
+ if (reason) *reason = "- Output variables have weighted defuzzifiers\n"
+ "- Output variables only have monotonic terms";
+ return Engine::Tsukamoto;
+ }
+
+ //Inverse Tsukamoto
+ bool inverseTsukamoto = true;
+ for (std::size_t i = 0; inverseTsukamoto and i < outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = outputVariables().at(i);
+ //Defuzzifier cannot be integral
+ WeightedDefuzzifier* weightedDefuzzifier =
+ dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier());
+ inverseTsukamoto = inverseTsukamoto and weightedDefuzzifier;
+ }
+ if (inverseTsukamoto) {
+ if (name) *name = "Inverse Tsukamoto";
+ if (reason) *reason = "- Output variables have weighted defuzzifiers\n"
+ "- Output variables do not only have constant, linear or function terms\n"
+ "- Output variables do not only have monotonic terms";
+ return Engine::InverseTsukamoto;
+ }
+
+ bool hybrid = true;
+ for (std::size_t i = 0; i < outputVariables().size(); ++i) {
+ OutputVariable* outputVariable = outputVariables().at(i);
+ //Output variables have non-fl::null defuzzifiers
+ hybrid = hybrid and outputVariable->getDefuzzifier();
+ }
+ if (hybrid) {
+ if (name) *name = "Hybrid";
+ if (reason) *reason = "- Output variables have different types of defuzzifiers";
+ return Engine::Hybrid;
+ }
+
+ if (name) *name = "Unknown";
+ if (reason) *reason = "- One or more output variables do not have a defuzzifier";
+ return Engine::Unknown;
+ }
+
+ Engine* Engine::clone() const {
+ return new Engine(*this);
+ }
+
+ std::vector<Variable*> Engine::variables() const {
+ std::vector<Variable*> result;
+ result.reserve(inputVariables().size() + outputVariables().size());
+ result.insert(result.end(), inputVariables().begin(), inputVariables().end());
+ result.insert(result.end(), outputVariables().begin(), outputVariables().end());
+ return result;
+ }
+
+ /**
+ * Operations for InputVariables
+ */
+ void Engine::setInputValue(const std::string& name, scalar value) {
+ InputVariable* inputVariable = getInputVariable(name);
+ inputVariable->setValue(value);
+ }
+
+ void Engine::addInputVariable(InputVariable* inputVariable) {
+ inputVariables().push_back(inputVariable);
+ }
+
+ InputVariable* Engine::setInputVariable(InputVariable* inputVariable, std::size_t index) {
+ InputVariable* result = inputVariables().at(index);
+ inputVariables().at(index) = inputVariable;
+ return result;
+ }
+
+ void Engine::insertInputVariable(InputVariable* inputVariable, std::size_t index) {
+ inputVariables().insert(inputVariables().begin() + index, inputVariable);
+ }
+
+ InputVariable* Engine::getInputVariable(std::size_t index) const {
+ return inputVariables().at(index);
+ }
+
+ InputVariable* Engine::getInputVariable(const std::string& name) const {
+ for (std::size_t i = 0; i < inputVariables().size(); ++i) {
+ if (inputVariables().at(i)->getName() == name)
+ return inputVariables().at(i);
+ }
+ throw Exception("[engine error] input variable <" + name + "> not found", FL_AT);
+ }
+
+ bool Engine::hasInputVariable(const std::string& name) const {
+ for (std::size_t i = 0; i < inputVariables().size(); ++i) {
+ if (inputVariables().at(i)->getName() == name)
+ return true;
+ }
+ return false;
+ }
+
+ InputVariable* Engine::removeInputVariable(std::size_t index) {
+ InputVariable* result = inputVariables().at(index);
+ inputVariables().erase(inputVariables().begin() + index);
+ return result;
+ }
+
+ InputVariable* Engine::removeInputVariable(const std::string& name) {
+ for (std::size_t i = 0; i < inputVariables().size(); ++i) {
+ if (inputVariables().at(i)->getName() == name) {
+ InputVariable* result = inputVariables().at(i);
+ inputVariables().erase(inputVariables().begin() + i);
+ return result;
+ }
+ }
+ throw Exception("[engine error] input variable <" + name + "> not found", FL_AT);
+ }
+
+ std::size_t Engine::numberOfInputVariables() const {
+ return inputVariables().size();
+ }
+
+ const std::vector<InputVariable*>& Engine::inputVariables() const {
+ return this->_inputVariables;
+ }
+
+ void Engine::setInputVariables(const std::vector<InputVariable*>& inputVariables) {
+ this->_inputVariables = inputVariables;
+ }
+
+ std::vector<InputVariable*>& Engine::inputVariables() {
+ return this->_inputVariables;
+ }
+
+ /**
+ * Operations for OutputVariables
+ */
+ scalar Engine::getOutputValue(const std::string& name) {
+ OutputVariable* outputVariable = getOutputVariable(name);
+ return outputVariable->getValue();
+ }
+
+ void Engine::addOutputVariable(OutputVariable* outputVariable) {
+ outputVariables().push_back(outputVariable);
+ }
+
+ OutputVariable* Engine::setOutputVariable(OutputVariable* outputVariable, std::size_t index) {
+ OutputVariable* result = outputVariables().at(index);
+ outputVariables().at(index) = outputVariable;
+ return result;
+ }
+
+ void Engine::insertOutputVariable(OutputVariable* outputVariable, std::size_t index) {
+ outputVariables().insert(outputVariables().begin() + index, outputVariable);
+ }
+
+ OutputVariable* Engine::getOutputVariable(std::size_t index) const {
+ return outputVariables().at(index);
+ }
+
+ OutputVariable* Engine::getOutputVariable(const std::string& name) const {
+ for (std::size_t i = 0; i < outputVariables().size(); ++i) {
+ if (outputVariables().at(i)->getName() == name)
+ return outputVariables().at(i);
+ }
+ throw Exception("[engine error] output variable <" + name + "> not found", FL_AT);
+ }
+
+ bool Engine::hasOutputVariable(const std::string& name) const {
+ for (std::size_t i = 0; i < outputVariables().size(); ++i) {
+ if (outputVariables().at(i)->getName() == name)
+ return true;
+ }
+ return false;
+ }
+
+ OutputVariable* Engine::removeOutputVariable(std::size_t index) {
+ OutputVariable* result = outputVariables().at(index);
+ outputVariables().erase(outputVariables().begin() + index);
+ return result;
+ }
+
+ OutputVariable* Engine::removeOutputVariable(const std::string& name) {
+ for (std::size_t i = 0; i < outputVariables().size(); ++i) {
+ if (outputVariables().at(i)->getName() == name) {
+ OutputVariable* result = outputVariables().at(i);
+ outputVariables().erase(outputVariables().begin() + i);
+ return result;
+ }
+ }
+ throw Exception("[engine error] output variable <" + name + "> not found", FL_AT);
+ }
+
+ std::size_t Engine::numberOfOutputVariables() const {
+ return outputVariables().size();
+ }
+
+ const std::vector<OutputVariable*>& Engine::outputVariables() const {
+ return this->_outputVariables;
+ }
+
+ void Engine::setOutputVariables(const std::vector<OutputVariable*>& outputVariables) {
+ this->_outputVariables = outputVariables;
+ }
+
+ std::vector<OutputVariable*>& Engine::outputVariables() {
+ return this->_outputVariables;
+ }
+
+ /**
+ * Operations for iterable datatype _ruleblocks
+ */
+ void Engine::addRuleBlock(RuleBlock* ruleblock) {
+ ruleBlocks().push_back(ruleblock);
+ }
+
+ RuleBlock* Engine::setRuleBlock(RuleBlock* ruleBlock, std::size_t index) {
+ RuleBlock* result = ruleBlocks().at(index);
+ ruleBlocks().at(index) = ruleBlock;
+ return result;
+ }
+
+ void Engine::insertRuleBlock(RuleBlock* ruleblock, std::size_t index) {
+ ruleBlocks().insert(ruleBlocks().begin() + index, ruleblock);
+ }
+
+ RuleBlock* Engine::getRuleBlock(std::size_t index) const {
+ return ruleBlocks().at(index);
+ }
+
+ RuleBlock* Engine::getRuleBlock(const std::string& name) const {
+ for (std::size_t i = 0; i < ruleBlocks().size(); ++i) {
+ if (ruleBlocks().at(i)->getName() == name)
+ return ruleBlocks().at(i);
+ }
+ throw Exception("[engine error] rule block <" + name + "> not found", FL_AT);
+ }
+
+ bool Engine::hasRuleBlock(const std::string& name) const {
+ for (std::size_t i = 0; i < ruleBlocks().size(); ++i) {
+ if (ruleBlocks().at(i)->getName() == name)
+ return true;
+ }
+ return false;
+ }
+
+ RuleBlock* Engine::removeRuleBlock(std::size_t index) {
+ RuleBlock* result = ruleBlocks().at(index);
+ ruleBlocks().erase(ruleBlocks().begin() + index);
+ return result;
+ }
+
+ RuleBlock* Engine::removeRuleBlock(const std::string& name) {
+ for (std::size_t i = 0; i < ruleBlocks().size(); ++i) {
+ if (ruleBlocks().at(i)->getName() == name) {
+ RuleBlock* result = ruleBlocks().at(i);
+ ruleBlocks().erase(ruleBlocks().begin() + i);
+ return result;
+ }
+ }
+ throw Exception("[engine error] rule block <" + name + "> not found", FL_AT);
+ }
+
+ std::size_t Engine::numberOfRuleBlocks() const {
+ return ruleBlocks().size();
+ }
+
+ const std::vector<RuleBlock*>& Engine::ruleBlocks() const {
+ return this->_ruleBlocks;
+ }
+
+ void Engine::setRuleBlocks(const std::vector<RuleBlock*>& ruleBlocks) {
+ this->_ruleBlocks = ruleBlocks;
+ }
+
+ std::vector<RuleBlock*>& Engine::ruleBlocks() {
+ return this->_ruleBlocks;
+ }
+
+}
diff --git a/fuzzylite/src/Exception.cpp b/fuzzylite/src/Exception.cpp
new file mode 100644
index 0000000..1c27e70
--- /dev/null
+++ b/fuzzylite/src/Exception.cpp
@@ -0,0 +1,184 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Exception.h"
+
+
+#ifdef FL_BACKTRACE
+
+#ifdef FL_UNIX
+#include <execinfo.h>
+
+#elif defined FL_WINDOWS
+#include <windows.h>
+#include <winbase.h>
+
+#ifndef __MINGW32__
+/*Disable warning 8.1\Include\um\dbghelp.h(1544):
+warning C4091: 'typedef ': ignored on left of '' when no variable is declared*/
+#pragma warning (push)
+#pragma warning (disable:4091)
+#include <dbghelp.h>
+#pragma warning (pop)
+#endif
+
+#endif
+
+#endif
+
+
+#include <csignal>
+#include <cstring>
+
+namespace fl {
+
+ Exception::Exception(const std::string& what)
+ : std::exception(), _what(what) {
+ FL_DBG(this->what());
+ }
+
+ Exception::Exception(const std::string& what, const std::string& file, int line,
+ const std::string& function)
+ : std::exception(), _what(what) {
+ append(file, line, function);
+ FL_DBG(this->what());
+ }
+
+ Exception::~Exception() FL_INOEXCEPT { }
+
+ void Exception::setWhat(const std::string& what) {
+ this->_what = what;
+ }
+
+ std::string Exception::getWhat() const {
+ return this->_what;
+ }
+
+ const char* Exception::what() const FL_INOEXCEPT {
+ return this->_what.c_str();
+ }
+
+ void Exception::append(const std::string& whatElse) {
+ this->_what += whatElse + "\n";
+ }
+
+ void Exception::append(const std::string& file, int line, const std::string& function) {
+ std::ostringstream ss;
+ ss << "\n{at " << file << "::" << function << "() [line:" << line << "]}";
+ _what += ss.str();
+ }
+
+ void Exception::append(const std::string& whatElse,
+ const std::string& file, int line, const std::string& function) {
+ append(whatElse);
+ append(file, line, function);
+ }
+
+ std::string Exception::btCallStack() {
+#ifndef FL_BACKTRACE
+ return "[backtrace disabled] fuzzylite was built without -DFL_BACKTRACE";
+#elif defined FL_UNIX
+ std::ostringstream btStream;
+ const int bufferSize = 30;
+ void* buffer[bufferSize];
+ int backtraceSize = ::backtrace(buffer, bufferSize);
+ char **btSymbols = ::backtrace_symbols(buffer, backtraceSize);
+ if (btSymbols == fl::null) {
+ btStream << "[backtrace error] no symbols could be retrieved";
+ } else {
+ if (backtraceSize == 0) {
+ btStream << "[backtrace is empty]";
+ }
+ for (int i = 0; i < backtraceSize; ++i) {
+ btStream << btSymbols[i] << "\n";
+ }
+ }
+ ::free(btSymbols);
+ return btStream.str();
+
+
+#elif defined FL_WINDOWS && ! defined __MINGW32__
+ std::ostringstream btStream;
+ const int bufferSize = 30;
+ void* buffer[bufferSize];
+ SymInitialize(GetCurrentProcess(), fl::null, TRUE);
+
+ int backtraceSize = CaptureStackBackTrace(0, bufferSize, buffer, fl::null);
+ SYMBOL_INFO* btSymbol = (SYMBOL_INFO *) calloc(sizeof ( SYMBOL_INFO) + 256 * sizeof ( char), 1);
+ if (not btSymbol) {
+ btStream << "[backtrace error] no symbols could be retrieved";
+ } else {
+ btSymbol->MaxNameLen = 255;
+ btSymbol->SizeOfStruct = sizeof ( SYMBOL_INFO);
+ if (backtraceSize == 0) {
+ btStream << "[backtrace is empty]";
+ }
+ for (int i = 0; i < backtraceSize; ++i) {
+ SymFromAddr(GetCurrentProcess(), (DWORD64) (buffer[ i ]), 0, btSymbol);
+ btStream << (backtraceSize - i - 1) << ": " <<
+ btSymbol->Name << " at 0x" << btSymbol->Address << "\n";
+ }
+ }
+ ::free(btSymbol);
+ return btStream.str();
+#else
+ return "[backtrace missing] supported only in Unix and Windows platforms";
+#endif
+ }
+
+ void Exception::signalHandler(int unixSignal) {
+ std::ostringstream ex;
+ ex << "[unexpected signal " << unixSignal << "] ";
+#ifdef FL_UNIX
+ ex << ::strsignal(unixSignal);
+#endif
+ ex << "\nBACKTRACE:\n" << btCallStack();
+ Exception::catchException(Exception(ex.str(), FL_AT));
+ ::exit(EXIT_FAILURE);
+ }
+
+ void Exception::convertToException(int unixSignal) {
+ std::string signalDescription;
+#ifdef FL_UNIX
+ //Unblock the signal
+ sigset_t empty;
+ sigemptyset(&empty);
+ sigaddset(&empty, unixSignal);
+ sigprocmask(SIG_UNBLOCK, &empty, fl::null);
+ signalDescription = ::strsignal(unixSignal);
+#endif
+ std::ostringstream ex;
+ ex << "[signal " << unixSignal << "] " << signalDescription << "\n";
+ ex << "BACKTRACE:\n" << btCallStack();
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ void Exception::terminate() {
+ Exception::catchException(Exception("[unexpected exception] BACKTRACE:\n" + btCallStack(), FL_AT));
+ ::exit(EXIT_FAILURE);
+ }
+
+ void Exception::catchException(const std::exception& exception) {
+ std::ostringstream ss;
+ ss << exception.what();
+ std::string backtrace = btCallStack();
+ if (not backtrace.empty()) {
+ ss << "\n\nBACKTRACE:\n" << backtrace;
+ }
+ FL_LOG(ss.str());
+ }
+
+}
diff --git a/fuzzylite/src/activation/First.cpp b/fuzzylite/src/activation/First.cpp
new file mode 100644
index 0000000..fcf7484
--- /dev/null
+++ b/fuzzylite/src/activation/First.cpp
@@ -0,0 +1,122 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/First.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ First::First(int numberOfRules, scalar threshold) : Activation(),
+ _numberOfRules(numberOfRules), _threshold(threshold) { }
+
+ First::~First() { }
+
+ std::string First::className() const {
+ return "First";
+ }
+
+ std::string First::parameters() const {
+ return Op::str(getNumberOfRules()) + " " + Op::str(getThreshold());
+ }
+
+ void First::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] activation <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setNumberOfRules((int) Op::toScalar(values.at(0)));
+ setThreshold(Op::toScalar(values.at(1)));
+ }
+
+ Complexity First::complexity(const RuleBlock* ruleBlock) const {
+ Complexity result;
+
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ Complexity meanFiring;
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ result.comparison(1 + 3);
+ const Rule* rule = ruleBlock->getRule(i);
+ result += rule->complexityOfActivation(conjunction, disjunction);
+ meanFiring += rule->complexityOfFiring(implication);
+ }
+ meanFiring.divide(scalar(ruleBlock->numberOfRules()));
+
+ result += meanFiring.multiply(getNumberOfRules());
+ result += Complexity().arithmetic(1).multiply(getNumberOfRules());
+ return result;
+ }
+
+ void First::activate(RuleBlock* ruleBlock) {
+ FL_DBG("Activation: " << className() << " " << parameters());
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ int activated = 0;
+ for (std::vector<Rule*>::const_iterator it = ruleBlock->rules().begin();
+ it != ruleBlock->rules().end(); ++it) {
+ Rule* rule = (*it);
+ rule->deactivate();
+
+ if (rule->isLoaded()) {
+ scalar activationDegree = rule->activateWith(conjunction, disjunction);
+ if (activated < _numberOfRules
+ and Op::isGt(activationDegree, 0.0)
+ and Op::isGE(activationDegree, _threshold)) {
+ rule->trigger(implication);
+ ++activated;
+ }
+ }
+ }
+ }
+
+ void First::setNumberOfRules(int numberOfRules) {
+ this->_numberOfRules = numberOfRules;
+ }
+
+ int First::getNumberOfRules() const {
+ return this->_numberOfRules;
+ }
+
+ void First::setThreshold(scalar threshold) {
+ this->_threshold = threshold;
+ }
+
+ scalar First::getThreshold() const {
+ return this->_threshold;
+ }
+
+ First* First::clone() const {
+ return new First(*this);
+ }
+
+ Activation* First::constructor() {
+ return new First;
+ }
+
+}
+
diff --git a/fuzzylite/src/activation/General.cpp b/fuzzylite/src/activation/General.cpp
new file mode 100644
index 0000000..a42c588
--- /dev/null
+++ b/fuzzylite/src/activation/General.cpp
@@ -0,0 +1,77 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/General.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ General::General() : Activation() { }
+
+ General::~General() { }
+
+ std::string General::className() const {
+ return "General";
+ }
+
+ std::string General::parameters() const {
+ return "";
+ }
+
+ void General::configure(const std::string& parameters) {
+ FL_IUNUSED(parameters);
+ }
+
+ Complexity General::complexity(const RuleBlock* ruleBlock) const {
+ Complexity result;
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ result.comparison(1);
+ result += ruleBlock->getRule(i)->complexity(
+ ruleBlock->getConjunction(), ruleBlock->getDisjunction(),
+ ruleBlock->getImplication());
+ }
+ return result;
+ }
+
+ void General::activate(RuleBlock* ruleBlock) {
+ FL_DBG("Activation: " << className() << " " << parameters());
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ const std::size_t numberOfRules = ruleBlock->numberOfRules();
+ for (std::size_t i = 0; i < numberOfRules; ++i) {
+ Rule* rule = ruleBlock->getRule(i);
+ rule->deactivate();
+ if (rule->isLoaded()) {
+ rule->activateWith(conjunction, disjunction);
+ rule->trigger(implication);
+ }
+ }
+ }
+
+ General* General::clone() const {
+ return new General(*this);
+ }
+
+ Activation* General::constructor() {
+ return new General;
+ }
+
+}
diff --git a/fuzzylite/src/activation/Highest.cpp b/fuzzylite/src/activation/Highest.cpp
new file mode 100644
index 0000000..612c16b
--- /dev/null
+++ b/fuzzylite/src/activation/Highest.cpp
@@ -0,0 +1,120 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/Highest.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+#include <queue>
+
+namespace fl {
+
+ Highest::Highest(int numberOfRules) : Activation(), _numberOfRules(numberOfRules) { }
+
+ Highest::~Highest() { }
+
+ std::string Highest::className() const {
+ return "Highest";
+ }
+
+ std::string Highest::parameters() const {
+ return Op::str(getNumberOfRules());
+ }
+
+ void Highest::configure(const std::string& parameters) {
+ setNumberOfRules((int) Op::toScalar(parameters));
+ }
+
+ int Highest::getNumberOfRules() const {
+ return this->_numberOfRules;
+ }
+
+ void Highest::setNumberOfRules(int numberOfRules) {
+ this->_numberOfRules = numberOfRules;
+ }
+
+ Complexity Highest::complexity(const RuleBlock* ruleBlock) const {
+ //Cost of priority_queue:
+ //http://stackoverflow.com/questions/2974470/efficiency-of-the-stl-priority-queue
+ Complexity result;
+
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ Complexity meanFiring;
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ const Rule* rule = ruleBlock->getRule(i);
+ result += rule->complexityOfActivation(conjunction, disjunction);
+ meanFiring += rule->complexityOfFiring(implication);
+ }
+ meanFiring.divide(scalar(ruleBlock->numberOfRules()));
+
+ //Complexity of push is O(log n)
+ result += Complexity().function(1).multiply(ruleBlock->numberOfRules()
+ * std::log(scalar(ruleBlock->numberOfRules())));
+
+ result += Complexity().comparison(2).arithmetic(1).multiply(getNumberOfRules());
+ result += meanFiring.multiply(getNumberOfRules());
+ //Complexity of pop is 2 * O(log n)
+ result += Complexity().function(1).multiply(getNumberOfRules() *
+ 2 * std::log(scalar(ruleBlock->numberOfRules())));
+ return result;
+ }
+
+ struct Descending {
+
+ bool operator()(const Rule* a, const Rule* b) const {
+ return a->getActivationDegree() < b->getActivationDegree();
+ }
+ };
+
+ void Highest::activate(RuleBlock* ruleBlock) {
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ std::priority_queue<Rule*, std::vector<Rule*>, Descending> rulesToActivate;
+
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ Rule* rule = ruleBlock->getRule(i);
+ rule->deactivate();
+ if (rule->isLoaded()) {
+ scalar activationDegree = rule->activateWith(conjunction, disjunction);
+ if (Op::isGt(activationDegree, 0.0))
+ rulesToActivate.push(rule);
+ }
+ }
+
+ int activated = 0;
+ while (rulesToActivate.size() > 0 and activated++ < _numberOfRules) {
+ Rule* rule = rulesToActivate.top();
+ rule->trigger(implication);
+ rulesToActivate.pop();
+ }
+ }
+
+ Highest* Highest::clone() const {
+ return new Highest(*this);
+ }
+
+ Activation* Highest::constructor() {
+ return new Highest;
+ }
+
+}
diff --git a/fuzzylite/src/activation/Last.cpp b/fuzzylite/src/activation/Last.cpp
new file mode 100644
index 0000000..90b5dc9
--- /dev/null
+++ b/fuzzylite/src/activation/Last.cpp
@@ -0,0 +1,121 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/Last.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ Last::Last(int numberOfRules, scalar threshold) : Activation(),
+ _numberOfRules(numberOfRules), _threshold(threshold) { }
+
+ Last::~Last() { }
+
+ std::string Last::className() const {
+ return "Last";
+ }
+
+ std::string Last::parameters() const {
+ return Op::str(getNumberOfRules()) + " " + Op::str(getThreshold());
+ }
+
+ void Last::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] activation <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setNumberOfRules((int) Op::toScalar(values.at(0)));
+ setThreshold(Op::toScalar(values.at(1)));
+ }
+
+ void Last::setNumberOfRules(int numberOfRules) {
+ this->_numberOfRules = numberOfRules;
+ }
+
+ int Last::getNumberOfRules() const {
+ return this->_numberOfRules;
+ }
+
+ void Last::setThreshold(scalar threshold) {
+ this->_threshold = threshold;
+ }
+
+ scalar Last::getThreshold() const {
+ return this->_threshold;
+ }
+
+ Complexity Last::complexity(const RuleBlock* ruleBlock) const {
+ Complexity result;
+
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ Complexity meanFiring;
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ result.comparison(1 + 3);
+ const Rule* rule = ruleBlock->getRule(i);
+ result += rule->complexityOfActivation(conjunction, disjunction);
+ meanFiring += rule->complexityOfFiring(implication);
+ }
+ meanFiring.divide(scalar(ruleBlock->numberOfRules()));
+
+ result += meanFiring.multiply(getNumberOfRules());
+ result += Complexity().arithmetic(1).multiply(getNumberOfRules());
+ return result;
+ }
+
+ void Last::activate(RuleBlock* ruleBlock) {
+ FL_DBG("Activation: " << className() << " " << parameters());
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ int activated = 0;
+ for (std::vector<Rule*>::const_reverse_iterator it = ruleBlock->rules().rbegin();
+ it != ruleBlock->rules().rend(); ++it) {
+ Rule* rule = (*it);
+ rule->deactivate();
+
+ if (rule->isLoaded()) {
+ scalar activationDegree = rule->activateWith(conjunction, disjunction);
+ if (activated < _numberOfRules
+ and Op::isGt(activationDegree, 0.0)
+ and Op::isGE(activationDegree, _threshold)) {
+ rule->trigger(implication);
+ ++activated;
+ }
+ }
+ }
+ }
+
+ Last* Last::clone() const {
+ return new Last(*this);
+ }
+
+ Activation* Last::constructor() {
+ return new Last;
+ }
+
+}
diff --git a/fuzzylite/src/activation/Lowest.cpp b/fuzzylite/src/activation/Lowest.cpp
new file mode 100644
index 0000000..52e7e85
--- /dev/null
+++ b/fuzzylite/src/activation/Lowest.cpp
@@ -0,0 +1,122 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/Lowest.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+#include <queue>
+
+namespace fl {
+
+ Lowest::Lowest(int numberOfRules) : Activation(), _numberOfRules(numberOfRules) { }
+
+ Lowest::~Lowest() { }
+
+ std::string Lowest::className() const {
+ return "Lowest";
+ }
+
+ std::string Lowest::parameters() const {
+ return Op::str(getNumberOfRules());
+ }
+
+ void Lowest::configure(const std::string& parameters) {
+ setNumberOfRules((int) Op::toScalar(parameters));
+ }
+
+ int Lowest::getNumberOfRules() const {
+ return this->_numberOfRules;
+ }
+
+ void Lowest::setNumberOfRules(int activatedRules) {
+ this->_numberOfRules = activatedRules;
+ }
+
+ Complexity Lowest::complexity(const RuleBlock* ruleBlock) const {
+ //Cost of priority_queue:
+ //http://stackoverflow.com/questions/2974470/efficiency-of-the-stl-priority-queue
+ Complexity result;
+
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ Complexity meanFiring;
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ const Rule* rule = ruleBlock->getRule(i);
+ result.comparison(2);
+ result += rule->complexityOfActivation(conjunction, disjunction);
+ meanFiring += rule->complexityOfFiring(implication);
+ }
+ meanFiring.divide(scalar(ruleBlock->numberOfRules()));
+
+ //Complexity of push is O(log n)
+ result += Complexity().function(1).multiply(ruleBlock->numberOfRules()
+ * std::log(scalar(ruleBlock->numberOfRules())));
+
+ result += Complexity().comparison(2).arithmetic(1).multiply(getNumberOfRules());
+ result += meanFiring.multiply(getNumberOfRules());
+ //Complexity of pop is 2 * O(log n)
+ result += Complexity().function(1).multiply(getNumberOfRules() *
+ 2 * std::log(scalar(ruleBlock->numberOfRules())));
+ return result;
+ }
+
+ struct Ascending {
+
+ bool operator()(const Rule* a, const Rule* b) {
+ return a->getActivationDegree() > b->getActivationDegree();
+ }
+ };
+
+ void Lowest::activate(RuleBlock* ruleBlock) {
+ FL_DBG("Activation: " << className() << " " << parameters());
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ std::priority_queue<Rule*, std::vector<Rule*>, Ascending> rulesToActivate;
+
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ Rule* rule = ruleBlock->getRule(i);
+ rule->deactivate();
+ if (rule->isLoaded()) {
+ scalar activationDegree = rule->activateWith(conjunction, disjunction);
+ if (Op::isGt(activationDegree, 0.0))
+ rulesToActivate.push(rule);
+ }
+ }
+
+ int activated = 0;
+ while (rulesToActivate.size() > 0 and activated++ < _numberOfRules) {
+ Rule* rule = rulesToActivate.top();
+ rule->trigger(implication);
+ rulesToActivate.pop();
+ }
+ }
+
+ Lowest* Lowest::clone() const {
+ return new Lowest(*this);
+ }
+
+ Activation* Lowest::constructor() {
+ return new Lowest;
+ }
+
+}
diff --git a/fuzzylite/src/activation/Proportional.cpp b/fuzzylite/src/activation/Proportional.cpp
new file mode 100644
index 0000000..07fa2aa
--- /dev/null
+++ b/fuzzylite/src/activation/Proportional.cpp
@@ -0,0 +1,91 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/Proportional.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ Proportional::Proportional() : Activation() { }
+
+ Proportional::~Proportional() { }
+
+ std::string Proportional::className() const {
+ return "Proportional";
+ }
+
+ std::string Proportional::parameters() const {
+ return "";
+ }
+
+ void Proportional::configure(const std::string& parameters) {
+ FL_IUNUSED(parameters);
+ }
+
+ Complexity Proportional::complexity(const RuleBlock* ruleBlock) const {
+ Complexity result;
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ result.comparison(1).arithmetic(1);
+ result += ruleBlock->getRule(i)->complexityOfActivation(
+ ruleBlock->getConjunction(), ruleBlock->getDisjunction());
+ }
+
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ result.arithmetic(1);
+ result += ruleBlock->getRule(i)->complexityOfFiring(ruleBlock->getImplication());
+ }
+ return result;
+ }
+
+ void Proportional::activate(RuleBlock* ruleBlock) {
+ FL_DBG("Activation: " << className() << " " << parameters());
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ scalar sumActivationDegrees = 0.0;
+ std::vector<Rule*> rulesToActivate;
+ const std::size_t numberOfRules = ruleBlock->numberOfRules();
+ for (std::size_t i = 0; i < numberOfRules; ++i) {
+ Rule* rule = ruleBlock->getRule(i);
+ rule->deactivate();
+ if (rule->isLoaded()) {
+ scalar activationDegree = rule->activateWith(conjunction, disjunction);
+ rulesToActivate.push_back(rule);
+ sumActivationDegrees += activationDegree;
+ }
+ }
+
+ for (std::size_t i = 0; i < rulesToActivate.size(); ++i) {
+ Rule* rule = rulesToActivate.at(i);
+ scalar activationDegree = rule->getActivationDegree() / sumActivationDegrees;
+ rule->setActivationDegree(activationDegree);
+ rule->trigger(implication);
+ }
+ }
+
+ Proportional* Proportional::clone() const {
+ return new Proportional(*this);
+ }
+
+ Activation* Proportional::constructor() {
+ return new Proportional;
+ }
+
+}
diff --git a/fuzzylite/src/activation/Threshold.cpp b/fuzzylite/src/activation/Threshold.cpp
new file mode 100644
index 0000000..cd1f034
--- /dev/null
+++ b/fuzzylite/src/activation/Threshold.cpp
@@ -0,0 +1,170 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/activation/Threshold.h"
+
+#include "fl/rule/RuleBlock.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ Threshold::Threshold(Comparison comparison, scalar threshold) : Activation(),
+ _comparison(comparison), _value(threshold) { }
+
+ Threshold::Threshold(const std::string& comparison, scalar threshold) : Activation(),
+ _comparison(parseComparison(comparison)), _value(threshold) { }
+
+ Threshold::~Threshold() { }
+
+ std::string Threshold::className() const {
+ return "Threshold";
+ }
+
+ std::string Threshold::parameters() const {
+ std::ostringstream ss;
+ ss << comparisonOperator() << " " << Op::str(getValue());
+ return ss.str();
+ }
+
+ void Threshold::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] activation <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setComparison(parseComparison(values.at(0)));
+ setValue(Op::toScalar(values.at(1)));
+ }
+
+ void Threshold::setComparison(Comparison comparison) {
+ this->_comparison = comparison;
+ }
+
+ Threshold::Comparison Threshold::getComparison() const {
+ return this->_comparison;
+ }
+
+ std::string Threshold::comparisonOperator() const {
+ return comparisonOperator(getComparison());
+ }
+
+ std::string Threshold::comparisonOperator(Comparison comparison) const {
+ switch (comparison) {
+ case LessThan: return "<";
+ case LessThanOrEqualTo: return "<=";
+ case EqualTo: return "==";
+ case NotEqualTo: return "!=";
+ case GreaterThanOrEqualTo: return ">=";
+ case GreaterThan: return ">";
+ default: return "?";
+ }
+ }
+
+ std::vector<std::string> Threshold::availableComparisonOperators() const {
+ std::vector<std::string> result;
+ result.push_back("<");
+ result.push_back("<=");
+ result.push_back("==");
+ result.push_back("!=");
+ result.push_back(">=");
+ result.push_back(">");
+ return result;
+ }
+
+ Threshold::Comparison Threshold::parseComparison(const std::string& name) const {
+ if (name == "<") return LessThan;
+ if (name == "<=") return LessThanOrEqualTo;
+ if (name == "==") return EqualTo;
+ if (name == "!=") return NotEqualTo;
+ if (name == ">=") return GreaterThanOrEqualTo;
+ if (name == ">") return GreaterThan;
+ throw Exception("[syntax error] invalid threshold type by name <" + name + ">", FL_AT);
+ }
+
+ void Threshold::setValue(scalar value) {
+ this->_value = value;
+ }
+
+ scalar Threshold::getValue() const {
+ return this->_value;
+ }
+
+ void Threshold::setThreshold(Comparison comparison, scalar threshold) {
+ setComparison(comparison);
+ setValue(threshold);
+ }
+
+ void Threshold::setThreshold(const std::string& comparison, scalar value) {
+ setComparison(parseComparison(comparison));
+ setValue(value);
+ }
+
+ bool Threshold::activatesWith(scalar activationDegree) const {
+ switch (getComparison()) {
+ case LessThan: return Op::isLt(activationDegree, getValue());
+ case LessThanOrEqualTo: return Op::isLE(activationDegree, getValue());
+ case EqualTo: return Op::isEq(activationDegree, getValue());
+ case NotEqualTo: return not Op::isEq(activationDegree, getValue());
+ case GreaterThanOrEqualTo: return Op::isGE(activationDegree, getValue());
+ case GreaterThan: return Op::isGt(activationDegree, getValue());
+ default: return false;
+ }
+ }
+
+ Complexity Threshold::complexity(const RuleBlock* ruleBlock) const {
+ Complexity result;
+ for (std::size_t i = 0; i < ruleBlock->rules().size(); ++i) {
+ result.comparison(2);
+ result += ruleBlock->rules().at(i)->complexity(
+ ruleBlock->getConjunction(), ruleBlock->getDisjunction(),
+ ruleBlock->getImplication());
+ }
+ return result;
+ }
+
+ void Threshold::activate(RuleBlock* ruleBlock) {
+ FL_DBG("Activation: " << className() << " " << parameters());
+ const TNorm* conjunction = ruleBlock->getConjunction();
+ const SNorm* disjunction = ruleBlock->getDisjunction();
+ const TNorm* implication = ruleBlock->getImplication();
+
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ Rule* rule = ruleBlock->getRule(i);
+ rule->deactivate();
+ if (rule->isLoaded()) {
+ scalar activationDegree = rule->activateWith(conjunction, disjunction);
+ if (activatesWith(activationDegree)) {
+ rule->trigger(implication);
+ }
+ }
+ }
+ }
+
+ Threshold* Threshold::clone() const {
+ return new Threshold(*this);
+ }
+
+ Activation* Threshold::constructor() {
+ return new Threshold;
+ }
+
+}
+
diff --git a/fuzzylite/src/defuzzifier/Bisector.cpp b/fuzzylite/src/defuzzifier/Bisector.cpp
new file mode 100644
index 0000000..ed61b6f
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/Bisector.cpp
@@ -0,0 +1,68 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/Bisector.h"
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ Bisector::Bisector(int resolution)
+ : IntegralDefuzzifier(resolution) { }
+
+ Bisector::~Bisector() { }
+
+ std::string Bisector::className() const {
+ return "Bisector";
+ }
+
+ Complexity Bisector::complexity(const Term* term) const {
+ return Complexity().comparison(1).arithmetic(1 + 2 + 5) +
+ term->complexity().comparison(1).arithmetic(1 + 5).multiply(getResolution());
+ }
+
+ scalar Bisector::defuzzify(const Term* term, scalar minimum, scalar maximum) const {
+ if (not Op::isFinite(minimum + maximum)) return fl::nan;
+
+ const scalar dx = (maximum - minimum) / getResolution();
+ int counter = getResolution();
+ int left = 0, right = 0;
+ scalar leftArea = 0, rightArea = 0;
+ scalar xLeft = minimum, xRight = maximum;
+ while (counter-- > 0) {
+ if (Op::isLE(leftArea, rightArea)) {
+ xLeft = minimum + (left + 0.5) * dx;
+ leftArea += term->membership(xLeft);
+ ++left;
+ } else {
+ xRight = maximum - (right + 0.5) * dx;
+ rightArea += term->membership(xRight);
+ ++right;
+ }
+ }
+ //Inverse weighted average to compensate
+ return (leftArea * xRight + rightArea * xLeft) / (leftArea + rightArea);
+ }
+
+ Bisector* Bisector::clone() const {
+ return new Bisector(*this);
+ }
+
+ Defuzzifier* Bisector::constructor() {
+ return new Bisector;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/Centroid.cpp b/fuzzylite/src/defuzzifier/Centroid.cpp
new file mode 100644
index 0000000..177da26
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/Centroid.cpp
@@ -0,0 +1,68 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/Centroid.h"
+
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ Centroid::Centroid(int resolution)
+ : IntegralDefuzzifier(resolution) { }
+
+ Centroid::~Centroid() { }
+
+ std::string Centroid::className() const {
+ return "Centroid";
+ }
+
+ Complexity Centroid::complexity(const Term* term) const {
+ return Complexity().comparison(1).arithmetic(1 + 2 + 1) +
+ term->complexity().arithmetic(6).multiply(getResolution());
+ }
+
+ scalar Centroid::defuzzify(const Term* term, scalar minimum, scalar maximum) const {
+ if (not Op::isFinite(minimum + maximum)) return fl::nan;
+
+ const int resolution = getResolution();
+ const scalar dx = (maximum - minimum) / resolution;
+ scalar x, y;
+ scalar area = 0, xcentroid = 0;
+ //scalar ycentroid = 0;
+ for (int i = 0; i < resolution; ++i) {
+ x = minimum + (i + 0.5) * dx;
+ y = term->membership(x);
+
+ xcentroid += y * x;
+ //ycentroid += y * y;
+ area += y;
+ }
+ //Final results not computed for efficiency
+ //xcentroid /= area;
+ //ycentroid /= 2 * area;
+ //area *= dx;
+ return xcentroid / area;
+ }
+
+ Centroid* Centroid::clone() const {
+ return new Centroid(*this);
+ }
+
+ Defuzzifier* Centroid::constructor() {
+ return new Centroid;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/IntegralDefuzzifier.cpp b/fuzzylite/src/defuzzifier/IntegralDefuzzifier.cpp
new file mode 100644
index 0000000..3b06b42
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/IntegralDefuzzifier.cpp
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/IntegralDefuzzifier.h"
+
+namespace fl {
+
+ int IntegralDefuzzifier::_defaultResolution = 100;
+
+ void IntegralDefuzzifier::setDefaultResolution(int defaultResolution) {
+ _defaultResolution = defaultResolution;
+ }
+
+ int IntegralDefuzzifier::defaultResolution() {
+ return _defaultResolution;
+ }
+
+ IntegralDefuzzifier::IntegralDefuzzifier(int resolution)
+ : Defuzzifier(), _resolution(resolution) { }
+
+ IntegralDefuzzifier::~IntegralDefuzzifier() { }
+
+ void IntegralDefuzzifier::setResolution(int resolution) {
+ this->_resolution = resolution;
+ }
+
+ int IntegralDefuzzifier::getResolution() const {
+ return this->_resolution;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/LargestOfMaximum.cpp b/fuzzylite/src/defuzzifier/LargestOfMaximum.cpp
new file mode 100644
index 0000000..ff05707
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/LargestOfMaximum.cpp
@@ -0,0 +1,65 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/LargestOfMaximum.h"
+
+#include "fl/Exception.h"
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ LargestOfMaximum::LargestOfMaximum(int resolution)
+ : IntegralDefuzzifier(resolution) { }
+
+ LargestOfMaximum::~LargestOfMaximum() { }
+
+ std::string LargestOfMaximum::className() const {
+ return "LargestOfMaximum";
+ }
+
+ Complexity LargestOfMaximum::complexity(const Term* term) const {
+ return Complexity().comparison(1).arithmetic(1 + 2) +
+ term->complexity().comparison(1).arithmetic(3).multiply(getResolution());
+ }
+
+ scalar LargestOfMaximum::defuzzify(const Term* term, scalar minimum, scalar maximum) const {
+ if (not Op::isFinite(minimum + maximum)) return fl::nan;
+
+ const int resolution = getResolution();
+ const scalar dx = (maximum - minimum) / resolution;
+ scalar x, y;
+ scalar ymax = -1.0, xlargest = maximum;
+ for (int i = 0; i < resolution; ++i) {
+ x = minimum + (i + 0.5) * dx;
+ y = term->membership(x);
+
+ if (Op::isGE(y, ymax)) {
+ ymax = y;
+ xlargest = x;
+ }
+ }
+ return xlargest;
+ }
+
+ LargestOfMaximum* LargestOfMaximum::clone() const {
+ return new LargestOfMaximum(*this);
+ }
+
+ Defuzzifier* LargestOfMaximum::constructor() {
+ return new LargestOfMaximum;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/MeanOfMaximum.cpp b/fuzzylite/src/defuzzifier/MeanOfMaximum.cpp
new file mode 100644
index 0000000..961e505
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/MeanOfMaximum.cpp
@@ -0,0 +1,77 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/MeanOfMaximum.h"
+
+#include "fl/Exception.h"
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ MeanOfMaximum::MeanOfMaximum(int resolution)
+ : IntegralDefuzzifier(resolution) { }
+
+ MeanOfMaximum::~MeanOfMaximum() { }
+
+ std::string MeanOfMaximum::className() const {
+ return "MeanOfMaximum";
+ }
+
+ Complexity MeanOfMaximum::complexity(const Term* term) const {
+ return Complexity().comparison(1).arithmetic(1 + 2 + 2) +
+ term->complexity().comparison(4).arithmetic(3).multiply(getResolution());
+ }
+
+ scalar MeanOfMaximum::defuzzify(const Term* term, scalar minimum, scalar maximum) const {
+ if (not Op::isFinite(minimum + maximum)) return fl::nan;
+
+ const int resolution = getResolution();
+ const scalar dx = (maximum - minimum) / resolution;
+ scalar x, y;
+ scalar ymax = -1.0;
+ scalar xsmallest = minimum;
+ scalar xlargest = maximum;
+ bool samePlateau = false;
+ for (int i = 0; i < resolution; ++i) {
+ x = minimum + (i + 0.5) * dx;
+ y = term->membership(x);
+
+ if (Op::isGt(y, ymax)) {
+ ymax = y;
+
+ xsmallest = x;
+ xlargest = x;
+
+ samePlateau = true;
+ } else if (samePlateau and Op::isEq(y, ymax)) {
+ xlargest = x;
+ } else if (Op::isLt(y, ymax)) {
+ samePlateau = false;
+ }
+ }
+
+ return 0.5 * (xlargest + xsmallest);
+ }
+
+ MeanOfMaximum* MeanOfMaximum::clone() const {
+ return new MeanOfMaximum(*this);
+ }
+
+ Defuzzifier* MeanOfMaximum::constructor() {
+ return new MeanOfMaximum;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/SmallestOfMaximum.cpp b/fuzzylite/src/defuzzifier/SmallestOfMaximum.cpp
new file mode 100644
index 0000000..7333702
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/SmallestOfMaximum.cpp
@@ -0,0 +1,65 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/SmallestOfMaximum.h"
+
+#include "fl/Exception.h"
+#include "fl/term/Term.h"
+
+namespace fl {
+
+ SmallestOfMaximum::SmallestOfMaximum(int resolution)
+ : IntegralDefuzzifier(resolution) { }
+
+ SmallestOfMaximum::~SmallestOfMaximum() { }
+
+ std::string SmallestOfMaximum::className() const {
+ return "SmallestOfMaximum";
+ }
+
+ Complexity SmallestOfMaximum::complexity(const Term* term) const {
+ return Complexity().comparison(1).arithmetic(1 + 2) +
+ term->complexity().comparison(1).arithmetic(3).multiply(getResolution());
+ }
+
+ scalar SmallestOfMaximum::defuzzify(const Term* term, scalar minimum, scalar maximum) const {
+ if (not Op::isFinite(minimum + maximum)) return fl::nan;
+
+ const int resolution = getResolution();
+ const scalar dx = (maximum - minimum) / resolution;
+ scalar x, y;
+ scalar ymax = -1.0, xsmallest = minimum;
+ for (int i = 0; i < resolution; ++i) {
+ x = minimum + (i + 0.5) * dx;
+ y = term->membership(x);
+
+ if (Op::isGt(y, ymax)) {
+ xsmallest = x;
+ ymax = y;
+ }
+ }
+ return xsmallest;
+ }
+
+ SmallestOfMaximum* SmallestOfMaximum::clone() const {
+ return new SmallestOfMaximum(*this);
+ }
+
+ Defuzzifier* SmallestOfMaximum::constructor() {
+ return new SmallestOfMaximum;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/WeightedAverage.cpp b/fuzzylite/src/defuzzifier/WeightedAverage.cpp
new file mode 100644
index 0000000..34af8c9
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/WeightedAverage.cpp
@@ -0,0 +1,100 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/WeightedAverage.h"
+
+#include "fl/term/Aggregated.h"
+
+#include <map>
+
+namespace fl {
+
+ WeightedAverage::WeightedAverage(Type type) : WeightedDefuzzifier(type) { }
+
+ WeightedAverage::WeightedAverage(const std::string& type) : WeightedDefuzzifier(type) { }
+
+ WeightedAverage::~WeightedAverage() { }
+
+ std::string WeightedAverage::className() const {
+ return "WeightedAverage";
+ }
+
+ Complexity WeightedAverage::complexity(const Term* term) const {
+ Complexity result;
+ result.comparison(4).function(1); //for dynamic_cast
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (fuzzyOutput) {
+ result += term->complexity().arithmetic(3).multiply(scalar(fuzzyOutput->numberOfTerms()));
+ }
+ return result;
+ }
+
+ scalar WeightedAverage::defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const {
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (not fuzzyOutput) {
+ std::ostringstream ss;
+ ss << "[defuzzification error]"
+ << "expected an Aggregated term instead of"
+ << "<" << (term ? term->toString() : "null") << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ if (fuzzyOutput->isEmpty()) return fl::nan;
+
+ minimum = fuzzyOutput->getMinimum();
+ maximum = fuzzyOutput->getMaximum();
+
+ Type type = getType();
+ if (type == Automatic) {
+ type = inferType(&(fuzzyOutput->terms().front()));
+ }
+
+ scalar sum = 0.0;
+ scalar weights = 0.0;
+ const std::size_t numberOfTerms = fuzzyOutput->numberOfTerms();
+ if (type == TakagiSugeno) {
+ //Provides Takagi-Sugeno and Inverse Tsukamoto of Functions
+ scalar w, z;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->membership(w);
+ sum += w * z;
+ weights += w;
+ }
+ } else {
+ scalar w, z;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->tsukamoto(w, minimum, maximum);
+ sum += w * z;
+ weights += w;
+ }
+ }
+ return sum / weights;
+ }
+
+ WeightedAverage* WeightedAverage::clone() const {
+ return new WeightedAverage(*this);
+ }
+
+ Defuzzifier* WeightedAverage::constructor() {
+ return new WeightedAverage;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/WeightedAverageCustom.cpp b/fuzzylite/src/defuzzifier/WeightedAverageCustom.cpp
new file mode 100644
index 0000000..0beb722
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/WeightedAverageCustom.cpp
@@ -0,0 +1,117 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/WeightedAverageCustom.h"
+
+#include "fl/term/Aggregated.h"
+
+#include <map>
+
+namespace fl {
+
+ WeightedAverageCustom::WeightedAverageCustom(Type type) : WeightedDefuzzifier(type) { }
+
+ WeightedAverageCustom::WeightedAverageCustom(const std::string& type) : WeightedDefuzzifier(type) { }
+
+ WeightedAverageCustom::~WeightedAverageCustom() { }
+
+ std::string WeightedAverageCustom::className() const {
+ return "WeightedAverageCustom";
+ }
+
+ Complexity WeightedAverageCustom::complexity(const Term* term) const {
+ Complexity result;
+ result.comparison(3).arithmetic(1).function(1);
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (fuzzyOutput) {
+ result += term->complexity().arithmetic(3).comparison(2)
+ .multiply(scalar(fuzzyOutput->numberOfTerms()));
+ }
+ return result;
+ }
+
+ scalar WeightedAverageCustom::defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const {
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (not fuzzyOutput) {
+ std::ostringstream ss;
+ ss << "[defuzzification error]"
+ << "expected an Aggregated term instead of"
+ << "<" << (term ? term->toString() : "null") << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ if (fuzzyOutput->isEmpty()) return fl::nan;
+
+ minimum = fuzzyOutput->getMinimum();
+ maximum = fuzzyOutput->getMaximum();
+
+ SNorm* aggregation = fuzzyOutput->getAggregation();
+
+ Type type = getType();
+ if (type == Automatic) {
+ type = inferType(&(fuzzyOutput->terms().front()));
+ }
+
+ scalar sum = 0.0;
+ scalar weights = 0.0;
+ const std::size_t numberOfTerms = fuzzyOutput->numberOfTerms();
+ if (type == TakagiSugeno) {
+ //Provides Takagi-Sugeno and Inverse Tsukamoto of Functions
+ scalar w, z, wz;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->membership(w);
+ const TNorm* implication = activated.getImplication();
+ wz = implication ? implication->compute(w, z) : (w * z);
+ if (aggregation) {
+ sum = aggregation->compute(sum, wz);
+ weights = aggregation->compute(weights, w);
+ } else {
+ sum += wz;
+ weights += w;
+ }
+ }
+ } else {
+ scalar w, z, wz;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->tsukamoto(w, minimum, maximum);
+ const TNorm* implication = activated.getImplication();
+ wz = implication ? implication->compute(w, z) : (w * z);
+ if (aggregation) {
+ sum = aggregation->compute(sum, wz);
+ weights = aggregation->compute(weights, w);
+ } else {
+ sum += wz;
+ weights += w;
+ }
+ }
+ }
+ return sum / weights;
+ }
+
+ WeightedAverageCustom* WeightedAverageCustom::clone() const {
+ return new WeightedAverageCustom(*this);
+ }
+
+ Defuzzifier* WeightedAverageCustom::constructor() {
+ return new WeightedAverageCustom;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/WeightedDefuzzifier.cpp b/fuzzylite/src/defuzzifier/WeightedDefuzzifier.cpp
new file mode 100644
index 0000000..743c59f
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/WeightedDefuzzifier.cpp
@@ -0,0 +1,76 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/WeightedDefuzzifier.h"
+
+#include "fl/term/Activated.h"
+#include "fl/term/Concave.h"
+#include "fl/term/Constant.h"
+#include "fl/term/Function.h"
+#include "fl/term/Linear.h"
+#include "fl/term/Ramp.h"
+#include "fl/term/Sigmoid.h"
+#include "fl/term/SShape.h"
+#include "fl/term/ZShape.h"
+
+namespace fl {
+
+ WeightedDefuzzifier::WeightedDefuzzifier(Type type) : _type(type) { }
+
+ WeightedDefuzzifier::WeightedDefuzzifier(const std::string& type) {
+ if (type == "Automatic") setType(Automatic);
+ else if (type == "TakagiSugeno") setType(TakagiSugeno);
+ else if (type == "Tsukamoto") setType(Tsukamoto);
+ else {
+ setType(Automatic);
+ FL_LOG("[warning] incorrect type <" + type + "> of WeightedDefuzzifier"
+ + " has been defaulted to <Automatic>");
+ }
+ }
+
+ WeightedDefuzzifier::~WeightedDefuzzifier() { }
+
+ std::string WeightedDefuzzifier::typeName(Type type) {
+ switch (type) {
+ case Automatic: return "Automatic";
+ case TakagiSugeno: return "TakagiSugeno";
+ case Tsukamoto: return "Tsukamoto";
+ default: return "";
+ }
+ }
+
+ void WeightedDefuzzifier::setType(Type type) {
+ this->_type = type;
+ }
+
+ WeightedDefuzzifier::Type WeightedDefuzzifier::getType() const {
+ return this->_type;
+ }
+
+ std::string WeightedDefuzzifier::getTypeName() const {
+ return typeName(getType());
+ }
+
+ WeightedDefuzzifier::Type WeightedDefuzzifier::inferType(const Term* term) const {
+ if (dynamic_cast<const Constant*> (term)
+ or dynamic_cast<const Linear*> (term)
+ or dynamic_cast<const Function*> (term)) {
+ return TakagiSugeno;
+ }
+ return Tsukamoto;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/WeightedSum.cpp b/fuzzylite/src/defuzzifier/WeightedSum.cpp
new file mode 100644
index 0000000..6c2343d
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/WeightedSum.cpp
@@ -0,0 +1,97 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/WeightedSum.h"
+
+#include "fl/term/Aggregated.h"
+
+#include <map>
+
+namespace fl {
+
+ WeightedSum::WeightedSum(Type type) : WeightedDefuzzifier(type) { }
+
+ WeightedSum::WeightedSum(const std::string& type) : WeightedDefuzzifier(type) { }
+
+ WeightedSum::~WeightedSum() { }
+
+ std::string WeightedSum::className() const {
+ return "WeightedSum";
+ }
+
+ Complexity WeightedSum::complexity(const Term* term) const {
+ Complexity result;
+ result.comparison(4).function(1);
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (fuzzyOutput) {
+ result += term->complexity().arithmetic(2).multiply(scalar(fuzzyOutput->numberOfTerms()));
+ }
+ return result;
+ }
+
+ scalar WeightedSum::defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const {
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (not fuzzyOutput) {
+ std::ostringstream ss;
+ ss << "[defuzzification error]"
+ << "expected an Aggregated term instead of"
+ << "<" << (term ? term->toString() : "null") << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ if (fuzzyOutput->isEmpty()) return fl::nan;
+
+ minimum = fuzzyOutput->getMinimum();
+ maximum = fuzzyOutput->getMaximum();
+
+ Type type = getType();
+ if (type == Automatic) {
+ type = inferType(&(fuzzyOutput->terms().front()));
+ }
+
+ scalar sum = 0.0;
+ const std::size_t numberOfTerms = fuzzyOutput->numberOfTerms();
+ if (type == TakagiSugeno) {
+ //Provides Takagi-Sugeno and Inverse Tsukamoto of Functions
+ scalar w, z;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->membership(w);
+ sum += w * z;
+ }
+ } else {
+ scalar w, z;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->tsukamoto(w, minimum, maximum);
+ sum += w * z;
+ }
+ }
+ return sum;
+ }
+
+ WeightedSum* WeightedSum::clone() const {
+ return new WeightedSum(*this);
+ }
+
+ Defuzzifier* WeightedSum::constructor() {
+ return new WeightedSum;
+ }
+
+}
diff --git a/fuzzylite/src/defuzzifier/WeightedSumCustom.cpp b/fuzzylite/src/defuzzifier/WeightedSumCustom.cpp
new file mode 100644
index 0000000..5a9084c
--- /dev/null
+++ b/fuzzylite/src/defuzzifier/WeightedSumCustom.cpp
@@ -0,0 +1,112 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/defuzzifier/WeightedSumCustom.h"
+
+#include "fl/term/Aggregated.h"
+
+#include <map>
+
+namespace fl {
+
+ WeightedSumCustom::WeightedSumCustom(Type type) : WeightedDefuzzifier(type) { }
+
+ WeightedSumCustom::WeightedSumCustom(const std::string& type) : WeightedDefuzzifier(type) { }
+
+ WeightedSumCustom::~WeightedSumCustom() { }
+
+ std::string WeightedSumCustom::className() const {
+ return "WeightedSumCustom";
+ }
+
+ Complexity WeightedSumCustom::complexity(const Term* term) const {
+ Complexity result;
+ result.comparison(4).function(1);
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (fuzzyOutput) {
+ result += term->complexity().arithmetic(2).comparison(2)
+ .multiply(scalar(fuzzyOutput->numberOfTerms()));
+ }
+ return result;
+ }
+
+ scalar WeightedSumCustom::defuzzify(const Term* term,
+ scalar minimum, scalar maximum) const {
+ const Aggregated* fuzzyOutput = dynamic_cast<const Aggregated*> (term);
+ if (not fuzzyOutput) {
+ std::ostringstream ss;
+ ss << "[defuzzification error]"
+ << "expected an Aggregated term instead of"
+ << "<" << (term ? term->toString() : "null") << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ if (fuzzyOutput->isEmpty()) return fl::nan;
+
+ minimum = fuzzyOutput->getMinimum();
+ maximum = fuzzyOutput->getMaximum();
+
+ Type type = getType();
+ if (type == Automatic) {
+ type = inferType(&(fuzzyOutput->terms().front()));
+ }
+
+ SNorm* aggregation = fuzzyOutput->getAggregation();
+
+ scalar sum = 0.0;
+ const std::size_t numberOfTerms = fuzzyOutput->numberOfTerms();
+ if (type == TakagiSugeno) {
+ //Provides Takagi-Sugeno and Inverse Tsukamoto of Functions
+ scalar w, z, wz;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->membership(w);
+ const TNorm* implication = activated.getImplication();
+ wz = implication ? implication->compute(w, z) : (w * z);
+ if (aggregation) {
+ sum = aggregation->compute(sum, wz);
+ } else {
+ sum += wz;
+ }
+ }
+ } else {
+ scalar w, z, wz;
+ for (std::size_t i = 0; i < numberOfTerms; ++i) {
+ const Activated& activated = fuzzyOutput->getTerm(i);
+ w = activated.getDegree();
+ z = activated.getTerm()->tsukamoto(w, minimum, maximum);
+ const TNorm* implication = activated.getImplication();
+ wz = implication ? implication->compute(w, z) : (w * z);
+ if (aggregation) {
+ sum = aggregation->compute(sum, wz);
+ } else {
+ sum += wz;
+ }
+ }
+ }
+ return sum;
+ }
+
+ WeightedSumCustom* WeightedSumCustom::clone() const {
+ return new WeightedSumCustom(*this);
+ }
+
+ Defuzzifier* WeightedSumCustom::constructor() {
+ return new WeightedSumCustom;
+ }
+
+}
diff --git a/fuzzylite/src/factory/ActivationFactory.cpp b/fuzzylite/src/factory/ActivationFactory.cpp
new file mode 100644
index 0000000..d000667
--- /dev/null
+++ b/fuzzylite/src/factory/ActivationFactory.cpp
@@ -0,0 +1,42 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/ActivationFactory.h"
+
+#include "fl/activation/First.h"
+#include "fl/activation/General.h"
+#include "fl/activation/Highest.h"
+#include "fl/activation/Last.h"
+#include "fl/activation/Lowest.h"
+#include "fl/activation/Proportional.h"
+#include "fl/activation/Threshold.h"
+
+namespace fl {
+
+ ActivationFactory::ActivationFactory() : ConstructionFactory<Activation*>("Activation") {
+ registerConstructor("", fl::null);
+ registerConstructor(First().className(), &(First::constructor));
+ registerConstructor(General().className(), &(General::constructor));
+ registerConstructor(Highest().className(), &(Highest::constructor));
+ registerConstructor(Last().className(), &(Last::constructor));
+ registerConstructor(Lowest().className(), &(Lowest::constructor));
+ registerConstructor(Proportional().className(), &(Proportional::constructor));
+ registerConstructor(Threshold().className(), &(Threshold::constructor));
+ }
+
+ ActivationFactory::~ActivationFactory() { }
+
+}
diff --git a/fuzzylite/src/factory/DefuzzifierFactory.cpp b/fuzzylite/src/factory/DefuzzifierFactory.cpp
new file mode 100644
index 0000000..3b0bfb1
--- /dev/null
+++ b/fuzzylite/src/factory/DefuzzifierFactory.cpp
@@ -0,0 +1,73 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/DefuzzifierFactory.h"
+
+#include "fl/defuzzifier/Bisector.h"
+#include "fl/defuzzifier/Centroid.h"
+#include "fl/defuzzifier/SmallestOfMaximum.h"
+#include "fl/defuzzifier/LargestOfMaximum.h"
+#include "fl/defuzzifier/MeanOfMaximum.h"
+#include "fl/defuzzifier/WeightedAverage.h"
+#include "fl/defuzzifier/WeightedAverageCustom.h"
+#include "fl/defuzzifier/WeightedSum.h"
+#include "fl/defuzzifier/WeightedSumCustom.h"
+
+namespace fl {
+
+ DefuzzifierFactory::DefuzzifierFactory() : ConstructionFactory<Defuzzifier*>("Defuzzifier") {
+ registerConstructor("", fl::null);
+ registerConstructor(Bisector().className(), &(Bisector::constructor));
+ registerConstructor(Centroid().className(), &(Centroid::constructor));
+ registerConstructor(LargestOfMaximum().className(), &(LargestOfMaximum::constructor));
+ registerConstructor(MeanOfMaximum().className(), &(MeanOfMaximum::constructor));
+ registerConstructor(SmallestOfMaximum().className(), &(SmallestOfMaximum::constructor));
+ registerConstructor(WeightedAverage().className(), &(WeightedAverage::constructor));
+// registerConstructor(WeightedAverageCustom().className(), &(WeightedAverageCustom::constructor));
+ registerConstructor(WeightedSum().className(), &(WeightedSum::constructor));
+// registerConstructor(WeightedSumCustom().className(), &(WeightedSumCustom::constructor));
+ }
+
+ DefuzzifierFactory::~DefuzzifierFactory() { }
+
+ Defuzzifier* DefuzzifierFactory::constructDefuzzifier(const std::string& key,
+ int resolution, WeightedDefuzzifier::Type type) const {
+ Defuzzifier* result = constructObject(key);
+ if (IntegralDefuzzifier * integralDefuzzifier = dynamic_cast<IntegralDefuzzifier*> (result)) {
+ integralDefuzzifier->setResolution(resolution);
+ } else if (WeightedDefuzzifier * weightedDefuzzifier = dynamic_cast<WeightedDefuzzifier*> (result)) {
+ weightedDefuzzifier->setType(type);
+ }
+ return result;
+ }
+
+ Defuzzifier* DefuzzifierFactory::constructDefuzzifier(const std::string& key, int resolution) const {
+ Defuzzifier* result = constructObject(key);
+ if (IntegralDefuzzifier * integralDefuzzifier = dynamic_cast<IntegralDefuzzifier*> (result)) {
+ integralDefuzzifier->setResolution(resolution);
+ }
+ return result;
+ }
+
+ Defuzzifier* DefuzzifierFactory::constructDefuzzifier(const std::string& key, WeightedDefuzzifier::Type type) {
+ Defuzzifier* result = constructObject(key);
+ if (WeightedDefuzzifier * weightedDefuzzifier = dynamic_cast<WeightedDefuzzifier*> (result)) {
+ weightedDefuzzifier->setType(type);
+ }
+ return result;
+ }
+
+}
diff --git a/fuzzylite/src/factory/FactoryManager.cpp b/fuzzylite/src/factory/FactoryManager.cpp
new file mode 100644
index 0000000..367d982
--- /dev/null
+++ b/fuzzylite/src/factory/FactoryManager.cpp
@@ -0,0 +1,129 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/FactoryManager.h"
+
+namespace fl {
+
+ FactoryManager* FactoryManager::instance() {
+ static FL_ITHREAD_LOCAL FactoryManager _instance;
+ return &_instance;
+ }
+
+ FactoryManager::FactoryManager() :
+ _tnorm(new TNormFactory), _snorm(new SNormFactory), _activation(new ActivationFactory),
+ _defuzzifier(new DefuzzifierFactory), _term(new TermFactory),
+ _hedge(new HedgeFactory), _function(new FunctionFactory) { }
+
+ FactoryManager::FactoryManager(TNormFactory* tnorm, SNormFactory* snorm,
+ ActivationFactory* activation, DefuzzifierFactory* defuzzifier,
+ TermFactory* term, HedgeFactory* hedge, FunctionFactory* function) :
+ _tnorm(tnorm), _snorm(snorm), _activation(activation),
+ _defuzzifier(defuzzifier), _term(term), _hedge(hedge), _function(function) { }
+
+ FactoryManager::FactoryManager(const FactoryManager& other)
+ : _tnorm(fl::null), _snorm(fl::null), _activation(fl::null),
+ _defuzzifier(fl::null), _term(fl::null), _hedge(fl::null),
+ _function(fl::null) {
+ if (other._tnorm.get()) this->_tnorm.reset(new TNormFactory(*other._tnorm.get()));
+ if (other._snorm.get()) this->_snorm.reset(new SNormFactory(*other._snorm.get()));
+ if (other._activation.get()) this->_activation.reset(new ActivationFactory(*other._activation.get()));
+ if (other._defuzzifier.get()) this->_defuzzifier.reset(new DefuzzifierFactory(*other._defuzzifier.get()));
+ if (other._term.get()) this->_term.reset(new TermFactory(*other._term.get()));
+ if (other._hedge.get()) this->_hedge.reset(new HedgeFactory(*other._hedge.get()));
+ if (other._function.get()) this->_function.reset(new FunctionFactory(*other._function.get()));
+ }
+
+ FactoryManager& FactoryManager::operator=(const FactoryManager& other) {
+ if (this != &other) {
+ _tnorm.reset(fl::null);
+ _snorm.reset(fl::null);
+ _activation.reset(fl::null);
+ _defuzzifier.reset(fl::null);
+ _term.reset(fl::null);
+ _hedge.reset(fl::null);
+ _function.reset(fl::null);
+
+ if (other._tnorm.get()) this->_tnorm.reset(new TNormFactory(*other._tnorm.get()));
+ if (other._snorm.get()) this->_snorm.reset(new SNormFactory(*other._snorm.get()));
+ if (other._activation.get()) this->_activation.reset(new ActivationFactory(*other._activation.get()));
+ if (other._defuzzifier.get()) this->_defuzzifier.reset(new DefuzzifierFactory(*other._defuzzifier.get()));
+ if (other._term.get()) this->_term.reset(new TermFactory(*other._term.get()));
+ if (other._hedge.get()) this->_hedge.reset(new HedgeFactory(*other._hedge.get()));
+ if (other._function.get()) this->_function.reset(new FunctionFactory(*other._function.get()));
+ }
+ return *this;
+ }
+
+ FactoryManager::~FactoryManager() { }
+
+ void FactoryManager::setTnorm(TNormFactory* tnorm) {
+ this->_tnorm.reset(tnorm);
+ }
+
+ TNormFactory* FactoryManager::tnorm() const {
+ return this->_tnorm.get();
+ }
+
+ void FactoryManager::setSnorm(SNormFactory* snorm) {
+ this->_snorm.reset(snorm);
+ }
+
+ SNormFactory* FactoryManager::snorm() const {
+ return this->_snorm.get();
+ }
+
+ void FactoryManager::setActivation(ActivationFactory* activation) {
+ this->_activation.reset(activation);
+ }
+
+ ActivationFactory* FactoryManager::activation() const {
+ return this->_activation.get();
+ }
+
+ void FactoryManager::setDefuzzifier(DefuzzifierFactory* defuzzifier) {
+ this->_defuzzifier.reset(defuzzifier);
+ }
+
+ DefuzzifierFactory* FactoryManager::defuzzifier() const {
+ return this->_defuzzifier.get();
+ }
+
+ void FactoryManager::setTerm(TermFactory* term) {
+ this->_term.reset(term);
+ }
+
+ TermFactory* FactoryManager::term() const {
+ return this->_term.get();
+ }
+
+ void FactoryManager::setHedge(HedgeFactory* hedge) {
+ this->_hedge.reset(hedge);
+ }
+
+ HedgeFactory* FactoryManager::hedge() const {
+ return this->_hedge.get();
+ }
+
+ void FactoryManager::setFunction(FunctionFactory* function) {
+ this->_function.reset(function);
+ }
+
+ FunctionFactory* FactoryManager::function() const {
+ return this->_function.get();
+ }
+
+}
diff --git a/fuzzylite/src/factory/FunctionFactory.cpp b/fuzzylite/src/factory/FunctionFactory.cpp
new file mode 100644
index 0000000..8e52ddf
--- /dev/null
+++ b/fuzzylite/src/factory/FunctionFactory.cpp
@@ -0,0 +1,169 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/FunctionFactory.h"
+
+#include "fl/rule/Rule.h"
+
+namespace fl {
+
+ FunctionFactory::FunctionFactory() : CloningFactory<Function::Element*>("Function::Element") {
+ registerOperators();
+ registerFunctions();
+ }
+
+ FunctionFactory::~FunctionFactory() { }
+
+ void FunctionFactory::registerOperators() {
+ //OPERATORS:
+ int p = 100;
+ //First order: not, negate:
+ registerObject("!", new Function::Element("!", "Logical NOT",
+ Function::Element::Operator, &(Op::logicalNot), p, 1)); //logical not
+ registerObject("~", new Function::Element("~", "Negation",
+ Function::Element::Operator, &(Op::negate), p, 1)); // ~ negates a number
+
+ p -= 10;
+ //Second order: power
+ registerObject("^", new Function::Element("^", "Power",
+ Function::Element::Operator, &(std::pow), p, 1));
+
+ p -= 10;
+ //Third order: multiplication, division, modulo
+ registerObject("*", new Function::Element("*", "Multiplication",
+ Function::Element::Operator, &(Op::multiply), p));
+ registerObject("/", new Function::Element("/", "Division",
+ Function::Element::Operator, &(Op::divide), p));
+ registerObject("%", new Function::Element("%", "Modulo",
+ Function::Element::Operator, &(Op::modulo), p));
+
+ p -= 10;
+ //Fourth order: addition, subtraction
+ registerObject("+", new Function::Element("+", "Addition",
+ Function::Element::Operator, &(Op::add), p));
+ registerObject("-", new Function::Element("-", "Subtraction",
+ Function::Element::Operator, &(Op::subtract), p));
+
+ //Fifth order: logical and, logical or
+ p -= 10; //Logical AND
+ registerObject(Rule::andKeyword(), new Function::Element(Rule::andKeyword(), "Logical AND",
+ Function::Element::Operator, &(Op::logicalAnd), p));
+ p -= 10; //Logical OR
+ registerObject(Rule::orKeyword(), new Function::Element(Rule::orKeyword(), "Logical OR",
+ Function::Element::Operator, &(Op::logicalOr), p));
+ }
+
+ void FunctionFactory::registerFunctions() {
+ //FUNCTIONS
+ registerObject("gt", new Function::Element("gt", "Greater than (>)",
+ Function::Element::Function, &(Op::gt)));
+ registerObject("ge", new Function::Element("ge", "Greater than or equal to (>=)",
+ Function::Element::Function, &(Op::ge)));
+ registerObject("eq", new Function::Element("eq", "Equal to (==)",
+ Function::Element::Function, &(Op::eq)));
+ registerObject("neq", new Function::Element("neq", "Not equal to (!=)",
+ Function::Element::Function, &(Op::neq)));
+ registerObject("le", new Function::Element("le", "Less than or equal to (<=)",
+ Function::Element::Function, &(Op::le)));
+ registerObject("lt", new Function::Element("lt", "Less than (<)",
+ Function::Element::Function, &(Op::lt)));
+
+ registerObject("min", new Function::Element("min", "Minimum",
+ Function::Element::Function, &(Op::min)));
+ registerObject("max", new Function::Element("max", "Maximum",
+ Function::Element::Function, &(Op::max)));
+
+ registerObject("acos", new Function::Element("acos", "Inverse cosine",
+ Function::Element::Function, &(std::acos)));
+ registerObject("asin", new Function::Element("asin", "Inverse sine",
+ Function::Element::Function, &(std::asin)));
+ registerObject("atan", new Function::Element("atan", "Inverse tangent",
+ Function::Element::Function, &(std::atan)));
+
+ registerObject("ceil", new Function::Element("ceil", "Ceiling",
+ Function::Element::Function, &(std::ceil)));
+ registerObject("cos", new Function::Element("cos", "Cosine",
+ Function::Element::Function, &(std::cos)));
+ registerObject("cosh", new Function::Element("cosh", "Hyperbolic cosine",
+ Function::Element::Function, &(std::cosh)));
+ registerObject("exp", new Function::Element("exp", "Exponential",
+ Function::Element::Function, &(std::exp)));
+ registerObject("abs", new Function::Element("abs", "Absolute",
+ Function::Element::Function, &(std::abs)));
+ registerObject("fabs", new Function::Element("fabs", "Absolute",
+ Function::Element::Function, &(std::fabs)));
+ registerObject("floor", new Function::Element("floor", "Floor",
+ Function::Element::Function, &(std::floor)));
+ registerObject("log", new Function::Element("log", "Natural logarithm",
+ Function::Element::Function, &(std::log)));
+ registerObject("log10", new Function::Element("log10", "Common logarithm",
+ Function::Element::Function, &(std::log10)));
+ registerObject("round", new Function::Element("round", "Round",
+ Function::Element::Function, &(Op::round)));
+ registerObject("sin", new Function::Element("sin", "Sine",
+ Function::Element::Function, &(std::sin)));
+ registerObject("sinh", new Function::Element("sinh", "Hyperbolic sine",
+ Function::Element::Function, &(std::sinh)));
+ registerObject("sqrt", new Function::Element("sqrt", "Square root",
+ Function::Element::Function, &(std::sqrt)));
+ registerObject("tan", new Function::Element("tan", "Tangent",
+ Function::Element::Function, &(std::tan)));
+ registerObject("tanh", new Function::Element("tanh", "Hyperbolic tangent",
+ Function::Element::Function, &(std::tanh)));
+
+#if defined(FL_UNIX) && !defined(FL_USE_FLOAT)
+ //found in Unix when using double precision. not found in Windows.
+ registerObject("log1p", new Function::Element("log1p", "Natural logarithm plus one",
+ Function::Element::Function, &(log1p)));
+ registerObject("acosh", new Function::Element("acosh", "Inverse hyperbolic cosine",
+ Function::Element::Function, &(acosh)));
+ registerObject("asinh", new Function::Element("asinh", "Inverse hyperbolic sine",
+ Function::Element::Function, &(asinh)));
+ registerObject("atanh", new Function::Element("atanh", "Inverse hyperbolic tangent",
+ Function::Element::Function, &(atanh)));
+#endif
+
+ registerObject("pow", new Function::Element("pow", "Power",
+ Function::Element::Function, &(std::pow)));
+ registerObject("atan2", new Function::Element("atan2", "Inverse tangent (y,x)",
+ Function::Element::Function, &(std::atan2)));
+ registerObject("fmod", new Function::Element("fmod", "Floating-point remainder",
+ Function::Element::Function, &(std::fmod)));
+ }
+
+ std::vector<std::string> FunctionFactory::availableOperators() const {
+ std::vector<std::string> result;
+ std::map<std::string, Function::Element*>::const_iterator it = this->objects().begin();
+ while (it != this->objects().end()) {
+ if (it->second and it->second->type == Function::Element::Operator)
+ result.push_back(it->first);
+ ++it;
+ }
+ return result;
+ }
+
+ std::vector<std::string> FunctionFactory::availableFunctions() const {
+ std::vector<std::string> result;
+ std::map<std::string, Function::Element*>::const_iterator it = this->objects().begin();
+ while (it != this->objects().end()) {
+ if (it->second and it->second->type == Function::Element::Function)
+ result.push_back(it->first);
+ ++it;
+ }
+ return result;
+ }
+
+}
diff --git a/fuzzylite/src/factory/HedgeFactory.cpp b/fuzzylite/src/factory/HedgeFactory.cpp
new file mode 100644
index 0000000..1a6452c
--- /dev/null
+++ b/fuzzylite/src/factory/HedgeFactory.cpp
@@ -0,0 +1,40 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/HedgeFactory.h"
+
+#include "fl/hedge/Any.h"
+#include "fl/hedge/Extremely.h"
+#include "fl/hedge/Not.h"
+#include "fl/hedge/Seldom.h"
+#include "fl/hedge/Somewhat.h"
+#include "fl/hedge/Very.h"
+
+namespace fl {
+
+ HedgeFactory::HedgeFactory() : ConstructionFactory<Hedge*>("Hedge") {
+ registerConstructor("", fl::null);
+ registerConstructor(Any().name(), &(Any::constructor));
+ registerConstructor(Extremely().name(), &(Extremely::constructor));
+ registerConstructor(Not().name(), &(Not::constructor));
+ registerConstructor(Seldom().name(), &(Seldom::constructor));
+ registerConstructor(Somewhat().name(), &(Somewhat::constructor));
+ registerConstructor(Very().name(), &(Very::constructor));
+ }
+
+ HedgeFactory::~HedgeFactory() { }
+
+}
diff --git a/fuzzylite/src/factory/SNormFactory.cpp b/fuzzylite/src/factory/SNormFactory.cpp
new file mode 100644
index 0000000..fdaef87
--- /dev/null
+++ b/fuzzylite/src/factory/SNormFactory.cpp
@@ -0,0 +1,46 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/SNormFactory.h"
+
+#include "fl/norm/s/AlgebraicSum.h"
+#include "fl/norm/s/BoundedSum.h"
+#include "fl/norm/s/DrasticSum.h"
+#include "fl/norm/s/EinsteinSum.h"
+#include "fl/norm/s/HamacherSum.h"
+#include "fl/norm/s/Maximum.h"
+#include "fl/norm/s/NilpotentMaximum.h"
+#include "fl/norm/s/NormalizedSum.h"
+#include "fl/norm/s/UnboundedSum.h"
+
+namespace fl {
+
+ SNormFactory::SNormFactory() : ConstructionFactory<SNorm*>("SNorm") {
+ registerConstructor("", fl::null);
+ registerConstructor(AlgebraicSum().className(), &(AlgebraicSum::constructor));
+ registerConstructor(BoundedSum().className(), &(BoundedSum::constructor));
+ registerConstructor(DrasticSum().className(), &(DrasticSum::constructor));
+ registerConstructor(EinsteinSum().className(), &(EinsteinSum::constructor));
+ registerConstructor(HamacherSum().className(), &(HamacherSum::constructor));
+ registerConstructor(Maximum().className(), &(Maximum::constructor));
+ registerConstructor(NilpotentMaximum().className(), &(NilpotentMaximum::constructor));
+ registerConstructor(NormalizedSum().className(), &(NormalizedSum::constructor));
+ registerConstructor(UnboundedSum().className(), &(UnboundedSum::constructor));
+ }
+
+ SNormFactory::~SNormFactory() { }
+
+}
diff --git a/fuzzylite/src/factory/TNormFactory.cpp b/fuzzylite/src/factory/TNormFactory.cpp
new file mode 100644
index 0000000..0dda02e
--- /dev/null
+++ b/fuzzylite/src/factory/TNormFactory.cpp
@@ -0,0 +1,42 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/TNormFactory.h"
+
+#include "fl/norm/t/AlgebraicProduct.h"
+#include "fl/norm/t/BoundedDifference.h"
+#include "fl/norm/t/DrasticProduct.h"
+#include "fl/norm/t/EinsteinProduct.h"
+#include "fl/norm/t/HamacherProduct.h"
+#include "fl/norm/t/Minimum.h"
+#include "fl/norm/t/NilpotentMinimum.h"
+
+namespace fl {
+
+ TNormFactory::TNormFactory() : ConstructionFactory<TNorm*>("TNorm") {
+ registerConstructor("", fl::null);
+ registerConstructor(AlgebraicProduct().className(), &(AlgebraicProduct::constructor));
+ registerConstructor(BoundedDifference().className(), &(BoundedDifference::constructor));
+ registerConstructor(DrasticProduct().className(), &(DrasticProduct::constructor));
+ registerConstructor(EinsteinProduct().className(), &(EinsteinProduct::constructor));
+ registerConstructor(HamacherProduct().className(), &(HamacherProduct::constructor));
+ registerConstructor(Minimum().className(), &(Minimum::constructor));
+ registerConstructor(NilpotentMinimum().className(), &(NilpotentMinimum::constructor));
+ }
+
+ TNormFactory::~TNormFactory() { }
+
+}
diff --git a/fuzzylite/src/factory/TermFactory.cpp b/fuzzylite/src/factory/TermFactory.cpp
new file mode 100644
index 0000000..e135704
--- /dev/null
+++ b/fuzzylite/src/factory/TermFactory.cpp
@@ -0,0 +1,70 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/factory/TermFactory.h"
+
+#include "fl/term/Bell.h"
+#include "fl/term/Binary.h"
+#include "fl/term/Concave.h"
+#include "fl/term/Constant.h"
+#include "fl/term/Cosine.h"
+#include "fl/term/Discrete.h"
+#include "fl/term/Function.h"
+#include "fl/term/Gaussian.h"
+#include "fl/term/GaussianProduct.h"
+#include "fl/term/Linear.h"
+#include "fl/term/PiShape.h"
+#include "fl/term/Ramp.h"
+#include "fl/term/Rectangle.h"
+#include "fl/term/SShape.h"
+#include "fl/term/Sigmoid.h"
+#include "fl/term/SigmoidDifference.h"
+#include "fl/term/SigmoidProduct.h"
+#include "fl/term/Spike.h"
+#include "fl/term/Trapezoid.h"
+#include "fl/term/Triangle.h"
+#include "fl/term/ZShape.h"
+
+namespace fl {
+
+ TermFactory::TermFactory() : ConstructionFactory<Term*>("Term") {
+ registerConstructor("", fl::null);
+ registerConstructor(Bell().className(), &(Bell::constructor));
+ registerConstructor(Binary().className(), &(Binary::constructor));
+ registerConstructor(Concave().className(), &(Concave::constructor));
+ registerConstructor(Constant().className(), &(Constant::constructor));
+ registerConstructor(Cosine().className(), &(Cosine::constructor));
+ registerConstructor(Discrete().className(), &(Discrete::constructor));
+ registerConstructor(Function().className(), &(Function::constructor));
+ registerConstructor(Gaussian().className(), &(Gaussian::constructor));
+ registerConstructor(GaussianProduct().className(), &(GaussianProduct::constructor));
+ registerConstructor(Linear().className(), &(Linear::constructor));
+ registerConstructor(PiShape().className(), &(PiShape::constructor));
+ registerConstructor(Ramp().className(), &(Ramp::constructor));
+ registerConstructor(Rectangle().className(), &(Rectangle::constructor));
+ registerConstructor(SShape().className(), &(SShape::constructor));
+ registerConstructor(Sigmoid().className(), &(Sigmoid::constructor));
+ registerConstructor(SigmoidDifference().className(), &(SigmoidDifference::constructor));
+ registerConstructor(SigmoidProduct().className(), &(SigmoidProduct::constructor));
+ registerConstructor(Spike().className(), &(Spike::constructor));
+ registerConstructor(Trapezoid().className(), &(Trapezoid::constructor));
+ registerConstructor(Triangle().className(), &(Triangle::constructor));
+ registerConstructor(ZShape().className(), &(ZShape::constructor));
+ }
+
+ TermFactory::~TermFactory() { }
+
+}
diff --git a/fuzzylite/src/fuzzylite.cpp b/fuzzylite/src/fuzzylite.cpp
new file mode 100644
index 0000000..db17fec
--- /dev/null
+++ b/fuzzylite/src/fuzzylite.cpp
@@ -0,0 +1,53 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/fuzzylite.h"
+
+namespace fl {
+
+
+ int fuzzylite::_decimals = 3;
+ std::ios_base::fmtflags fuzzylite::_scalarFormat = std::ios_base::fixed;
+ scalar fuzzylite::_macheps = 1e-6;
+ bool fuzzylite::_debugging = false;
+ bool fuzzylite::_logging = true;
+
+ std::string platform() {
+#ifdef FL_UNIX
+ return "Unix";
+#elif defined FL_WINDOWS
+ return "Windows";
+#else
+ return "?";
+#endif
+ }
+
+ std::string floatingPoint() {
+ scalar someScalar = 0;
+ FL_IUNUSED(someScalar);
+ std::string type;
+
+ std::ostringstream ss;
+#ifdef FL_USE_FLOAT
+ type = "float";
+#else
+ type = "double";
+#endif
+ ss << "fl::scalar is defined as \'" << type << "\' using " <<
+ sizeof (someScalar) << " bytes";
+ return ss.str();
+ }
+}
diff --git a/fuzzylite/src/hedge/Any.cpp b/fuzzylite/src/hedge/Any.cpp
new file mode 100644
index 0000000..9d04262
--- /dev/null
+++ b/fuzzylite/src/hedge/Any.cpp
@@ -0,0 +1,47 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/Any.h"
+
+namespace fl {
+
+ Any::Any() { }
+
+ Any::~Any() { }
+
+ std::string Any::name() const {
+ return "any";
+ }
+
+ Complexity Any::complexity() const {
+ return Complexity();
+ }
+
+ scalar Any::hedge(scalar x) const {
+ FL_IUNUSED(x);
+ return 1.0;
+ }
+
+ Any* Any::clone() const {
+ return new Any(*this);
+ }
+
+ Hedge* Any::constructor() {
+ return new Any;
+ }
+
+}
+
diff --git a/fuzzylite/src/hedge/Extremely.cpp b/fuzzylite/src/hedge/Extremely.cpp
new file mode 100644
index 0000000..60d3abd
--- /dev/null
+++ b/fuzzylite/src/hedge/Extremely.cpp
@@ -0,0 +1,46 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/Extremely.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string Extremely::name() const {
+ return "extremely";
+ }
+
+ Complexity Extremely::complexity() const {
+ return Complexity().comparison(1).arithmetic(5);
+ }
+
+ scalar Extremely::hedge(scalar x) const {
+ return Op::isLE(x, 0.5)
+ ? 2.0 * x * x
+ : (1.0 - 2.0 * (1.0 - x) * (1.0 - x));
+ }
+
+ Extremely* Extremely::clone() const {
+ return new Extremely(*this);
+ }
+
+ Hedge* Extremely::constructor() {
+ return new Extremely;
+ }
+
+}
+
diff --git a/fuzzylite/src/hedge/HedgeFunction.cpp b/fuzzylite/src/hedge/HedgeFunction.cpp
new file mode 100644
index 0000000..c31c72c
--- /dev/null
+++ b/fuzzylite/src/hedge/HedgeFunction.cpp
@@ -0,0 +1,63 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/HedgeFunction.h"
+
+namespace fl {
+
+ HedgeFunction::HedgeFunction(const std::string& formula) : Hedge() {
+ _function.variables["x"] = fl::nan;
+ if (not formula.empty()) {
+ _function.load(formula);
+ }
+ }
+
+ std::string HedgeFunction::name() const {
+ return "HedgeFunction";
+ }
+
+ Complexity HedgeFunction::complexity() const {
+ if (_function.root())
+ return _function.complexity().function(2 * std::log(scalar(_function.variables.size())));
+ return _function.complexity();
+ }
+
+ scalar HedgeFunction::hedge(scalar x) const {
+ _function.variables["x"] = x;
+ return _function.membership(x);
+ }
+
+ Function& HedgeFunction::function() {
+ return this->_function;
+ }
+
+ void HedgeFunction::setFormula(const std::string& formula) {
+ _function.load(formula);
+ }
+
+ std::string HedgeFunction::getFormula() const {
+ return _function.getFormula();
+ }
+
+ HedgeFunction* HedgeFunction::clone() const {
+ return new HedgeFunction(*this);
+ }
+
+ Hedge* HedgeFunction::constructor() {
+ return new HedgeFunction;
+ }
+
+}
diff --git a/fuzzylite/src/hedge/Not.cpp b/fuzzylite/src/hedge/Not.cpp
new file mode 100644
index 0000000..defbabd
--- /dev/null
+++ b/fuzzylite/src/hedge/Not.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/Not.h"
+
+namespace fl {
+
+ std::string Not::name() const {
+ return "not";
+ }
+
+ Complexity Not::complexity() const {
+ return Complexity().arithmetic(1);
+ }
+
+ scalar Not::hedge(scalar x) const {
+ return 1.0 - x;
+ }
+
+ Not* Not::clone() const {
+ return new Not(*this);
+ }
+
+ Hedge* Not::constructor() {
+ return new Not;
+ }
+
+}
diff --git a/fuzzylite/src/hedge/Seldom.cpp b/fuzzylite/src/hedge/Seldom.cpp
new file mode 100644
index 0000000..092e873
--- /dev/null
+++ b/fuzzylite/src/hedge/Seldom.cpp
@@ -0,0 +1,45 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/Seldom.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string Seldom::name() const {
+ return "seldom";
+ }
+
+ Complexity Seldom::complexity() const {
+ return Complexity().comparison(1).function(1).arithmetic(3);
+ }
+
+ scalar Seldom::hedge(scalar x) const {
+ return Op::isLE(x, 0.5)
+ ? std::sqrt(0.5 * x)
+ : (1.0 - std::sqrt(0.5 * (1.0 - x)));
+ }
+
+ Seldom* Seldom::clone() const {
+ return new Seldom(*this);
+ }
+
+ Hedge* Seldom::constructor() {
+ return new Seldom;
+ }
+
+}
diff --git a/fuzzylite/src/hedge/Somewhat.cpp b/fuzzylite/src/hedge/Somewhat.cpp
new file mode 100644
index 0000000..4d68c20
--- /dev/null
+++ b/fuzzylite/src/hedge/Somewhat.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/Somewhat.h"
+
+namespace fl {
+
+ std::string Somewhat::name() const {
+ return "somewhat";
+ }
+
+ Complexity Somewhat::complexity() const {
+ return Complexity().function(1);
+ }
+
+ scalar Somewhat::hedge(scalar x) const {
+ return std::sqrt(x);
+ }
+
+ Somewhat* Somewhat::clone() const {
+ return new Somewhat(*this);
+ }
+
+ Hedge* Somewhat::constructor() {
+ return new Somewhat;
+ }
+
+}
diff --git a/fuzzylite/src/hedge/Very.cpp b/fuzzylite/src/hedge/Very.cpp
new file mode 100644
index 0000000..5ac7a86
--- /dev/null
+++ b/fuzzylite/src/hedge/Very.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/hedge/Very.h"
+
+namespace fl {
+
+ std::string Very::name() const {
+ return "very";
+ }
+
+ Complexity Very::complexity() const {
+ return Complexity().arithmetic(1);
+ }
+
+ scalar Very::hedge(scalar x) const {
+ return x * x;
+ }
+
+ Very* Very::clone() const {
+ return new Very(*this);
+ }
+
+ Hedge* Very::constructor() {
+ return new Very;
+ }
+
+}
diff --git a/fuzzylite/src/imex/CppExporter.cpp b/fuzzylite/src/imex/CppExporter.cpp
new file mode 100644
index 0000000..8a77c0c
--- /dev/null
+++ b/fuzzylite/src/imex/CppExporter.cpp
@@ -0,0 +1,267 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/CppExporter.h"
+
+#include "fl/Headers.h"
+
+namespace fl {
+
+ CppExporter::CppExporter(bool prefixNamespace, bool usingVariableNames) : Exporter(),
+ _usingNamespace(prefixNamespace), _usingVariableNames(usingVariableNames) { }
+
+ CppExporter::~CppExporter() { }
+
+ std::string CppExporter::name() const {
+ return "CppExporter";
+ }
+
+ std::string CppExporter::fl(const std::string& clazz) const {
+ return _usingNamespace ? "fl::" + clazz : clazz;
+ }
+
+ void CppExporter::setUsingNamespace(bool usingNamespace) {
+ this->_usingNamespace = usingNamespace;
+ }
+
+ bool CppExporter::isUsingNamespace() const {
+ return this->_usingNamespace;
+ }
+
+ void CppExporter::setUsingVariableNames(bool usingVariableNames) {
+ this->_usingVariableNames = usingVariableNames;
+ }
+
+ bool CppExporter::isUsingVariableNames() const {
+ return this->_usingVariableNames;
+ }
+
+ std::string CppExporter::toString(const Engine* engine) const {
+ std::ostringstream cpp;
+ cpp << "//Code automatically generated with " << fuzzylite::library() << ".\n\n";
+ if (not isUsingNamespace()) cpp << "using namespace fl;\n\n";
+ cpp << fl("Engine* ") << "engine = new " << fl("Engine;\n");
+ cpp << "engine->setName(\"" << engine->getName() << "\");\n";
+ cpp << "engine->setDescription(\"" << engine->getDescription() << "\");\n";
+
+ cpp << "\n";
+
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ cpp << toString(engine->getInputVariable(i), engine) << "\n";
+ }
+
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ cpp << toString(engine->getOutputVariable(i), engine) << "\n";
+ }
+
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ cpp << toString(engine->getRuleBlock(i), engine) << "\n";
+ }
+
+ return cpp.str();
+ }
+
+ std::string CppExporter::toString(const InputVariable* inputVariable, const Engine* engine) const {
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(inputVariable->getName());
+ } else {
+ name = "inputVariable";
+ if (engine->numberOfInputVariables() > 1) {
+ std::size_t index = std::distance(engine->inputVariables().begin(),
+ std::find(engine->inputVariables().begin(),
+ engine->inputVariables().end(), inputVariable));
+ name += Op::str(index + 1);
+ }
+ }
+ std::ostringstream ss;
+ ss << fl("InputVariable* ") << name << " = new " << fl("InputVariable;\n");
+ ss << name << "->setName(\"" << inputVariable->getName() << "\");\n";
+ ss << name << "->setDescription(\"" << inputVariable->getDescription() << "\");\n";
+ ss << name << "->setEnabled(" << (inputVariable->isEnabled() ? "true" : "false") << ");\n";
+ ss << name << "->setRange(" <<
+ toString(inputVariable->getMinimum()) << ", " <<
+ toString(inputVariable->getMaximum()) << ");\n";
+ ss << name << "->setLockValueInRange(" << (inputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ for (std::size_t t = 0; t < inputVariable->numberOfTerms(); ++t) {
+ ss << name << "->addTerm(" << toString(inputVariable->getTerm(t)) << ");\n";
+ }
+ ss << "engine->addInputVariable(" << name << ");\n";
+ return ss.str();
+ }
+
+ std::string CppExporter::toString(const OutputVariable* outputVariable, const Engine* engine) const {
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(outputVariable->getName());
+ } else {
+ name = "outputVariable";
+ if (engine->numberOfOutputVariables() > 1) {
+ std::size_t index = std::distance(engine->outputVariables().begin(),
+ std::find(engine->outputVariables().begin(),
+ engine->outputVariables().end(), outputVariable));
+ name += Op::str(index + 1);
+ }
+ }
+ std::ostringstream ss;
+ ss << fl("OutputVariable* ") << name << " = new " << fl("OutputVariable;\n");
+ ss << name << "->setName(\"" << outputVariable->getName() << "\");\n";
+ ss << name << "->setDescription(\"" << outputVariable->getDescription() << "\");\n";
+ ss << name << "->setEnabled(" << (outputVariable->isEnabled() ? "true" : "false") << ");\n";
+ ss << name << "->setRange(" <<
+ toString(outputVariable->getMinimum()) << ", " <<
+ toString(outputVariable->getMaximum()) << ");\n";
+ ss << name << "->setLockValueInRange(" <<
+ (outputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ ss << name << "->setAggregation(" <<
+ toString(outputVariable->fuzzyOutput()->getAggregation()) << ");\n";
+ ss << name << "->setDefuzzifier(" <<
+ toString(outputVariable->getDefuzzifier()) << ");\n";
+ ss << name << "->setDefaultValue(" <<
+ toString(outputVariable->getDefaultValue()) << ");\n";
+ ss << name << "->setLockPreviousValue(" <<
+ (outputVariable->isLockPreviousValue() ? "true" : "false") << ");\n";
+ for (std::size_t t = 0; t < outputVariable->numberOfTerms(); ++t) {
+ ss << name << "->addTerm(" << toString(outputVariable->getTerm(t)) << ");\n";
+ }
+ ss << "engine->addOutputVariable(" << name << ");\n";
+ return ss.str();
+ }
+
+ std::string CppExporter::toString(const RuleBlock* ruleBlock, const Engine* engine) const {
+ std::string name;
+
+ if (isUsingVariableNames() and not ruleBlock->getName().empty()) {
+ name = Op::validName(ruleBlock->getName());
+ } else {
+ name = "ruleBlock";
+ if (engine->numberOfRuleBlocks() > 1) {
+ std::size_t index = std::distance(engine->ruleBlocks().begin(),
+ std::find(engine->ruleBlocks().begin(),
+ engine->ruleBlocks().end(), ruleBlock));
+ name += Op::str(index + 1);
+ }
+ }
+
+ std::ostringstream ss;
+ ss << fl("RuleBlock* ") << name << " = new " << fl("RuleBlock;\n");
+ ss << name << "->setName(\"" << ruleBlock->getName() << "\");\n";
+ ss << name << "->setDescription(\"" << ruleBlock->getDescription() << "\");\n";
+ ss << name << "->setEnabled(" << (ruleBlock->isEnabled() ? "true" : "false") << ");\n";
+ ss << name << "->setConjunction(" <<
+ toString(ruleBlock->getConjunction()) << ");\n";
+ ss << name << "->setDisjunction("
+ << toString(ruleBlock->getDisjunction()) << ");\n";
+ ss << name << "->setImplication("
+ << toString(ruleBlock->getImplication()) << ");\n";
+ ss << name << "->setActivation("
+ << toString(ruleBlock->getActivation()) << ");\n";
+ for (std::size_t r = 0; r < ruleBlock->numberOfRules(); ++r) {
+ ss << name << "->addRule(" << fl("Rule") << "::parse(\"" <<
+ ruleBlock->getRule(r)->getText() << "\", engine));\n";
+ }
+ ss << "engine->addRuleBlock(" << name << ");\n";
+ return ss.str();
+ }
+
+ std::string CppExporter::toString(scalar value) const {
+ if (Op::isNaN(value))
+ return "fl::nan";
+ if (Op::isInf(value)) {
+ return (value > 0 ? "fl::inf" : "-fl::inf");
+ }
+ return Op::str(value);
+ }
+
+ std::string CppExporter::toString(const Term* term) const {
+ if (not term) return "fl::null";
+
+ if (const Discrete * discrete = dynamic_cast<const Discrete*> (term)) {
+ std::ostringstream ss;
+ ss << fl(term->className()) << "::create(\"" << term->getName() << "\", "
+ << (discrete->xy().size() * 2) << ", "
+ << Op::join(Discrete::toVector(discrete->xy()), ", ") << ")";
+ return ss.str();
+ }
+
+ if (const Function * function = dynamic_cast<const Function*> (term)) {
+ std::ostringstream ss;
+ ss << fl(term->className()) << "::create(\"" << term->getName() << "\", "
+ << "\"" << function->getFormula() << "\", engine)";
+ return ss.str();
+ }
+
+ if (const Linear * linear = dynamic_cast<const Linear*> (term)) {
+ std::ostringstream ss;
+ ss << fl(term->className()) << "::create(\"" << term->getName() << "\", "
+ << "engine, " << Op::join(linear->coefficients(), ", ") << ")";
+ return ss.str();
+ }
+
+ std::ostringstream ss;
+ ss << "new " << fl(term->className()) << "(\"" << term->getName() << "\", "
+ << Op::findReplace(term->parameters(), " ", ", ") << ")";
+ return ss.str();
+ }
+
+ std::string CppExporter::toString(const Hedge * hedge) const {
+ if (hedge->name() == Any().name()) return "new " + fl("Any");
+ if (hedge->name() == Extremely().name()) return "new " + fl("Extremely");
+ if (hedge->name() == Not().name()) return "new " + fl("Not");
+ if (hedge->name() == Seldom().name()) return "new " + fl("Seldom");
+ if (hedge->name() == Somewhat().name()) return "new " + fl("Somewhat");
+ if (hedge->name() == Very().name()) return "new " + fl("Very");
+ return "new " + fl(hedge->name());
+ }
+
+ std::string CppExporter::toString(const Norm* op) const {
+ if (not op) return "fl::null";
+ return "new " + fl(op->className());
+ }
+
+ std::string CppExporter::toString(const Defuzzifier* defuzzifier) const {
+ if (not defuzzifier) return "fl::null";
+ if (const IntegralDefuzzifier * integralDefuzzifier =
+ dynamic_cast<const IntegralDefuzzifier*> (defuzzifier)) {
+ return "new " + fl(integralDefuzzifier->className()) + "("
+ + Op::str(integralDefuzzifier->getResolution()) + ")";
+ }
+ if (const WeightedDefuzzifier * weightedDefuzzifier =
+ dynamic_cast<const WeightedDefuzzifier*> (defuzzifier)) {
+ return "new " + weightedDefuzzifier->className() +
+ "(\"" + weightedDefuzzifier->getTypeName() + "\")";
+ }
+ return "new " + fl(defuzzifier->className());
+ }
+
+ std::string CppExporter::toString(const Activation* activation) const {
+ if (not activation) return "fl::null";
+ std::string parameters = Op::trim(activation->parameters());
+ if (parameters.empty()) return "new " + fl(activation->className());
+
+ std::vector<std::string> values = Op::split(parameters, " ");
+ for (std::size_t i = 0; i < values.size(); ++i) {
+ std::string parameter = values.at(i);
+ values.at(i) = (Op::isNumeric(parameter) ? parameter : ("\"" + parameter + "\""));
+ }
+ return "new " + fl(activation->className()) + "(" + Op::join(values, ", ") + ")";
+ }
+
+ CppExporter* CppExporter::clone() const {
+ return new CppExporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/Exporter.cpp b/fuzzylite/src/imex/Exporter.cpp
new file mode 100644
index 0000000..1aaf24e
--- /dev/null
+++ b/fuzzylite/src/imex/Exporter.cpp
@@ -0,0 +1,37 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/Exporter.h"
+#include "fl/Exception.h"
+
+#include <fstream>
+
+namespace fl {
+
+ Exporter::Exporter() { }
+
+ Exporter::~Exporter() { }
+
+ void Exporter::toFile(const std::string& path, const Engine* engine) const {
+ std::ofstream writer(path.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ }
+ writer << toString(engine) << std::endl;
+ writer.close();
+ }
+
+}
diff --git a/fuzzylite/src/imex/FclExporter.cpp b/fuzzylite/src/imex/FclExporter.cpp
new file mode 100644
index 0000000..98f1177
--- /dev/null
+++ b/fuzzylite/src/imex/FclExporter.cpp
@@ -0,0 +1,200 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FclExporter.h"
+
+#include "fl/Headers.h"
+
+namespace fl {
+
+ FclExporter::FclExporter(const std::string& indent) : Exporter(), _indent(indent) { }
+
+ FclExporter::~FclExporter() { }
+
+ void FclExporter::setIndent(const std::string& indent) {
+ this->_indent = indent;
+ }
+
+ std::string FclExporter::getIndent() const {
+ return this->_indent;
+ }
+
+ std::string FclExporter::name() const {
+ return "FclExporter";
+ }
+
+ std::string FclExporter::toString(const Engine* engine) const {
+ std::ostringstream fcl;
+ fcl << "//Code automatically generated with " << fuzzylite::library() << ".\n\n";
+ fcl << "FUNCTION_BLOCK " << engine->getName() << "\n\n";
+
+ fcl << "VAR_INPUT\n";
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ fcl << _indent << Op::validName(engine->getInputVariable(i)->getName()) << ": REAL;\n";
+ }
+ fcl << "END_VAR\n\n";
+
+ fcl << "VAR_OUTPUT\n";
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ fcl << _indent << Op::validName(engine->getOutputVariable(i)->getName()) << ": REAL;\n";
+ }
+ fcl << "END_VAR\n\n";
+
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ InputVariable* inputVariable = engine->getInputVariable(i);
+ fcl << toString(inputVariable) << "\n";
+ }
+
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ OutputVariable* outputVariable = engine->getOutputVariable(i);
+ fcl << toString(outputVariable) << "\n";
+ }
+
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ RuleBlock* ruleblock = engine->getRuleBlock(i);
+ fcl << toString(ruleblock) << "\n";
+ }
+
+ fcl << "END_FUNCTION_BLOCK\n";
+ return fcl.str();
+ }
+
+ std::string FclExporter::toString(const InputVariable* inputVariable) const {
+ std::ostringstream fcl;
+ fcl << "FUZZIFY " << Op::validName(inputVariable->getName()) << "\n";
+ fcl << _indent << "RANGE := (" << Op::join(2, " .. ",
+ inputVariable->getMinimum(), inputVariable->getMaximum())
+ << ");\n";
+
+ for (std::size_t t = 0; t < inputVariable->numberOfTerms(); ++t) {
+ Term* term = inputVariable->getTerm(t);
+ fcl << _indent << "TERM " << Op::validName(term->getName()) << " := " << toString(term)
+ << ";\n";
+ }
+ fcl << "END_FUZZIFY\n";
+ return fcl.str();
+ }
+
+ std::string FclExporter::toString(const OutputVariable* outputVariable) const {
+ std::ostringstream fcl;
+ fcl << "DEFUZZIFY " << Op::validName(outputVariable->getName()) << "\n";
+ fcl << _indent << "RANGE := (" << Op::join(2, " .. ",
+ outputVariable->getMinimum(), outputVariable->getMaximum())
+ << ");\n";
+
+ for (std::size_t t = 0; t < outputVariable->numberOfTerms(); ++t) {
+ Term* term = outputVariable->getTerm(t);
+ fcl << _indent << "TERM " << Op::validName(term->getName()) << " := " << toString(term)
+ << ";\n";
+ }
+ if (outputVariable->getDefuzzifier()) {
+ fcl << _indent << "METHOD : " << toString(outputVariable->getDefuzzifier()) << ";\n";
+ }
+ if (outputVariable->fuzzyOutput()->getAggregation())
+ fcl << _indent << "ACCU : " << toString(outputVariable->fuzzyOutput()->getAggregation()) << ";\n";
+
+ fcl << _indent << "DEFAULT := " << Op::str(outputVariable->getDefaultValue());
+ if (outputVariable->isLockPreviousValue()) {
+ fcl << " | NC";
+ }
+ fcl << ";\n";
+
+ fcl << "END_DEFUZZIFY\n";
+ return fcl.str();
+ }
+
+ std::string FclExporter::toString(const RuleBlock* ruleBlock) const {
+ std::ostringstream fcl;
+ fcl << "RULEBLOCK " << ruleBlock->getName() << "\n";
+ if (ruleBlock->getConjunction())
+ fcl << _indent << "AND : " << toString(ruleBlock->getConjunction()) << ";\n";
+ if (ruleBlock->getDisjunction())
+ fcl << _indent << "OR : " << toString(ruleBlock->getDisjunction()) << ";\n";
+ if (ruleBlock->getImplication())
+ fcl << _indent << "ACT : " << toString(ruleBlock->getImplication()) << ";\n";
+
+ for (std::size_t r = 0; r < ruleBlock->numberOfRules(); ++r) {
+ fcl << _indent << "RULE " << (r + 1) << " : " <<
+ ruleBlock->getRule(r)->getText() << "\n";
+ }
+ fcl << "END_RULEBLOCK\n";
+ return fcl.str();
+ }
+
+ std::string FclExporter::toString(const Norm* norm) const {
+ if (not norm) return "NONE";
+
+ std::string name = norm->className();
+ //TNorms
+ if (name == Minimum().className()) return "MIN";
+ if (name == AlgebraicProduct().className()) return "PROD";
+ if (name == BoundedDifference().className()) return "BDIF";
+ if (name == DrasticProduct().className()) return "DPROD";
+ if (name == EinsteinProduct().className()) return "EPROD";
+ if (name == HamacherProduct().className()) return "HPROD";
+ if (name == NilpotentMinimum().className()) return "NMIN";
+
+ //SNorms
+ if (name == Maximum().className()) return "MAX";
+ if (name == AlgebraicSum().className()) return "ASUM";
+ if (name == NormalizedSum().className()) return "NSUM";
+ if (name == BoundedSum().className()) return "BSUM";
+ if (name == DrasticSum().className()) return "DSUM";
+ if (name == EinsteinSum().className()) return "ESUM";
+ if (name == HamacherSum().className()) return "HSUM";
+ if (name == NilpotentMaximum().className()) return "NMAX";
+
+ return norm->className();
+ }
+
+ std::string FclExporter::toString(const Defuzzifier* defuzzifier) const {
+ if (not defuzzifier) return "NONE";
+ if (defuzzifier->className() == Centroid().className()) return "COG";
+ if (defuzzifier->className() == Bisector().className()) return "COA";
+ if (defuzzifier->className() == SmallestOfMaximum().className()) return "LM";
+ if (defuzzifier->className() == LargestOfMaximum().className()) return "RM";
+ if (defuzzifier->className() == MeanOfMaximum().className()) return "MM";
+ if (defuzzifier->className() == WeightedAverage().className()) return "COGS";
+ if (defuzzifier->className() == WeightedSum().className()) return "COGSS";
+ return defuzzifier->className();
+ }
+
+ std::string FclExporter::toString(const Term* term) const {
+ if (not term) return "";
+ if (const Discrete * discrete = dynamic_cast<const Discrete*> (term)) {
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < discrete->xy().size(); ++i) {
+ ss << "(" << Op::str(discrete->xy(i).first) << ", "
+ << Op::str(discrete->xy(i).second) << ")";
+ if (i + 1 < discrete->xy().size()) ss << " ";
+ }
+ return ss.str();
+ }
+
+ if (const Constant * constant = dynamic_cast<const Constant*> (term)) {
+ return Op::str(constant->getValue());
+ }
+
+ std::ostringstream ss;
+ ss << term->className() << " " << term->parameters();
+ return ss.str();
+ }
+
+ FclExporter* FclExporter::clone() const {
+ return new FclExporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/FclImporter.cpp b/fuzzylite/src/imex/FclImporter.cpp
new file mode 100644
index 0000000..06879cd
--- /dev/null
+++ b/fuzzylite/src/imex/FclImporter.cpp
@@ -0,0 +1,587 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FclImporter.h"
+
+#include "fl/Headers.h"
+
+namespace fl {
+
+ FclImporter::FclImporter() : Importer() { }
+
+ FclImporter::~FclImporter() { }
+
+ std::string FclImporter::name() const {
+ return "FclImporter";
+ }
+
+ Engine* FclImporter::fromString(const std::string& fcl) const {
+ FL_unique_ptr<Engine> engine(new Engine);
+
+ std::map<std::string, std::string> tags;
+ tags["VAR_INPUT"] = "END_VAR";
+ tags["VAR_OUTPUT"] = "END_VAR";
+ tags["FUZZIFY"] = "END_FUZZIFY";
+ tags["DEFUZZIFY"] = "END_DEFUZZIFY";
+ tags["RULEBLOCK"] = "END_RULEBLOCK";
+ std::map<std::string, std::string>::const_iterator tagFinder;
+
+ std::string currentTag = "", closingTag = "";
+ std::ostringstream block;
+ std::istringstream fclReader(fcl);
+ std::string line;
+
+ std::size_t lineNumber = 0;
+ while (std::getline(fclReader, line)) {
+ ++lineNumber;
+ line = Op::split(line, "//", false).front();
+ line = Op::split(line, "#", false).front();
+ line = Op::trim(Op::findReplace(line, ";", ""));
+ if (line.empty() or line.at(0) == '%') {
+ continue;
+ }
+
+ std::istringstream tokenizer(line);
+ std::string firstToken;
+ tokenizer >> firstToken;
+
+ if (firstToken == "FUNCTION_BLOCK") {
+ if (tokenizer.rdbuf()->in_avail() > 0) {
+ std::ostringstream name;
+ std::string token;
+ tokenizer >> token;
+ name << token;
+ while (tokenizer >> token) {
+ name << " " << token;
+ }
+ engine->setName(name.str());
+ }
+ continue;
+ }
+ if (firstToken == "END_FUNCTION_BLOCK") {
+ break;
+ }
+
+ if (currentTag.empty()) {
+ tagFinder = tags.find(firstToken);
+ if (tagFinder == tags.end()) {
+ std::ostringstream ex;
+ ex << "[syntax error] unknown block definition <" << firstToken
+ << "> " << " in line " << lineNumber << ": " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ currentTag = tagFinder->first;
+ closingTag = tagFinder->second;
+ block.str("");
+ block.clear();
+ block << line << "\n";
+ continue;
+ }
+
+ if (not currentTag.empty()) {
+ if (firstToken == closingTag) {
+ processBlock(currentTag, block.str(), engine.get());
+ currentTag = "";
+ closingTag = "";
+ } else if (tags.find(firstToken) != tags.end()) {
+ //if opening new block without closing the previous one
+ std::ostringstream ex;
+ ex << "[syntax error] expected <" << closingTag << "> before <"
+ << firstToken << "> in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ } else {
+ block << line << "\n";
+ }
+ continue;
+ }
+ }
+
+ if (not currentTag.empty()) {
+ std::ostringstream ex;
+ ex << "[syntax error] ";
+ if (block.rdbuf()->in_avail() > 0) {
+ ex << "expected <" << closingTag << "> for block:\n" << block.str();
+ } else {
+ ex << "expected <" << closingTag << ">, but not found";
+ }
+ throw Exception(ex.str(), FL_AT);
+ }
+ return engine.release();
+ }
+
+ void FclImporter::processBlock(const std::string& tag, const std::string& block, Engine* engine) const {
+ if (tag == "VAR_INPUT" or tag == "VAR_OUTPUT") {
+ processVar(tag, block, engine);
+ } else if (tag == "FUZZIFY") {
+ processFuzzify(block, engine);
+ } else if (tag == "DEFUZZIFY") {
+ processDefuzzify(block, engine);
+ } else if (tag == "RULEBLOCK") {
+ processRuleBlock(block, engine);
+ } else {
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected tag <" << tag << "> for block:\n" << block;
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+
+ void FclImporter::processVar(const std::string& tag, const std::string& block, Engine* engine)const {
+ std::istringstream blockReader(block);
+ std::string line;
+
+ std::getline(blockReader, line); //discard first line as it is VAR_INPUT
+ while (std::getline(blockReader, line)) {
+ std::vector<std::string> token = Op::split(line, ":");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key : value) in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ std::string name = Op::validName(token.at(0));
+ if (tag == "VAR_INPUT")
+ engine->addInputVariable(new InputVariable(name));
+ else if (tag == "VAR_OUTPUT")
+ engine->addOutputVariable(new OutputVariable(name));
+ else {
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected tag <" << tag << "> in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+ }
+
+ void FclImporter::processFuzzify(const std::string& block, Engine* engine)const {
+ std::istringstream blockReader(block);
+ std::string line;
+
+ std::getline(blockReader, line);
+ std::string name;
+ std::size_t index = line.find_first_of(' ');
+ if (index != std::string::npos) {
+ name = Op::validName(line.substr(index + 1));
+ } else {
+ std::ostringstream ex;
+ ex << "[syntax error] expected name of input variable in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (not engine->hasInputVariable(name)) {
+ std::ostringstream ex;
+ ex << "[syntax error] engine does not contain "
+ "input variable <" << name << "> from line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ InputVariable* inputVariable = engine->getInputVariable(name);
+ while (std::getline(blockReader, line)) {
+ std::istringstream ss(line);
+ std::string firstToken;
+ ss >> firstToken;
+ try {
+ if (firstToken == "RANGE") {
+ std::pair<scalar, scalar> minmax = parseRange(line);
+ inputVariable->setMinimum(minmax.first);
+ inputVariable->setMaximum(minmax.second);
+ } else if (firstToken == "ENABLED") {
+ inputVariable->setEnabled(parseEnabled(line));
+ } else if (firstToken == "TERM") {
+ inputVariable->addTerm(parseTerm(line, engine));
+ } else throw Exception("[syntax error] unexpected token "
+ "<" + firstToken + ">" + line, FL_AT);
+ } catch (Exception& ex) {
+ ex.append("At line: <" + line + ">");
+ throw;
+ }
+ }
+
+ }
+
+ void FclImporter::processDefuzzify(const std::string& block, Engine* engine) const {
+ std::istringstream blockReader(block);
+ std::string line;
+
+ std::getline(blockReader, line);
+ std::string name;
+ std::size_t index = line.find_first_of(' ');
+ if (index != std::string::npos) {
+ name = Op::validName(line.substr(index + 1));
+ } else {
+ std::ostringstream ex;
+ ex << "[syntax error] expected an output variable name in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (not engine->hasOutputVariable(name)) {
+ std::ostringstream ex;
+ ex << "[syntax error] output variable <" << name
+ << "> not registered in engine. "
+ << "Line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ OutputVariable* outputVariable = engine->getOutputVariable(name);
+ while (std::getline(blockReader, line)) {
+ line = Op::trim(line);
+ std::istringstream tokenizer(line);
+ std::string firstToken;
+ tokenizer >> firstToken;
+ if (firstToken == "TERM") {
+ outputVariable->addTerm(parseTerm(line, engine));
+ } else if (firstToken == "METHOD") {
+ outputVariable->setDefuzzifier(parseDefuzzifier(line));
+ } else if (firstToken == "ACCU") {
+ outputVariable->fuzzyOutput()->setAggregation(parseSNorm(line));
+ } else if (firstToken == "DEFAULT") {
+ std::pair<scalar, bool> defaultAndLock = parseDefaultValue(line);
+ outputVariable->setDefaultValue(defaultAndLock.first);
+ outputVariable->setLockPreviousValue(defaultAndLock.second or
+ outputVariable->isLockPreviousValue());
+ } else if (firstToken == "RANGE") {
+ std::pair<scalar, scalar> minmax = parseRange(line);
+ outputVariable->setMinimum(minmax.first);
+ outputVariable->setMaximum(minmax.second);
+ } else if (firstToken == "LOCK") {
+ std::pair<bool, bool> output_range = parseLocks(line);
+ outputVariable->setLockPreviousValue(output_range.first);
+ outputVariable->setLockValueInRange(output_range.second);
+ } else if (firstToken == "ENABLED") {
+ outputVariable->setEnabled(parseEnabled(line));
+ } else {
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected token <" << firstToken <<
+ "> in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+
+ }
+
+ void FclImporter::processRuleBlock(const std::string& block, Engine* engine)const {
+ std::istringstream blockReader(block);
+ std::string line;
+
+ std::string name;
+ std::getline(blockReader, line);
+ std::size_t index = line.find_last_of(' ');
+ if (index != std::string::npos) name = line.substr(index + 1);
+ RuleBlock * ruleblock = new RuleBlock(name);
+ ruleblock->setActivation(new General);
+ engine->addRuleBlock(ruleblock);
+
+ while (std::getline(blockReader, line)) {
+ std::string firstToken = line.substr(0, line.find_first_of(' '));
+ if (firstToken == "AND") {
+ ruleblock->setConjunction(parseTNorm(line));
+ } else if (firstToken == "OR") {
+ ruleblock->setDisjunction(parseSNorm(line));
+ } else if (firstToken == "ACT") {
+ ruleblock->setImplication(parseTNorm(line));
+ } else if (firstToken == "ENABLED") {
+ ruleblock->setEnabled(parseEnabled(line));
+ } else if (firstToken == "RULE") {
+ std::size_t ruleStart = line.find_first_of(':');
+ if (ruleStart == std::string::npos) ruleStart = 4; // "RULE".size()
+ std::string ruleText = line.substr(ruleStart + 1);
+ ruleText = Op::trim(ruleText);
+ Rule* rule = new Rule(ruleText);
+ try {
+ rule->load(engine);
+ } catch (...) {
+ //ignore
+ }
+ ruleblock->addRule(rule);
+ } else {
+ std::ostringstream ex;
+ ex << "[syntax error] keyword <" << firstToken
+ << "> not recognized in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+ }
+
+ TNorm* FclImporter::parseTNorm(const std::string& line) const {
+ std::vector<std::string> token = Op::split(line, ":");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key : value) in line: "
+ << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ std::string name = Op::trim(token.at(1));
+ std::string className = name;
+ if (name == "NONE") className = "";
+ else if (name == "MIN") className = Minimum().className();
+ else if (name == "PROD") className = AlgebraicProduct().className();
+ else if (name == "BDIF") className = BoundedDifference().className();
+ else if (name == "DPROD") className = DrasticProduct().className();
+ else if (name == "EPROD") className = EinsteinProduct().className();
+ else if (name == "HPROD") className = HamacherProduct().className();
+ else if (name == "NMIN") className = NilpotentMinimum().className();
+
+ return FactoryManager::instance()->tnorm()->constructObject(className);
+ }
+
+ SNorm* FclImporter::parseSNorm(const std::string& line) const {
+ std::vector<std::string> token = Op::split(line, ":");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key : value) in line: "
+ << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ std::string name = Op::trim(token.at(1));
+ std::string className = name;
+ if (name == "NONE") className = "";
+ else if (name == "MAX") className = Maximum().className();
+ else if (name == "ASUM") className = AlgebraicSum().className();
+ else if (name == "BSUM") className = BoundedSum().className();
+ else if (name == "NSUM") className = NormalizedSum().className();
+ else if (name == "DSUM") className = DrasticSum().className();
+ else if (name == "ESUM") className = EinsteinSum().className();
+ else if (name == "HSUM") className = HamacherSum().className();
+ else if (name == "NMAX") className = NilpotentMaximum().className();
+
+ return FactoryManager::instance()->snorm()->constructObject(className);
+ }
+
+ Term* FclImporter::parseTerm(const std::string& line, const Engine* engine) const {
+ std::ostringstream spacer;
+ for (std::size_t i = 0; i < line.size(); ++i) {
+ if (line.at(i) == '(' or line.at(i) == ')' or line.at(i) == ',') {
+ spacer << " " << line.at(i) << " ";
+ } else if (line.at(i) == ':') {
+ spacer << " :";
+ } else if (line.at(i) == '=') {
+ spacer << "= ";
+ } else
+ spacer << line.at(i);
+ }
+ std::string spacedLine = spacer.str();
+
+ enum FSM {
+ S_KWTERM, S_NAME, S_ASSIGN, S_TERMCLASS, S_PARAMETERS
+ };
+ FSM state = S_KWTERM;
+ std::istringstream tokenizer(spacedLine);
+ std::string token;
+ std::string name, termClass;
+ std::vector<std::string> parameters;
+ while (tokenizer >> token) {
+ if (state == S_KWTERM and token == "TERM") {
+ state = S_NAME;
+ continue;
+ }
+ if (state == S_NAME) {
+ name = token;
+ state = S_ASSIGN;
+ continue;
+ }
+ if (state == S_ASSIGN and token == ":=") {
+ state = S_TERMCLASS;
+ continue;
+ }
+ if (state == S_TERMCLASS) {
+ if (Op::isNumeric(token)) {
+ termClass = Constant().className();
+ parameters.push_back(token);
+ } else if (token == "(") {
+ termClass = Discrete().className();
+ } else {
+ termClass = token;
+ }
+ state = S_PARAMETERS;
+ continue;
+ }
+ if (state == S_PARAMETERS) {
+ if (termClass != Function().className() and
+ (token == "(" or token == ")" or token == ",")) {
+ continue;
+ }
+ if (token == ";") break;
+ parameters.push_back(Op::trim(token));
+ }
+ }
+ if (state <= S_TERMCLASS)
+ throw Exception("[syntax error] malformed term in line: " + line, FL_AT);
+
+ FL_unique_ptr<Term> term;
+ term.reset(FactoryManager::instance()->term()->constructObject(termClass));
+ term->updateReference(engine);
+ term->setName(Op::validName(name));
+ std::string separator;
+ if (not dynamic_cast<Function*> (term.get())) {
+ separator = " ";
+ }
+ term->configure(Op::join(parameters, separator)); //remove spaces for text of function
+ return term.release();
+ }
+
+ Defuzzifier* FclImporter::parseDefuzzifier(const std::string& line) const {
+ std::vector<std::string> token = Op::split(line, ":");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key : value) in "
+ << "line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ std::string name = Op::trim(token.at(1));
+ std::string className = name;
+ if (name == "NONE") className = "";
+ else if (name == "COG") className = Centroid().className();
+ else if (name == "COA") className = Bisector().className();
+ else if (name == "LM") className = SmallestOfMaximum().className();
+ else if (name == "RM") className = LargestOfMaximum().className();
+ else if (name == "MM") className = MeanOfMaximum().className();
+ else if (name == "COGS") className = WeightedAverage().className();
+ else if (name == "COGSS") className = WeightedSum().className();
+
+ return FactoryManager::instance()->defuzzifier()->constructObject(className);
+ }
+
+ std::pair<scalar, bool> FclImporter::parseDefaultValue(const std::string& line) const {
+ std::vector<std::string> token = Op::split(line, ":=");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key := value) in line: "
+ << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ std::vector<std::string> values = Op::split(token.at(1), "|");
+
+ std::string defaultValue = values.front();
+ std::string nc;
+ if (values.size() == 2) nc = values.back();
+
+ defaultValue = Op::trim(defaultValue);
+ nc = Op::trim(nc);
+
+ scalar value;
+ try {
+ value = Op::toScalar(defaultValue);
+ } catch (...) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected numeric value, "
+ << "but found <" << defaultValue << "> in line: "
+ << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ bool lockPreviousOutput = (nc == "NC");
+
+ if (not (lockPreviousOutput or nc.empty())) {
+ throw Exception("[syntax error] expected keyword <NC>, "
+ "but found <" + nc + "> in line: " + line, FL_AT);
+ }
+
+ return std::pair<scalar, bool>(value, lockPreviousOutput);
+ }
+
+ std::pair<scalar, scalar> FclImporter::parseRange(const std::string& line) const {
+ std::vector<std::string> token = Op::split(line, ":=");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key := value) in line: "
+ << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ std::string rangeToken = token.at(1);
+
+ std::ostringstream range;
+ for (std::size_t i = 0; i < rangeToken.size(); ++i) {
+ char character = rangeToken.at(i);
+ if (character == '(' or character == ')' or character == ' ' or character == ';')
+ continue;
+ range << character;
+ }
+ token = Op::split(range.str(), "..");
+ if (token.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type 'start .. end', "
+ << "but found <" << range.str() << "> in line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+ scalar minimum, maximum;
+ int index;
+ try {
+ minimum = Op::toScalar(token.at(index = 0));
+ maximum = Op::toScalar(token.at(index = 1));
+ } catch (std::exception& ex) {
+ FL_IUNUSED(ex);
+ std::ostringstream ss;
+ ss << "[syntax error] expected numeric value, but found <" << token.at(index) << "> in "
+ << "line: " << line;
+ throw Exception(ss.str(), FL_AT);
+ }
+ return std::pair<scalar, scalar>(minimum, maximum);
+ }
+
+ std::pair<bool, bool> FclImporter::parseLocks(const std::string& line) const {
+ std::size_t index = line.find_first_of(":");
+ if (index == std::string::npos) {
+ throw Exception("[syntax error] expected property of type "
+ "'key : value' in line: " + line, FL_AT);
+ }
+ bool output, range;
+ std::string value = line.substr(index + 1);
+ std::vector<std::string> flags = Op::split(value, "|");
+ if (flags.size() == 1) {
+ std::string flag = Op::trim(flags.front());
+ output = (flag == "PREVIOUS");
+ range = (flag == "RANGE");
+ if (not (output or range)) {
+ throw Exception("[syntax error] expected locking flags "
+ "<PREVIOUS|RANGE>, but found <" + flag + "> in line: " + line, FL_AT);
+ }
+ } else if (flags.size() == 2) {
+ std::string flagA = Op::trim(flags.front());
+ std::string flagB = Op::trim(flags.back());
+ output = (flagA == "PREVIOUS" or flagB == "PREVIOUS");
+ range = (flagA == "RANGE" or flagB == "RANGE");
+ if (not (output and range)) {
+ throw Exception("[syntax error] expected locking flags "
+ "<PREVIOUS|RANGE>, but found "
+ "<" + flags.front() + "|" + flags.back() + "> in line: " + line, FL_AT);
+ }
+ } else {
+ throw Exception("[syntax error] expected locking flags "
+ "<PREVIOUS|RANGE>, but found "
+ "<" + value + "> in line: " + line, FL_AT);
+ }
+ return std::pair<bool, bool>(output, range);
+ }
+
+ bool FclImporter::parseEnabled(const std::string& line) const {
+ std::vector<std::string> tokens = Op::split(line, ":");
+ if (tokens.size() != 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected property of type (key : value) in "
+ << "line: " << line;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ std::string boolean = Op::trim(tokens.at(1));
+ if (boolean == "TRUE") return true;
+ if (boolean == "FALSE") return false;
+ throw Exception("[syntax error] expected boolean <TRUE|FALSE>, but found <" + line + ">", FL_AT);
+ }
+
+ FclImporter* FclImporter::clone() const {
+ return new FclImporter(*this);
+ }
+
+
+}
diff --git a/fuzzylite/src/imex/FisExporter.cpp b/fuzzylite/src/imex/FisExporter.cpp
new file mode 100644
index 0000000..2daac9a
--- /dev/null
+++ b/fuzzylite/src/imex/FisExporter.cpp
@@ -0,0 +1,423 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FisExporter.h"
+
+#include "fl/Headers.h"
+
+#include <queue>
+
+namespace fl {
+
+ FisExporter::FisExporter() : Exporter() { }
+
+ FisExporter::~FisExporter() { }
+
+ std::string FisExporter::name() const {
+ return "FisExporter";
+ }
+
+ std::string FisExporter::toString(const Engine* engine) const {
+ std::ostringstream fis;
+ fis << exportSystem(engine) << "\n";
+
+ fis << exportInputs(engine);
+
+ fis << exportOutputs(engine);
+
+ fis << exportRules(engine);
+
+ return fis.str();
+ }
+
+ std::string FisExporter::exportSystem(const Engine* engine) const {
+ std::ostringstream fis;
+ fis << "#Code automatically generated with " << fuzzylite::library() << ".\n\n";
+ fis << "[System]\n";
+ fis << "Name='" << engine->getName() << "'\n";
+ std::string type;
+ if (engine->type() == Engine::Mamdani or engine->type() == Engine::Larsen) {
+ type = "mamdani";
+ } else if (engine->type() == Engine::TakagiSugeno) {
+ type = "sugeno";
+ } else if (engine->type() == Engine::Tsukamoto) {
+ type = "tsukamoto";
+ } else if (engine->type() == Engine::InverseTsukamoto) {
+ type = "inverse tsukamoto";
+ } else if (engine->type() == Engine::Hybrid) {
+ type = "hybrid";
+ } else {
+ type = "unknown";
+ }
+ fis << "Type='" << type << "'\n";
+ fis << "Version=" << fuzzylite::version() << "\n";
+ fis << "NumInputs=" << engine->numberOfInputVariables() << "\n";
+ fis << "NumOutputs=" << engine->numberOfOutputVariables() << "\n";
+
+ std::size_t numberOfRules = 0;
+ const TNorm* conjunction = fl::null;
+ const SNorm* disjunction = fl::null;
+ const TNorm* implication = fl::null;
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ RuleBlock* rb = engine->getRuleBlock(i);
+ numberOfRules += rb->numberOfRules();
+ if (not conjunction) conjunction = rb->getConjunction();
+ if (not disjunction) disjunction = rb->getDisjunction();
+ if (not implication) implication = rb->getImplication();
+ }
+ fis << "NumRules=" << numberOfRules << "\n";
+ fis << "AndMethod='" << (conjunction ? toString(conjunction) : "min") << "'\n";
+ fis << "OrMethod='" << (disjunction ? toString(disjunction) : "max") << "'\n";
+ fis << "ImpMethod='" << (implication ? toString(implication) : "min") << "'\n";
+
+ const SNorm* aggregation = fl::null;
+ Defuzzifier* defuzzifier = fl::null;
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ OutputVariable* outputVariable = engine->getOutputVariable(i);
+ if (not aggregation) aggregation = outputVariable->fuzzyOutput()->getAggregation();
+ if (not defuzzifier) defuzzifier = outputVariable->getDefuzzifier();
+ }
+
+ fis << "AggMethod='" << (aggregation ? toString(aggregation) : "max") << "'\n";
+ fis << "DefuzzMethod='" << toString(defuzzifier) << "'\n";
+ return fis.str();
+ }
+
+ std::string FisExporter::exportInputs(const Engine* engine) const {
+ std::ostringstream fis;
+ for (std::size_t ixVar = 0; ixVar < engine->numberOfInputVariables(); ++ixVar) {
+ InputVariable* var = engine->getInputVariable(ixVar);
+ fis << "[Input" << (ixVar + 1) << "]\n";
+ fis << "Name='" << Op::validName(var->getName()) << "'\n";
+ fis << "Range=[" << Op::join(2, " ", var->getMinimum(), var->getMaximum()) << "]\n";
+ fis << "NumMFs=" << var->numberOfTerms() << "\n";
+ for (std::size_t ixTerm = 0; ixTerm < var->numberOfTerms(); ++ixTerm) {
+ fis << "MF" << (ixTerm + 1) << "='" << Op::validName(var->getTerm(ixTerm)->getName()) << "':"
+ << toString(var->getTerm(ixTerm)) << "\n";
+ }
+ fis << "\n";
+ }
+ return fis.str();
+ }
+
+ std::string FisExporter::exportOutputs(const Engine* engine) const {
+ std::ostringstream fis;
+ for (std::size_t ixVar = 0; ixVar < engine->numberOfOutputVariables(); ++ixVar) {
+ OutputVariable* var = engine->getOutputVariable(ixVar);
+ fis << "[Output" << (ixVar + 1) << "]\n";
+ fis << "Name='" << Op::validName(var->getName()) << "'\n";
+ fis << "Range=[" << Op::join(2, " ", var->getMinimum(), var->getMaximum()) << "]\n";
+ fis << "NumMFs=" << var->numberOfTerms() << "\n";
+ for (std::size_t ixTerm = 0; ixTerm < var->numberOfTerms(); ++ixTerm) {
+ fis << "MF" << (ixTerm + 1) << "='" << Op::validName(var->getTerm(ixTerm)->getName()) << "':"
+ << toString(var->getTerm(ixTerm)) << "\n";
+ }
+ fis << "\n";
+ }
+ return fis.str();
+ }
+
+ std::string FisExporter::exportRules(const Engine* engine) const {
+ std::ostringstream fis;
+ fis << "[Rules]\n";
+ for (std::size_t ixRuleBlock = 0; ixRuleBlock < engine->numberOfRuleBlocks(); ++ixRuleBlock) {
+ RuleBlock* rb = engine->getRuleBlock(ixRuleBlock);
+ if (engine->numberOfRuleBlocks() > 1) fis << "# RuleBlock " << rb->getName() << "\n";
+ for (std::size_t ixRule = 0; ixRule < rb->numberOfRules(); ++ixRule) {
+ Rule* rule = rb->getRule(ixRule);
+ if (rule->isLoaded()) {
+ fis << exportRule(rule, engine) << "\n";
+ }
+ }
+ }
+ return fis.str();
+ }
+
+ std::string FisExporter::exportRule(const Rule* rule, const Engine* engine) const {
+ if (not rule) return "";
+ std::vector<Proposition*> propositions;
+ std::vector<Operator*> operators;
+
+ std::queue<Expression*> bfsQueue;
+ bfsQueue.push(rule->getAntecedent()->getExpression());
+ while (not bfsQueue.empty()) {
+ Expression* front = bfsQueue.front();
+ bfsQueue.pop();
+ Operator* op = dynamic_cast<Operator*> (front);
+ if (op) {
+ bfsQueue.push(op->left);
+ bfsQueue.push(op->right);
+ operators.push_back(op);
+ } else {
+ propositions.push_back(dynamic_cast<Proposition*> (front));
+ }
+ }
+
+ bool equalOperators = true;
+ for (std::size_t i = 0; i + 1 < operators.size(); ++i) {
+ if (operators.at(i)->name != operators.at(i + 1)->name) {
+ equalOperators = false;
+ break;
+ }
+ }
+ if (not equalOperators) {
+ throw Exception("[exporter error] "
+ "fis files do not support rules with different connectors "
+ "(i.e. ['and', 'or']). All connectors within a rule must be the same", FL_AT);
+ }
+ std::ostringstream fis;
+ std::vector<Variable*> inputVariables, outputVariables;
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i)
+ inputVariables.push_back(engine->getInputVariable(i));
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i)
+ outputVariables.push_back(engine->getOutputVariable(i));
+
+ fis << translate(propositions, inputVariables) << ", ";
+ fis << translate(rule->getConsequent()->conclusions(), outputVariables);
+ fis << "(" << Op::str(rule->getWeight()) << ") : ";
+ if (operators.size() == 0) fis << "1"; //does not matter
+ else {
+ if (operators.at(0)->name == Rule::andKeyword()) fis << "1";
+ else if (operators.at(0)->name == Rule::orKeyword()) fis << "2";
+ else fis << operators.at(0)->name;
+ }
+ return fis.str();
+ }
+
+ std::string FisExporter::translate(const std::vector<Proposition*>& propositions,
+ const std::vector<Variable*> variables) const {
+ std::ostringstream ss;
+ for (std::size_t ixVariable = 0; ixVariable < variables.size(); ++ixVariable) {
+ Variable* variable = variables.at(ixVariable);
+ std::size_t termIndexPlusOne = 0;
+ scalar plusHedge = 0;
+ int negated = 1;
+ for (std::size_t ixProposition = 0; ixProposition < propositions.size(); ++ixProposition) {
+ Proposition* proposition = propositions.at(ixProposition);
+ if (proposition->variable != variable) continue;
+
+ for (std::size_t termIndex = 0; termIndex < variable->numberOfTerms(); ++termIndex) {
+ if (variable->getTerm(termIndex) == proposition->term) {
+ termIndexPlusOne = termIndex + 1;
+ break;
+ }
+ }
+
+ std::vector<Hedge*> hedges = proposition->hedges;
+ if (hedges.size() > 1) {
+ FL_DBG("[exporter warning] only a few combinations of multiple "
+ "hedges are supported in fis files");
+ }
+ for (std::size_t ixHedge = 0; ixHedge < hedges.size(); ++ixHedge) {
+ Hedge* hedge = hedges.at(ixHedge);
+ if (hedge->name() == Not().name()) negated *= -1;
+ else if (hedge->name() == Extremely().name()) plusHedge += 0.3;
+ else if (hedge->name() == Very().name()) plusHedge += 0.2;
+ else if (hedge->name() == Somewhat().name()) plusHedge += 0.05;
+ else if (hedge->name() == Seldom().name()) plusHedge += 0.01;
+ else if (hedge->name() == Any().name()) plusHedge += 0.99;
+ else plusHedge = fl::nan; //Unreconized hedge combination (e.g. Any)
+ }
+
+ break;
+ }
+ if (negated < 0) ss << "-";
+ if (not Op::isNaN(plusHedge)) {
+ ss << Op::str(termIndexPlusOne + plusHedge);
+ } else {
+ ss << termIndexPlusOne << ".?"; // Unreconized hedge combination
+ }
+ ss << " ";
+ }
+ return ss.str();
+ }
+
+ std::string FisExporter::toString(const TNorm * tnorm) const {
+ if (not tnorm) return "";
+ if (tnorm->className() == Minimum().className()) return "min";
+ if (tnorm->className() == AlgebraicProduct().className()) return "prod";
+ if (tnorm->className() == BoundedDifference().className()) return "bounded_difference";
+ if (tnorm->className() == DrasticProduct().className()) return "drastic_product";
+ if (tnorm->className() == EinsteinProduct().className()) return "einstein_product";
+ if (tnorm->className() == HamacherProduct().className()) return "hamacher_product";
+ if (tnorm->className() == NilpotentMinimum().className()) return "nilpotent_minimum";
+ return tnorm->className();
+ }
+
+ std::string FisExporter::toString(const SNorm* snorm) const {
+ if (not snorm) return "";
+ if (snorm->className() == Maximum().className()) return "max";
+ if (snorm->className() == AlgebraicSum().className()) return "probor";
+ if (snorm->className() == BoundedSum().className()) return "bounded_sum";
+ if (snorm->className() == NormalizedSum().className()) return "normalized_sum";
+ if (snorm->className() == DrasticSum().className()) return "drastic_sum";
+ if (snorm->className() == EinsteinSum().className()) return "einstein_sum";
+ if (snorm->className() == HamacherSum().className()) return "hamacher_sum";
+ if (snorm->className() == NilpotentMaximum().className()) return "nilpotent_maximum";
+ if (snorm->className() == UnboundedSum().className()) return "sum";
+ return snorm->className();
+ }
+
+ std::string FisExporter::toString(const Defuzzifier * defuzzifier) const {
+ if (not defuzzifier) return "";
+ if (defuzzifier->className() == Centroid().className()) return "centroid";
+ if (defuzzifier->className() == Bisector().className()) return "bisector";
+ if (defuzzifier->className() == LargestOfMaximum().className()) return "lom";
+ if (defuzzifier->className() == MeanOfMaximum().className()) return "mom";
+ if (defuzzifier->className() == SmallestOfMaximum().className()) return "som";
+ if (defuzzifier->className() == WeightedAverage().className()) return "wtaver";
+ if (defuzzifier->className() == WeightedSum().className()) return "wtsum";
+ return defuzzifier->className();
+ }
+
+ std::string FisExporter::toString(const Term * term) const {
+ std::ostringstream ss;
+ if (const Bell * x = dynamic_cast<const Bell*> (term)) {
+ ss << "'gbellmf',[" << Op::join(3, " ",
+ x->getWidth(), x->getSlope(), x->getCenter()) << "]";
+ return ss.str();
+ }
+
+ if (const Binary * x = dynamic_cast<const Binary*> (term)) {
+ ss << "'binarymf,[" << Op::join(2, " ",
+ x->getStart(), x->getDirection()) << "]";
+ return ss.str();
+ }
+
+ if (const Concave * x = dynamic_cast<const Concave*> (term)) {
+ ss << "'concavemf',[" << Op::join(2, " ",
+ x->getInflection(), x->getEnd()) << "]";
+ return ss.str();
+ }
+
+ if (const Constant * x = dynamic_cast<const Constant*> (term)) {
+ ss << "'constant',[" << Op::str(x->getValue()) << "]";
+ return ss.str();
+ }
+
+ if (const Cosine * x = dynamic_cast<const Cosine*> (term)) {
+ ss << "'cosinemf',[" << Op::join(2, " ",
+ x->getCenter(), x->getWidth()) << "]";
+ return ss.str();
+ }
+
+ if (const Discrete * x = dynamic_cast<const Discrete*> (term)) {
+ ss << "'discretemf',[" << Op::join(Discrete::toVector(x->xy()), " ") << "]";
+ return ss.str();
+ }
+
+ if (const Function * x = dynamic_cast<const Function*> (term)) {
+ ss << "'function',[" << x->getFormula() << "]";
+ return ss.str();
+ }
+
+ if (const Gaussian * x = dynamic_cast<const Gaussian*> (term)) {
+ ss << "'gaussmf',[" << Op::join(2, " ",
+ x->getStandardDeviation(), x->getMean()) << "]";
+ return ss.str();
+ }
+
+ if (const GaussianProduct * x = dynamic_cast<const GaussianProduct*> (term)) {
+ ss << "'gauss2mf',[" << Op::join(4, " ",
+ x->getStandardDeviationA(), x->getMeanA(),
+ x->getStandardDeviationB(), x->getMeanB()) << "]";
+ return ss.str();
+ }
+
+ if (const Linear * x = dynamic_cast<const Linear*> (term)) {
+ ss << "'linear',[" << Op::join<scalar>(x->coefficients(), " ") << "]";
+ return ss.str();
+ }
+
+
+ if (const PiShape * x = dynamic_cast<const PiShape*> (term)) {
+ ss << "'pimf',[" << Op::join(4, " ",
+ x->getBottomLeft(), x->getTopLeft(),
+ x->getTopRight(), x->getBottomRight()) << "]";
+ return ss.str();
+ }
+
+ if (const Ramp * x = dynamic_cast<const Ramp*> (term)) {
+ ss << "'rampmf',[" << Op::join(2, " ",
+ x->getStart(), x->getEnd()) << "]";
+ return ss.str();
+ }
+
+ if (const Rectangle * x = dynamic_cast<const Rectangle*> (term)) {
+ ss << "'rectmf',[" << Op::join(2, " ",
+ x->getStart(), x->getEnd()) << "]";
+ return ss.str();
+ }
+
+ if (const SigmoidDifference * x = dynamic_cast<const SigmoidDifference*> (term)) {
+ ss << "'dsigmf',[" << Op::join(4, " ",
+ x->getRising(), x->getLeft(),
+ x->getFalling(), x->getRight()) << "]";
+ return ss.str();
+ }
+
+ if (const Sigmoid * x = dynamic_cast<const Sigmoid*> (term)) {
+ ss << "'sigmf',[" << Op::join(2, " ",
+ x->getSlope(), x->getInflection()) << "]";
+ return ss.str();
+ }
+
+ if (const SigmoidProduct * x = dynamic_cast<const SigmoidProduct*> (term)) {
+ ss << "'psigmf',[" << Op::join(4, " ",
+ x->getRising(), x->getLeft(),
+ x->getFalling(), x->getRight()) << "]";
+ return ss.str();
+ }
+
+ if (const SShape * x = dynamic_cast<const SShape*> (term)) {
+ ss << "'smf',[" << Op::join(2, " ",
+ x->getStart(), x->getEnd()) << "]";
+ return ss.str();
+ }
+
+ if (const Spike * x = dynamic_cast<const Spike*> (term)) {
+ ss << "'spikemf',[" << Op::join(2, " ",
+ x->getCenter(), x->getWidth()) << "]";
+ return ss.str();
+ }
+
+ if (const Trapezoid * x = dynamic_cast<const Trapezoid*> (term)) {
+ ss << "'trapmf',[" << Op::join(4, " ",
+ x->getVertexA(), x->getVertexB(), x->getVertexC(), x->getVertexD()) << "]";
+ return ss.str();
+ }
+
+ if (const Triangle * x = dynamic_cast<const Triangle*> (term)) {
+ ss << "'trimf',[" << Op::join(3, " ",
+ x->getVertexA(), x->getVertexB(), x->getVertexC()) << "]";
+ return ss.str();
+ }
+
+ if (const ZShape * x = dynamic_cast<const ZShape*> (term)) {
+ ss << "'zmf',[" << Op::join(2, " ",
+ x->getStart(), x->getEnd()) << "]";
+ return ss.str();
+ }
+
+ ss << "[exporter error] term of class <" << (term ? term->className() : "null") << "> not supported";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ FisExporter* FisExporter::clone() const {
+ return new FisExporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/FisImporter.cpp b/fuzzylite/src/imex/FisImporter.cpp
new file mode 100644
index 0000000..f846469
--- /dev/null
+++ b/fuzzylite/src/imex/FisImporter.cpp
@@ -0,0 +1,484 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FisImporter.h"
+
+#include "fl/Headers.h"
+
+namespace fl {
+
+ FisImporter::FisImporter() : Importer() { }
+
+ FisImporter::~FisImporter() { }
+
+ std::string FisImporter::name() const {
+ return "FisImporter";
+ }
+
+ Engine* FisImporter::fromString(const std::string& fis) const {
+ FL_unique_ptr<Engine> engine(new Engine);
+
+ std::istringstream fisReader(fis);
+ std::string line;
+ std::size_t lineNumber = 0;
+
+ std::vector<std::string> sections;
+ while (std::getline(fisReader, line)) {
+ ++lineNumber;
+ //remove comments
+ line = Op::split(line, "//", false).front();
+ line = Op::split(line, "#", false).front();
+ line = Op::trim(line);
+ if (line.empty() or line.at(0) == '%') {
+ continue;
+ }
+
+ line = Op::findReplace(line, "'", "");
+
+ if ("[System]" == line.substr(0, std::string("[System]").size())
+ or "[Input" == line.substr(0, std::string("[Input").size())
+ or "[Output" == line.substr(0, std::string("[Output").size())
+ or "[Rules]" == line.substr(0, std::string("[Rules]").size())) {
+ sections.push_back(line);
+ } else {
+ if (not sections.empty()) {
+ sections.at(sections.size() - 1) += "\n" + line;
+ } else {
+ std::ostringstream ss;
+ ss << "[import error] line " << lineNumber << " <" << line << "> "
+ "does not belong to any section";
+ throw Exception(ss.str(), FL_AT);
+ }
+ }
+ }
+ std::string andMethod, orMethod, impMethod, aggMethod, defuzzMethod;
+ for (std::size_t i = 0; i < sections.size(); ++i) {
+ if ("[System]" == sections.at(i).substr(0, std::string("[System]").size()))
+ importSystem(sections.at(i), engine.get(),
+ andMethod, orMethod, impMethod, aggMethod, defuzzMethod);
+ else if ("[Input" == sections.at(i).substr(0, std::string("[Input").size()))
+ importInput(sections.at(i), engine.get());
+ else if ("[Output" == sections.at(i).substr(0, std::string("[Output").size()))
+ importOutput(sections.at(i), engine.get());
+ else if ("[Rules]" == sections.at(i).substr(0, std::string("[Rules]").size()))
+ importRules(sections.at(i), engine.get());
+ else throw Exception("[import error] section <"
+ + sections.at(i) + "> not recognized", FL_AT);
+ }
+ engine->configure(translateTNorm(andMethod), translateSNorm(orMethod),
+ translateTNorm(impMethod), translateSNorm(aggMethod),
+ translateDefuzzifier(defuzzMethod), General().className());
+ return engine.release();
+ }
+
+ void FisImporter::importSystem(const std::string& section, Engine * engine,
+ std::string& andMethod, std::string& orMethod,
+ std::string& impMethod, std::string& aggMethod,
+ std::string& defuzzMethod) const {
+ std::istringstream reader(section);
+ std::string line;
+ std::getline(reader, line); //ignore first line [System]
+ while (std::getline(reader, line)) {
+ std::vector<std::string> keyValue = Op::split(line, "=");
+
+ std::string key = Op::trim(keyValue.at(0));
+ std::string value;
+ for (std::size_t i = 1; i < keyValue.size(); ++i) {
+ value += keyValue.at(i);
+ }
+ value = Op::trim(value);
+ if (key == "Name") engine->setName(value);
+ else if (key == "AndMethod") andMethod = value;
+ else if (key == "OrMethod") orMethod = value;
+ else if (key == "ImpMethod") impMethod = value;
+ else if (key == "AggMethod") aggMethod = value;
+ else if (key == "DefuzzMethod") defuzzMethod = value;
+ else if (key == "Type" or key == "Version"
+ or key == "NumInputs" or key == "NumOutputs"
+ or key == "NumRules" or key == "NumMFs") {
+ //ignore because are redundant.
+ } else throw Exception("[import error] token <" + key + "> not recognized", FL_AT);
+ }
+ }
+
+ void FisImporter::importInput(const std::string& section, Engine* engine) const {
+ std::istringstream reader(section);
+ std::string line;
+ std::getline(reader, line); //ignore first line [Input#]
+
+ InputVariable* input = new InputVariable;
+ engine->addInputVariable(input);
+
+ while (std::getline(reader, line)) {
+ std::vector<std::string> keyValue = Op::split(line, "=");
+ if (keyValue.size() != 2)
+ throw Exception("[syntax error] expected a property of type "
+ "'key=value', but found <" + line + ">", FL_AT);
+ std::string key = Op::trim(keyValue.at(0));
+ std::string value = Op::trim(keyValue.at(1));
+
+ if (key == "Name") {
+ input->setName(Op::validName(value));
+ } else if (key == "Enabled") {
+ input->setEnabled(Op::isEq(Op::toScalar(value), 1.0));
+ } else if (key == "Range") {
+ std::pair<scalar, scalar> minmax = parseRange(value);
+ input->setMinimum(minmax.first);
+ input->setMaximum(minmax.second);
+ } else if (key.substr(0, 2) == "MF") {
+ input->addTerm(parseTerm(value, engine));
+ } else if (key == "NumMFs") {
+ //ignore
+ } else {
+ throw Exception("[import error] token <" + key + "> not recognized", FL_AT);
+ }
+ }
+ }
+
+ void FisImporter::importOutput(const std::string& section, Engine* engine) const {
+ std::istringstream reader(section);
+ std::string line;
+ std::getline(reader, line); //ignore first line [Output#]
+
+ OutputVariable* output = new OutputVariable;
+ engine->addOutputVariable(output);
+
+
+ while (std::getline(reader, line)) {
+ std::vector<std::string> keyValue = Op::split(line, "=");
+ if (keyValue.size() != 2)
+ throw Exception("[syntax error] expected a property of type "
+ "'key=value', but found < " + line + ">", FL_AT);
+ std::string key = Op::trim(keyValue.at(0));
+ std::string value = Op::trim(keyValue.at(1));
+
+ if (key == "Name") {
+ output->setName(Op::validName(value));
+ } else if (key == "Enabled") {
+ output->setEnabled(Op::isEq(Op::toScalar(value), 1.0));
+ } else if (key == "Range") {
+ std::pair<scalar, scalar> minmax = parseRange(value);
+ output->setMinimum(minmax.first);
+ output->setMaximum(minmax.second);
+ } else if (key.substr(0, 2) == "MF") {
+ output->addTerm(parseTerm(value, engine));
+ } else if (key == "Default") {
+ output->setDefaultValue(Op::toScalar(value));
+ } else if (key == "LockPrevious") {
+ output->setLockPreviousValue(Op::isEq(Op::toScalar(value), 1.0));
+ } else if (key == "LockRange") {
+ output->setLockValueInRange(Op::isEq(Op::toScalar(value), 1.0));
+ } else if (key == "NumMFs") {
+ //ignore
+ } else {
+ throw Exception("[import error] token <" + key + "> not recognized", FL_AT);
+ }
+ }
+ }
+
+ void FisImporter::importRules(const std::string& section, Engine* engine) const {
+ std::istringstream reader(section);
+ std::string line;
+ std::getline(reader, line); //ignore first line [Rules]
+
+ RuleBlock* ruleblock = new RuleBlock;
+ engine->addRuleBlock(ruleblock);
+
+ while (std::getline(reader, line)) {
+ std::vector<std::string> inputsAndRest = Op::split(line, ",");
+ if (inputsAndRest.size() != 2)
+ throw Exception("[syntax error] expected rule to match pattern "
+ "<'i '+, 'o '+ (w) : '1|2'>, but found instead <" + line + ">", FL_AT);
+
+ std::vector <std::string> outputsAndRest = Op::split(inputsAndRest.at(1), ":");
+ if (outputsAndRest.size() != 2)
+ throw Exception("[syntax error] expected rule to match pattern "
+ "<'i '+, 'o '+ (w) : '1|2'>, but found instead <" + line + ">", FL_AT);
+
+ std::vector<std::string> inputs = Op::split(inputsAndRest.at(0), " ");
+ std::vector<std::string> outputs = Op::split(outputsAndRest.at(0), " ");
+ std::string weightInParenthesis = outputs.at(outputs.size() - 1);
+ outputs.erase(outputs.begin() + outputs.size() - 1);
+ std::string connector = Op::trim(outputsAndRest.at(1));
+
+ if (inputs.size() != engine->numberOfInputVariables()) {
+ std::ostringstream ss;
+ ss << "[syntax error] expected <" << engine->numberOfInputVariables() << ">"
+ " input variables, but found <" << inputs.size() << ">"
+ " input variables in rule <" << line << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+ if (outputs.size() != engine->numberOfOutputVariables()) {
+ std::ostringstream ss;
+ ss << "[syntax error] expected <" << engine->numberOfOutputVariables() << ">"
+ " output variables, but found <" << outputs.size() << ">"
+ " output variables in rule <" << line << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ std::vector<std::string> antecedent, consequent;
+
+ for (std::size_t i = 0; i < inputs.size(); ++i) {
+ scalar inputCode = Op::toScalar(inputs.at(i));
+ if (Op::isEq(inputCode, 0.0)) continue;
+ std::ostringstream ss;
+ ss << engine->getInputVariable(i)->getName() << " "
+ << Rule::isKeyword() << " "
+ << translateProposition(inputCode, engine->getInputVariable(i));
+ antecedent.push_back(ss.str());
+ }
+
+ for (std::size_t i = 0; i < outputs.size(); ++i) {
+ scalar outputCode = Op::toScalar(outputs.at(i));
+ if (Op::isEq(outputCode, 0.0)) continue;
+ std::ostringstream ss;
+ ss << engine->getOutputVariable(i)->getName() << " "
+ << Rule::isKeyword() << " "
+ << translateProposition(outputCode, engine->getOutputVariable(i));
+ consequent.push_back(ss.str());
+ }
+
+ std::ostringstream ruleText;
+
+ ruleText << Rule::ifKeyword() << " ";
+ for (std::size_t i = 0; i < antecedent.size(); ++i) {
+ ruleText << antecedent.at(i);
+ if (i + 1 < antecedent.size()) {
+ ruleText << " ";
+ if (connector == "1") ruleText << Rule::andKeyword() << " ";
+ else if (connector == "2") ruleText << Rule::orKeyword() << " ";
+ else throw Exception("[syntax error] connector <"
+ + connector + "> not recognized", FL_AT);
+ }
+ }
+
+ ruleText << " " << Rule::thenKeyword() << " ";
+ for (std::size_t i = 0; i < consequent.size(); ++i) {
+ ruleText << consequent.at(i);
+ if (i + 1 < consequent.size()) {
+ ruleText << " " << Rule::andKeyword() << " ";
+ }
+ }
+
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < weightInParenthesis.size(); ++i) {
+ if (weightInParenthesis.at(i) == '('
+ or weightInParenthesis.at(i) == ')'
+ or weightInParenthesis.at(i) == ' ') continue;
+ ss << weightInParenthesis.at(i);
+ }
+
+ scalar weight = Op::toScalar(ss.str());
+ if (not Op::isEq(weight, 1.0))
+ ruleText << " " << Rule::withKeyword() << " " << Op::str(weight);
+ Rule* rule = new Rule(ruleText.str());
+ try {
+ rule->load(engine);
+ } catch (...) {
+ //ignore
+ }
+ ruleblock->addRule(rule);
+ }
+ }
+
+ std::string FisImporter::translateProposition(scalar code, Variable* variable) const {
+ int intPart = (int) std::floor(std::abs(code)) - 1;
+ scalar fracPart = std::fmod(std::abs(code), scalar(1.0));
+ if (intPart >= static_cast<int> (variable->numberOfTerms())) {
+ std::ostringstream ex;
+ ex << "[syntax error] the code <" << code << "> refers to a term "
+ "out of range from variable <" << variable->getName() << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ bool isAny = intPart < 0;
+ std::ostringstream ss;
+ if (code < 0) ss << Not().name() << " ";
+ if (Op::isEq(fracPart, 0.01)) ss << Seldom().name() << " ";
+ else if (Op::isEq(fracPart, 0.05)) ss << Somewhat().name() << " ";
+ else if (Op::isEq(fracPart, 0.2)) ss << Very().name() << " ";
+ else if (Op::isEq(fracPart, 0.3)) ss << Extremely().name() << " ";
+ else if (Op::isEq(fracPart, 0.4)) ss << Very().name() << " " << Very().name() << " ";
+ else if (Op::isEq(fracPart, 0.99)) ss << Any().name() << " ";
+ else if (not Op::isEq(fracPart, 0.0))
+ throw Exception("[syntax error] no hedge defined in FIS format for <"
+ + Op::str(fracPart) + ">", FL_AT);
+ if (not isAny) {
+ ss << variable->getTerm(intPart)->getName();
+ }
+ return ss.str();
+ }
+
+ std::string FisImporter::translateTNorm(const std::string& name) const {
+ if (name.empty()) return "";
+ if (name == "min") return Minimum().className();
+ if (name == "prod") return AlgebraicProduct().className();
+ if (name == "bounded_difference") return BoundedDifference().className();
+ if (name == "drastic_product") return DrasticProduct().className();
+ if (name == "einstein_product") return EinsteinProduct().className();
+ if (name == "hamacher_product") return HamacherProduct().className();
+ if (name == "nilpotent_minimum") return NilpotentMinimum().className();
+ return name;
+ }
+
+ std::string FisImporter::translateSNorm(const std::string& name) const {
+ if (name.empty()) return "";
+ if (name == "max") return Maximum().className();
+ if (name == "probor") return AlgebraicSum().className();
+ if (name == "bounded_sum") return BoundedSum().className();
+ if (name == "normalized_sum") return NormalizedSum().className();
+ if (name == "drastic_sum") return DrasticSum().className();
+ if (name == "einstein_sum") return EinsteinSum().className();
+ if (name == "hamacher_sum") return HamacherSum().className();
+ if (name == "nilpotent_maximum") return NilpotentMaximum().className();
+ if (name == "sum") return UnboundedSum().className();
+ return name;
+ }
+
+ std::string FisImporter::translateDefuzzifier(const std::string& name) const {
+ if (name.empty()) return "";
+ if (name == "centroid") return Centroid().className();
+ if (name == "bisector") return Bisector().className();
+ if (name == "lom") return LargestOfMaximum().className();
+ if (name == "mom") return MeanOfMaximum().className();
+ if (name == "som") return SmallestOfMaximum().className();
+ if (name == "wtaver") return WeightedAverage().className();
+ if (name == "wtsum") return WeightedSum().className();
+ return name;
+ }
+
+ std::pair<scalar, scalar> FisImporter::parseRange(const std::string& range) const {
+ std::vector<std::string> parts = Op::split(range, " ");
+ if (parts.size() != 2)
+ throw Exception("[syntax error] expected range in format '[begin end]',"
+ " but found <" + range + ">", FL_AT);
+ std::string begin = parts.at(0), end = parts.at(1);
+ if (begin.at(0) != '[' or end.at(end.size() - 1) != ']')
+ throw Exception("[syntax error] expected range in format '[begin end]',"
+ " but found <" + range + ">", FL_AT);
+ std::pair<scalar, scalar> result;
+ result.first = Op::toScalar(begin.substr(1));
+ result.second = Op::toScalar(end.substr(0, end.size() - 1));
+ return result;
+ }
+
+ Term * FisImporter::parseTerm(const std::string& fis, const Engine* engine) const {
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < fis.size(); ++i) {
+ if (not (fis.at(i) == '[' or fis.at(i) == ']')) {
+ ss << fis.at(i);
+ }
+ }
+ std::string line = ss.str();
+
+ std::vector<std::string> nameTerm = Op::split(line, ":");
+ if (nameTerm.size() != 2) {
+ throw Exception("[syntax error] expected term in format 'name':'class',[params], "
+ "but found <" + line + ">", FL_AT);
+ }
+ std::vector<std::string> termParams = Op::split(nameTerm.at(1), ",");
+ if (termParams.size() != 2) {
+ throw Exception("[syntax error] expected term in format 'name':'class',[params], "
+ "but found " + line, FL_AT);
+ }
+
+ std::vector<std::string> parameters = Op::split(termParams.at(1), " ");
+ for (std::size_t i = 0; i < parameters.size(); ++i) {
+ parameters.at(i) = Op::trim(parameters.at(i));
+ }
+ return createInstance(
+ Op::trim(termParams.at(0)),
+ Op::trim(nameTerm.at(0)),
+ parameters, engine);
+ }
+
+ Term* FisImporter::createInstance(const std::string& mClass,
+ const std::string& name, const std::vector<std::string>& params,
+ const Engine* engine) const {
+ std::map<std::string, std::string> mapping;
+ mapping["binarymf"] = Binary().className();
+ mapping["concavemf"] = Concave().className();
+ mapping["constant"] = Constant().className();
+ mapping["cosinemf"] = Cosine().className();
+ mapping["discretemf"] = Discrete().className();
+ mapping["function"] = Function().className();
+ mapping["gbellmf"] = Bell().className();
+ mapping["gaussmf"] = Gaussian().className();
+ mapping["gauss2mf"] = GaussianProduct().className();
+ mapping["linear"] = Linear().className();
+ mapping["pimf"] = PiShape().className();
+ mapping["rampmf"] = Ramp().className();
+ mapping["rectmf"] = Rectangle().className();
+ mapping["smf"] = SShape().className();
+ mapping["sigmf"] = Sigmoid().className();
+ mapping["dsigmf"] = SigmoidDifference().className();
+ mapping["psigmf"] = SigmoidProduct().className();
+ mapping["spikemf"] = Spike().className();
+ mapping["trapmf"] = Trapezoid().className();
+ mapping["trimf"] = Triangle().className();
+ mapping["zmf"] = ZShape().className();
+
+ std::vector<std::string> sortedParams = params;
+
+ if (mClass == "gbellmf" and params.size() >= 3) {
+ sortedParams.at(0) = params.at(2);
+ sortedParams.at(1) = params.at(0);
+ sortedParams.at(2) = params.at(1);
+ } else if (mClass == "gaussmf" and params.size() >= 2) {
+ sortedParams.at(0) = params.at(1);
+ sortedParams.at(1) = params.at(0);
+ } else if (mClass == "gauss2mf" and params.size() >= 4) {
+ sortedParams.at(0) = params.at(1);
+ sortedParams.at(1) = params.at(0);
+ sortedParams.at(2) = params.at(3);
+ sortedParams.at(3) = params.at(2);
+ } else if (mClass == "sigmf" and params.size() >= 2) {
+ sortedParams.at(0) = params.at(1);
+ sortedParams.at(1) = params.at(0);
+ } else if (mClass == "dsigmf" and params.size() >= 4) {
+ sortedParams.at(0) = params.at(1);
+ sortedParams.at(1) = params.at(0);
+ sortedParams.at(2) = params.at(2);
+ sortedParams.at(3) = params.at(3);
+ } else if (mClass == "psigmf" and params.size() >= 4) {
+ sortedParams.at(0) = params.at(1);
+ sortedParams.at(1) = params.at(0);
+ sortedParams.at(2) = params.at(2);
+ sortedParams.at(3) = params.at(3);
+ }
+
+ std::string flClass;
+ std::map<std::string, std::string>::const_iterator it = mapping.find(mClass);
+ if (it != mapping.end()) flClass = it->second;
+ else flClass = mClass;
+
+ FL_unique_ptr<Term> term;
+ term.reset(FactoryManager::instance()->term()->constructObject(flClass));
+ term->updateReference(engine);
+ term->setName(Op::validName(name));
+ std::string separator;
+ if (not dynamic_cast<Function*> (term.get())) {
+ separator = " ";
+ }
+ term->configure(Op::join(sortedParams, separator));
+ return term.release();
+ }
+
+ FisImporter* FisImporter::clone() const {
+ return new FisImporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/FldExporter.cpp b/fuzzylite/src/imex/FldExporter.cpp
new file mode 100644
index 0000000..e25af1b
--- /dev/null
+++ b/fuzzylite/src/imex/FldExporter.cpp
@@ -0,0 +1,312 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FldExporter.h"
+
+#include "fl/Engine.h"
+#include "fl/Operation.h"
+#include "fl/variable/Variable.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#include <fstream>
+
+namespace fl {
+
+ FldExporter::FldExporter(const std::string& separator) : Exporter(),
+ _separator(separator), _exportHeaders(true),
+ _exportInputValues(true), _exportOutputValues(true) { }
+
+ FldExporter::~FldExporter() { }
+
+ std::string FldExporter::name() const {
+ return "FldExporter";
+ }
+
+ void FldExporter::setSeparator(const std::string& separator) {
+ this->_separator = separator;
+ }
+
+ std::string FldExporter::getSeparator() const {
+ return this->_separator;
+ }
+
+ void FldExporter::setExportHeader(bool exportHeaders) {
+ this->_exportHeaders = exportHeaders;
+ }
+
+ bool FldExporter::exportsHeader() const {
+ return this->_exportHeaders;
+ }
+
+ void FldExporter::setExportInputValues(bool exportInputValues) {
+ this->_exportInputValues = exportInputValues;
+ }
+
+ bool FldExporter::exportsInputValues() const {
+ return this->_exportInputValues;
+ }
+
+ void FldExporter::setExportOutputValues(bool exportOutputValues) {
+ this->_exportOutputValues = exportOutputValues;
+ }
+
+ bool FldExporter::exportsOutputValues() const {
+ return this->_exportOutputValues;
+ }
+
+ std::string FldExporter::header(const Engine* engine) const {
+ std::vector<std::string> result;
+ if (_exportInputValues) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ InputVariable* inputVariable = engine->getInputVariable(i);
+ result.push_back(inputVariable->getName());
+ }
+ }
+ if (_exportOutputValues) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ OutputVariable* outputVariable = engine->getOutputVariable(i);
+ result.push_back(outputVariable->getName());
+ }
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FldExporter::toString(const Engine* engine) const {
+ return toString(const_cast<Engine*> (engine), 1024, AllVariables);
+ }
+
+ std::string FldExporter::toString(Engine* engine, int values, ScopeOfValues scope) const {
+ return toString(engine, values, scope, engine->inputVariables());
+ }
+
+ std::string FldExporter::toString(Engine* engine, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
+ std::ostringstream result;
+ write(engine, result, values, scope, activeVariables);
+ return result.str();
+ }
+
+ std::string FldExporter::toString(Engine* engine, std::istream& reader) const {
+ std::ostringstream writer;
+ if (_exportHeaders) writer << header(engine) << "\n";
+ std::string line;
+ int lineNumber = 0;
+ while (std::getline(reader, line)) {
+ ++lineNumber;
+ line = Op::trim(line);
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+
+ write(engine, writer, inputValues, engine->inputVariables());
+ }
+ return writer.str();
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, int values, ScopeOfValues scope) const {
+ toFile(path, engine, values, scope, engine->inputVariables());
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
+ std::ofstream writer(path.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ }
+ write(engine, writer, values, scope, activeVariables);
+ writer.close();
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, std::istream& reader) const {
+ std::ofstream writer(path.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ }
+ if (_exportHeaders) writer << header(engine) << "\n";
+
+ std::string line;
+ int lineNumber = 0;
+ while (std::getline(reader, line)) {
+ ++lineNumber;
+ line = Op::trim(line);
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+
+ write(engine, writer, inputValues, engine->inputVariables());
+ }
+ writer.close();
+ }
+
+ std::vector<scalar> FldExporter::parse(const std::string& values) const {
+ std::vector<scalar> inputValues;
+ if (not (values.empty() or values.at(0) == '#')) {
+ inputValues = Op::toScalars(values);
+ }
+ return inputValues;
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer, int values, ScopeOfValues scope) const {
+ write(engine, writer, values, scope, engine->inputVariables());
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
+ if (_exportHeaders) writer << header(engine) << "\n";
+
+ if (activeVariables.size() != engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[exporter error] number of active variables "
+ "<" << activeVariables.size() << ">"
+ << "must match the number of input variables in the engine "
+ "<" << engine->inputVariables().size() << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ int resolution;
+ if (scope == AllVariables)
+ resolution = -1 + (int) std::max(1.0, std::pow(
+ values, 1.0 / engine->numberOfInputVariables()));
+ else //if (scope == EachVariable)
+ resolution = values - 1;
+
+ std::vector<int> sampleValues, minSampleValues, maxSampleValues;
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ sampleValues.push_back(0);
+ minSampleValues.push_back(0);
+ if (engine->inputVariables().at(i) == activeVariables.at(i))
+ maxSampleValues.push_back(resolution);
+ else maxSampleValues.push_back(0);
+ }
+
+ std::vector<scalar> inputValues(engine->numberOfInputVariables());
+ do {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ InputVariable* inputVariable = engine->getInputVariable(i);
+ if (inputVariable == activeVariables.at(i)) {
+ inputValues.at(i) = inputVariable->getMinimum()
+ + sampleValues.at(i) * inputVariable->range() / std::max(1, resolution);
+ } else {
+ inputValues.at(i) = inputVariable->getValue();
+ }
+ }
+ write(engine, writer, inputValues, activeVariables);
+ } while (Op::increment(sampleValues, minSampleValues, maxSampleValues));
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer, std::istream& reader) const {
+ if (_exportHeaders) writer << header(engine) << "\n";
+
+ std::string line;
+ std::size_t lineNumber = 0;
+ while (std::getline(reader, line)) {
+ ++lineNumber;
+ line = Op::trim(line);
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+ try {
+ write(engine, writer, inputValues, engine->inputVariables());
+ } catch (Exception& ex) {
+ ex.append(" writing line <" + Op::str(lineNumber) + ">");
+ throw;
+ }
+ }
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ const std::vector<scalar>& inputValues) const {
+ write(engine, writer, inputValues, engine->inputVariables());
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ const std::vector<scalar>& inputValues,
+ const std::vector<InputVariable*>& activeVariables) const {
+ if (inputValues.empty()) {
+ writer << "\n";
+ return;
+ }
+ if (inputValues.size() < engine->numberOfInputVariables()) {
+ std::ostringstream ex;
+ ex << "[export error] engine has <" << engine->numberOfInputVariables() << "> "
+ "input variables, but input data provides <" << inputValues.size() << "> values";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (activeVariables.size() != engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[exporter error] number of active variables <" << activeVariables.size() << "> "
+ "must match the number of input variables in the engine <" << engine->inputVariables().size() << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ std::vector<scalar> values;
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ InputVariable* inputVariable = engine->getInputVariable(i);
+ scalar inputValue;
+ if (inputVariable == activeVariables.at(i)) {
+ inputValue = inputValues.at(i);
+ } else {
+ inputValue = inputVariable->getValue();
+ }
+ inputVariable->setValue(inputValue);
+ if (_exportInputValues) values.push_back(inputValue);
+ }
+
+ engine->process();
+
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ OutputVariable* outputVariable = engine->getOutputVariable(i);
+ if (_exportOutputValues)
+ values.push_back(outputVariable->getValue());
+ }
+
+ writer << Op::join(values, _separator) << "\n";
+ }
+
+ FldExporter* FldExporter::clone() const {
+ return new FldExporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/FllExporter.cpp b/fuzzylite/src/imex/FllExporter.cpp
new file mode 100644
index 0000000..6a86152
--- /dev/null
+++ b/fuzzylite/src/imex/FllExporter.cpp
@@ -0,0 +1,210 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FllExporter.h"
+
+#include "fl/Headers.h"
+
+namespace fl {
+
+ FllExporter::FllExporter(const std::string& indent, const std::string& separator)
+ : Exporter(), _indent(indent), _separator(separator) { }
+
+ FllExporter::~FllExporter() { }
+
+ std::string FllExporter::name() const {
+ return "FllExporter";
+ }
+
+ void FllExporter::setIndent(const std::string& indent) {
+ this->_indent = indent;
+ }
+
+ std::string FllExporter::getIndent() const {
+ return this->_indent;
+ }
+
+ void FllExporter::setSeparator(const std::string& separator) {
+ this->_separator = separator;
+ }
+
+ std::string FllExporter::getSeparator() const {
+ return this->_separator;
+ }
+
+ std::string FllExporter::toString(const Engine* engine) const {
+ std::vector<std::string> result;
+ result.push_back("Engine: " + engine->getName());
+ if (not engine->getDescription().empty())
+ result.push_back("description: " + engine->getDescription());
+ for (std::size_t i = 0 ; i < engine->numberOfInputVariables(); ++i){
+ result.push_back(toString(engine->getInputVariable(i)));
+ }
+ for (std::size_t i = 0 ; i < engine->numberOfOutputVariables(); ++i){
+ result.push_back(toString(engine->getOutputVariable(i)));
+ }
+ for (std::size_t i = 0 ; i < engine->numberOfRuleBlocks(); ++i){
+ result.push_back(toString(engine->getRuleBlock(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const std::vector<Variable*>& variables) const {
+ std::vector<std::string> result;
+ for (std::size_t i = 0; i < variables.size(); ++i) {
+ result.push_back(toString(variables.at(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const std::vector<InputVariable*>& variables) const {
+ std::vector<std::string> result;
+ for (std::size_t i = 0; i < variables.size(); ++i) {
+ result.push_back(toString(variables.at(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const std::vector<OutputVariable*>& variables) const {
+ std::vector<std::string> result;
+ for (std::size_t i = 0; i < variables.size(); ++i) {
+ result.push_back(toString(variables.at(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const std::vector<RuleBlock*>& ruleBlocks) const {
+ std::vector<std::string> result;
+ for (std::size_t i = 0; i < ruleBlocks.size(); ++i) {
+ result.push_back(toString(ruleBlocks.at(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const Variable* variable) const {
+ std::vector<std::string> result;
+ result.push_back("Variable: " + Op::validName(variable->getName()));
+ if (not variable->getDescription().empty()) {
+ result.push_back(_indent + "description: " + variable->getDescription());
+ }
+ result.push_back(_indent + "enabled: " + (variable->isEnabled() ? "true" : "false"));
+ result.push_back(_indent + "range: " + Op::join(2, " ",
+ variable->getMinimum(), variable->getMaximum()));
+ result.push_back(_indent + "lock-range: " +
+ (variable->isLockValueInRange() ? "true" : "false"));
+ for (std::size_t i = 0; i < variable->numberOfTerms(); ++i) {
+ result.push_back(_indent + toString(variable->getTerm(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const InputVariable* inputVariable) const {
+ std::vector<std::string> result;
+ result.push_back("InputVariable: " + Op::validName(inputVariable->getName()));
+ if (not inputVariable->getDescription().empty()) {
+ result.push_back(_indent + "description: " + inputVariable->getDescription());
+ }
+ result.push_back(_indent + "enabled: " + (inputVariable->isEnabled() ? "true" : "false"));
+ result.push_back(_indent + "range: " + Op::join(2, " ",
+ inputVariable->getMinimum(), inputVariable->getMaximum()));
+ result.push_back(_indent + "lock-range: " +
+ (inputVariable->isLockValueInRange() ? "true" : "false"));
+ for (std::size_t i = 0; i < inputVariable->numberOfTerms(); ++i) {
+ result.push_back(_indent + toString(inputVariable->getTerm(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const OutputVariable* outputVariable) const {
+ std::vector<std::string> result;
+ result.push_back("OutputVariable: " + Op::validName(outputVariable->getName()));
+ if (not outputVariable->getDescription().empty()) {
+ result.push_back(_indent + "description: " + outputVariable->getDescription());
+ }
+ result.push_back(_indent + "enabled: " + (outputVariable->isEnabled() ? "true" : "false"));
+ result.push_back(_indent + "range: " + Op::join(2, " ",
+ outputVariable->getMinimum(), outputVariable->getMaximum()));
+ result.push_back(_indent + "lock-range: " +
+ (outputVariable->isLockValueInRange() ? "true" : "false"));
+ result.push_back(_indent + "aggregation: " +
+ toString(outputVariable->fuzzyOutput()->getAggregation()));
+ result.push_back(_indent + "defuzzifier: " +
+ toString(outputVariable->getDefuzzifier()));
+ result.push_back(_indent + "default: " + Op::str(outputVariable->getDefaultValue()));
+ result.push_back(_indent + "lock-previous: " +
+ (outputVariable->isLockPreviousValue() ? "true" : "false"));
+ for (std::size_t i = 0; i < outputVariable->numberOfTerms(); ++i) {
+ result.push_back(_indent + toString(outputVariable->getTerm(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const RuleBlock* ruleBlock) const {
+ std::vector<std::string> result;
+ result.push_back("RuleBlock: " + ruleBlock->getName());
+ if (not ruleBlock->getDescription().empty()) {
+ result.push_back(_indent + "description: " + ruleBlock->getDescription());
+ }
+ result.push_back(_indent + "enabled: " +
+ (ruleBlock->isEnabled() ? "true" : "false"));
+ result.push_back(_indent + "conjunction: " + toString(ruleBlock->getConjunction()));
+ result.push_back(_indent + "disjunction: " + toString(ruleBlock->getDisjunction()));
+ result.push_back(_indent + "implication: " + toString(ruleBlock->getImplication()));
+ result.push_back(_indent + "activation: " + toString(ruleBlock->getActivation()));
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ result.push_back(_indent + toString(ruleBlock->getRule(i)));
+ }
+ return Op::join(result, _separator);
+ }
+
+ std::string FllExporter::toString(const Rule* rule) const {
+ return "rule: " + rule->getText();
+ }
+
+ std::string FllExporter::toString(const Term* term) const {
+ return "term: " + Op::validName(term->getName()) + " " + term->className()
+ + " " + term->parameters();
+ }
+
+ std::string FllExporter::toString(const Norm* norm) const {
+ if (norm) return norm->className();
+ return "none";
+ }
+
+ std::string FllExporter::toString(const Activation* activation) const {
+ if (not activation) return "none";
+ if (activation->parameters().empty()) return activation->className();
+ return activation->className() + " " + activation->parameters();
+ }
+
+ std::string FllExporter::toString(const Defuzzifier* defuzzifier) const {
+ if (not defuzzifier) return "none";
+ if (const IntegralDefuzzifier * integralDefuzzifier =
+ dynamic_cast<const IntegralDefuzzifier*> (defuzzifier)) {
+ return defuzzifier->className() + " " + Op::str(integralDefuzzifier->getResolution());
+
+ } else if (const WeightedDefuzzifier * weightedDefuzzifier =
+ dynamic_cast<const WeightedDefuzzifier*> (defuzzifier)) {
+ return weightedDefuzzifier->className() + " " + weightedDefuzzifier->getTypeName();
+ }
+ return defuzzifier->className();
+ }
+
+ FllExporter* FllExporter::clone() const {
+ return new FllExporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/FllImporter.cpp b/fuzzylite/src/imex/FllImporter.cpp
new file mode 100644
index 0000000..ac9d1fc
--- /dev/null
+++ b/fuzzylite/src/imex/FllImporter.cpp
@@ -0,0 +1,316 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/FllImporter.h"
+
+#include "fl/Headers.h"
+
+#include <queue>
+
+namespace fl {
+
+ FllImporter::FllImporter(const std::string& separator) : Importer(),
+ _separator(separator) { }
+
+ FllImporter::~FllImporter() { }
+
+ std::string FllImporter::name() const {
+ return "FllImporter";
+ }
+
+ void FllImporter::setSeparator(const std::string& separator) {
+ this->_separator = separator;
+ }
+
+ std::string FllImporter::getSeparator() const {
+ return this->_separator;
+ }
+
+ Engine* FllImporter::fromString(const std::string& code) const {
+ FL_unique_ptr<Engine> engine(new Engine);
+
+ const std::string fll = Op::join(Op::split(code, _separator), "\n");
+ std::string tag;
+ std::vector<std::string> block;
+ std::istringstream fllReader(fll);
+ std::string line;
+
+ while (std::getline(fllReader, line)) {
+ line = Op::trim(Op::split(line, "#", false).front()); //remove comments
+ if (line.empty()) continue;
+ std::size_t colon = line.find_first_of(':');
+ if (colon == std::string::npos) {
+ throw Exception("[import error] expected a colon here: " + line, FL_AT);
+ }
+ std::string key = Op::trim(line.substr(0, colon));
+ std::string value = Op::trim(line.substr(colon + 1));
+ if ("Engine" == key) {
+ engine->setName(value);
+ continue;
+ } else if (key == "description" and block.empty()){
+ engine->setDescription(value);
+ continue;
+ } else if (key == "InputVariable"
+ or key == "OutputVariable"
+ or key == "RuleBlock") {
+ process(tag, Op::join(block, "\n"), engine.get());
+ block.clear(); //clear error flags
+ tag = key;
+ } else if (tag.empty()) {
+ throw Exception("[import error] unexpected block: " + line, FL_AT);
+ }
+ block.push_back(key + ":" + value);
+ }
+ process(tag, Op::join(block, "\n"), engine.get());
+ return engine.release();
+ }
+
+ void FllImporter::process(const std::string& tag, const std::string& block, Engine* engine) const {
+ if (tag.empty()) return;
+ // FL_LOG("Processing " << tag << "\n" << block);
+ if ("InputVariable" == tag) {
+ processInputVariable(block, engine);
+ } else if ("OutputVariable" == tag) {
+ processOutputVariable(block, engine);
+ } else if ("RuleBlock" == tag) {
+ processRuleBlock(block, engine);
+ } else {
+ throw Exception("[import error] block tag <" + tag + "> not recognized", FL_AT);
+ }
+ }
+
+ void FllImporter::processInputVariable(const std::string& block, Engine* engine) const {
+ std::istringstream reader(block);
+ std::string line;
+ FL_unique_ptr<InputVariable> inputVariable(new InputVariable);
+ while (std::getline(reader, line)) {
+ std::pair<std::string, std::string> keyValue = parseKeyValue(line, ':');
+ if ("InputVariable" == keyValue.first) {
+ inputVariable->setName(Op::validName(keyValue.second));
+ } else if ("description" == keyValue.first) {
+ inputVariable->setDescription(keyValue.second);
+ } else if ("enabled" == keyValue.first) {
+ inputVariable->setEnabled(parseBoolean(keyValue.second));
+ } else if ("range" == keyValue.first) {
+ std::pair<scalar, scalar> range = parseRange(keyValue.second);
+ inputVariable->setRange(range.first, range.second);
+ } else if ("lock-range" == keyValue.first) {
+ inputVariable->setLockValueInRange(parseBoolean(keyValue.second));
+ } else if ("term" == keyValue.first) {
+ inputVariable->addTerm(parseTerm(keyValue.second, engine));
+ } else {
+ throw Exception("[import error] key <" + keyValue.first + "> not "
+ "recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
+ }
+ }
+ engine->addInputVariable(inputVariable.release());
+ }
+
+ void FllImporter::processOutputVariable(const std::string& block, Engine* engine) const {
+ std::istringstream reader(block);
+ std::string line;
+ FL_unique_ptr<OutputVariable> outputVariable(new OutputVariable);
+ while (std::getline(reader, line)) {
+ std::pair<std::string, std::string> keyValue = parseKeyValue(line, ':');
+ if ("OutputVariable" == keyValue.first) {
+ outputVariable->setName(Op::validName(keyValue.second));
+ } else if ("description" == keyValue.first) {
+ outputVariable->setDescription(keyValue.second);
+ } else if ("enabled" == keyValue.first) {
+ outputVariable->setEnabled(parseBoolean(keyValue.second));
+ } else if ("range" == keyValue.first) {
+ std::pair<scalar, scalar> range = parseRange(keyValue.second);
+ outputVariable->setRange(range.first, range.second);
+ } else if ("default" == keyValue.first) {
+ outputVariable->setDefaultValue(Op::toScalar(keyValue.second));
+ } else if ("lock-previous" == keyValue.first or "lock-valid" == keyValue.first) {
+ outputVariable->setLockPreviousValue(parseBoolean(keyValue.second));
+ } else if ("lock-range" == keyValue.first) {
+ outputVariable->setLockValueInRange(parseBoolean(keyValue.second));
+ } else if ("defuzzifier" == keyValue.first) {
+ outputVariable->setDefuzzifier(parseDefuzzifier(keyValue.second));
+ } else if ("aggregation" == keyValue.first) {
+ outputVariable->fuzzyOutput()->setAggregation(parseSNorm(keyValue.second));
+ } else if ("accumulation" == keyValue.first) {
+ outputVariable->fuzzyOutput()->setAggregation(parseSNorm(keyValue.second));
+ FL_LOG("[warning] obsolete usage of identifier <accumulation: SNorm> in OutputVariable");
+ FL_LOG("[information] from version 6.0, the identifier <aggregation: SNorm> should be used");
+ FL_LOG("[backward compatibility] assumed "
+ "<aggregation: " << keyValue.second << "> "
+ "instead of <accumulation: " << keyValue.second << ">");
+ } else if ("term" == keyValue.first) {
+ outputVariable->addTerm(parseTerm(keyValue.second, engine));
+ } else {
+ throw Exception("[import error] key <" + keyValue.first + "> not "
+ "recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
+ }
+ }
+ engine->addOutputVariable(outputVariable.release());
+ }
+
+ void FllImporter::processRuleBlock(const std::string& block, Engine* engine) const {
+ std::istringstream reader(block);
+ std::string line;
+ FL_unique_ptr<RuleBlock> ruleBlock(new RuleBlock);
+ while (std::getline(reader, line)) {
+ std::pair<std::string, std::string> keyValue = parseKeyValue(line, ':');
+ if ("RuleBlock" == keyValue.first) {
+ ruleBlock->setName(keyValue.second);
+ } else if ("description" == keyValue.first) {
+ ruleBlock->setDescription(keyValue.second);
+ } else if ("enabled" == keyValue.first) {
+ ruleBlock->setEnabled(parseBoolean(keyValue.second));
+ } else if ("conjunction" == keyValue.first) {
+ ruleBlock->setConjunction(parseTNorm(keyValue.second));
+ } else if ("disjunction" == keyValue.first) {
+ ruleBlock->setDisjunction(parseSNorm(keyValue.second));
+ } else if ("implication" == keyValue.first) {
+ ruleBlock->setImplication(parseTNorm(keyValue.second));
+ } else if ("activation" == keyValue.first) {
+ TNormFactory* tnorm = FactoryManager::instance()->tnorm();
+ //@todo remove backwards compatibility in version 7.0
+ if (tnorm->hasConstructor(keyValue.second)) {
+ ruleBlock->setImplication(parseTNorm(keyValue.second));
+ FL_LOG("[warning] obsolete usage of identifier <activation: TNorm> "
+ "in RuleBlock");
+ FL_LOG("[information] from version 6.0, the identifiers are "
+ "<activation: Activation> for Activation methods "
+ "and <implication: TNorm> for T-Norms");
+ FL_LOG("[backward compatibility] assumed "
+ "<implication: " << keyValue.second << "> "
+ "instead of <activation: " << keyValue.second << ">");
+ } else {
+ ruleBlock->setActivation(parseActivation(keyValue.second));
+ }
+ } else if ("rule" == keyValue.first) {
+ Rule* rule = new Rule;
+ rule->setText(keyValue.second);
+ try {
+ rule->load(engine);
+ } catch (std::exception& ex) {
+ FL_LOG(ex.what());
+ }
+ ruleBlock->addRule(rule);
+ } else {
+ throw Exception("[import error] key <" + keyValue.first + "> not "
+ "recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
+ }
+ }
+ if (not ruleBlock->getActivation()){
+ ruleBlock->setActivation(new General);
+ }
+ engine->addRuleBlock(ruleBlock.release());
+ }
+
+ Term* FllImporter::parseTerm(const std::string& text, Engine* engine) const {
+ std::vector<std::string> tokens = Op::split(text, " ");
+
+ //MEDIUM Triangle 0.500 1.000 1.500
+
+ if (tokens.size() < 2) {
+ throw Exception("[syntax error] expected a term in format <name class parameters>, "
+ "but found <" + text + ">", FL_AT);
+ }
+ FL_unique_ptr<Term> term;
+ term.reset(FactoryManager::instance()->term()->constructObject(tokens.at(1)));
+ term->updateReference(engine);
+ term->setName(Op::validName(tokens.at(0)));
+ std::ostringstream parameters;
+ for (std::size_t i = 2; i < tokens.size(); ++i) {
+ parameters << tokens.at(i);
+ if (i + 1 < tokens.size()) parameters << " ";
+ }
+ term->configure(parameters.str());
+ return term.release();
+ }
+
+ TNorm* FllImporter::parseTNorm(const std::string& name) const {
+ if (name == "none") return FactoryManager::instance()->tnorm()->constructObject("");
+ return FactoryManager::instance()->tnorm()->constructObject(name);
+ }
+
+ SNorm* FllImporter::parseSNorm(const std::string& name) const {
+ if (name == "none") return FactoryManager::instance()->snorm()->constructObject("");
+ return FactoryManager::instance()->snorm()->constructObject(name);
+ }
+
+ Activation* FllImporter::parseActivation(const std::string& name) const {
+ if (name == "none") return FactoryManager::instance()->activation()->constructObject("");
+ std::vector<std::string> tokens = Op::split(name, " ");
+ Activation* result = FactoryManager::instance()->activation()->constructObject(tokens.front());
+
+ std::ostringstream parameters;
+ for (std::size_t i = 1; i < tokens.size(); ++i) {
+ parameters << tokens.at(i);
+ if (i + 1 < tokens.size()) parameters << " ";
+ }
+ result->configure(parameters.str());
+ return result;
+ }
+
+ Defuzzifier* FllImporter::parseDefuzzifier(const std::string& text) const {
+ std::vector<std::string> parameters = Op::split(text, " ");
+ std::string name = parameters.at(0);
+ if (name == "none") return FactoryManager::instance()->defuzzifier()->constructObject("");
+ Defuzzifier* defuzzifier = FactoryManager::instance()->defuzzifier()->constructObject(name);
+ if (parameters.size() > 1) {
+ std::string parameter(parameters.at(1));
+ if (IntegralDefuzzifier * integralDefuzzifier = dynamic_cast<IntegralDefuzzifier*> (defuzzifier)) {
+ integralDefuzzifier->setResolution((int) Op::toScalar(parameter));
+ } else if (WeightedDefuzzifier * weightedDefuzzifier = dynamic_cast<WeightedDefuzzifier*> (defuzzifier)) {
+ WeightedDefuzzifier::Type type = WeightedDefuzzifier::Automatic;
+ if (parameter == "Automatic") type = WeightedDefuzzifier::Automatic;
+ else if (parameter == "TakagiSugeno") type = WeightedDefuzzifier::TakagiSugeno;
+ else if (parameter == "Tsukamoto") type = WeightedDefuzzifier::Tsukamoto;
+ else throw Exception("[syntax error] unknown parameter of WeightedDefuzzifier <" + parameter + ">", FL_AT);
+ weightedDefuzzifier->setType(type);
+ }
+ }
+ return defuzzifier;
+ }
+
+ std::pair<scalar, scalar> FllImporter::parseRange(const std::string& text) const {
+ std::pair<std::string, std::string> range = parseKeyValue(text, ' ');
+ return std::pair<scalar, scalar>(Op::toScalar(range.first), Op::toScalar(range.second));
+ }
+
+ bool FllImporter::parseBoolean(const std::string& boolean) const {
+ if ("true" == boolean) return true;
+ if ("false" == boolean) return false;
+ throw Exception("[syntax error] expected boolean <true|false>, "
+ "but found <" + boolean + ">", FL_AT);
+ }
+
+ std::pair<std::string, std::string> FllImporter::parseKeyValue(const std::string& text,
+ char separator) const {
+ std::size_t half = text.find_first_of(separator);
+ if (half == std::string::npos) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected pair in the form "
+ "<key" << separator << "value>, but found <" << text << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ std::pair<std::string, std::string> result;
+ result.first = text.substr(0, half);
+ result.second = text.substr(half + 1);
+ return result;
+ }
+
+ FllImporter* FllImporter::clone() const {
+ return new FllImporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/Importer.cpp b/fuzzylite/src/imex/Importer.cpp
new file mode 100644
index 0000000..c0be7f5
--- /dev/null
+++ b/fuzzylite/src/imex/Importer.cpp
@@ -0,0 +1,42 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/Importer.h"
+#include "fl/Exception.h"
+
+#include <fstream>
+
+namespace fl {
+
+ Importer::Importer() { }
+
+ Importer::~Importer() { }
+
+ Engine* Importer::fromFile(const std::string& path) const {
+ std::ifstream reader(path.c_str());
+ if (not reader.is_open()) {
+ throw Exception("[file error] file <" + path + "> could not be opened", FL_AT);
+ }
+ std::ostringstream textEngine;
+ std::string line;
+ while (std::getline(reader, line)) {
+ textEngine << line << std::endl;
+ }
+ reader.close();
+ return fromString(textEngine.str());
+ }
+
+}
diff --git a/fuzzylite/src/imex/JavaExporter.cpp b/fuzzylite/src/imex/JavaExporter.cpp
new file mode 100644
index 0000000..6981dae
--- /dev/null
+++ b/fuzzylite/src/imex/JavaExporter.cpp
@@ -0,0 +1,251 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/JavaExporter.h"
+
+#include "fl/Headers.h"
+
+namespace fl {
+
+ JavaExporter::JavaExporter(bool usingVariableNames) : Exporter(),
+ _usingVariableNames(usingVariableNames) { }
+
+ JavaExporter::~JavaExporter() { }
+
+ std::string JavaExporter::name() const {
+ return "JavaExporter";
+ }
+
+ void JavaExporter::setUsingVariableNames(bool usingVariableNames) {
+ this->_usingVariableNames = usingVariableNames;
+ }
+
+ bool JavaExporter::isUsingVariableNames() const {
+ return this->_usingVariableNames;
+ }
+
+ std::string JavaExporter::toString(const Engine* engine) const {
+ std::ostringstream ss;
+ ss << "//Code automatically generated with " << fuzzylite::library() << ".\n\n";
+ ss << "Engine engine = new Engine();\n";
+ ss << "engine.setName(\"" << engine->getName() << "\");\n";
+ ss << "engine.setDescription(\"" << engine->getDescription() << "\");\n";
+ ss << "\n";
+
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
+ ss << toString(engine->getInputVariable(i), engine) << "\n";
+ }
+
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ ss << toString(engine->getOutputVariable(i), engine) << "\n";
+ }
+
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ ss << toString(engine->getRuleBlock(i), engine) << "\n";
+ }
+
+ return ss.str();
+ }
+
+ std::string JavaExporter::toString(const InputVariable* inputVariable, const Engine* engine) const {
+ std::ostringstream ss;
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(inputVariable->getName());
+ } else {
+ name = "inputVariable";
+ if (engine->numberOfInputVariables() > 1) {
+ std::size_t index = std::distance(engine->inputVariables().begin(),
+ std::find(engine->inputVariables().begin(),
+ engine->inputVariables().end(), inputVariable));
+ name += Op::str(index + 1);
+ }
+ }
+ ss << "InputVariable " << name << " = new InputVariable();\n";
+ ss << name << ".setName(\"" << inputVariable->getName() << "\");\n";
+ ss << name << ".setDescription(\"" << inputVariable->getDescription() << "\");\n";
+ ss << name << ".setEnabled(" << (inputVariable->isEnabled() ? "true" : "false") << ");\n";
+ ss << name << ".setRange("
+ << toString(inputVariable->getMinimum()) << ", "
+ << toString(inputVariable->getMaximum()) << ");\n";
+ ss << name << ".setLockValueInRange("
+ << (inputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ for (std::size_t i = 0; i < inputVariable->numberOfTerms(); ++i) {
+ ss << name << ".addTerm(" <<
+ toString(inputVariable->getTerm(i)) << ");\n";
+ }
+ ss << "engine.addInputVariable(" << name << ");\n";
+ return ss.str();
+ }
+
+ std::string JavaExporter::toString(const OutputVariable* outputVariable, const Engine* engine) const {
+ std::ostringstream ss;
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(outputVariable->getName());
+ } else {
+ name = "outputVariable";
+ if (engine->numberOfOutputVariables() > 1) {
+ std::size_t index = std::distance(engine->outputVariables().begin(),
+ std::find(engine->outputVariables().begin(),
+ engine->outputVariables().end(), outputVariable));
+ name += Op::str(index + 1);
+ }
+ }
+ ss << "OutputVariable " << name << " = new OutputVariable();\n";
+ ss << name << ".setName(\"" << outputVariable->getName() << "\");\n";
+ ss << name << ".setDescription(\"" << outputVariable->getDescription() << "\");\n";
+ ss << name << ".setEnabled(" << (outputVariable->isEnabled() ? "true" : "false") << ");\n";
+ ss << name << ".setRange("
+ << toString(outputVariable->getMinimum()) << ", "
+ << toString(outputVariable->getMaximum()) << ");\n";
+ ss << name << ".setLockValueInRange(" <<
+ (outputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ ss << name << ".setAggregation(" <<
+ toString(outputVariable->fuzzyOutput()->getAggregation()) << ");\n";
+ ss << name << ".setDefuzzifier(" <<
+ toString(outputVariable->getDefuzzifier()) << ");\n";
+ ss << name << ".setDefaultValue(" <<
+ toString(outputVariable->getDefaultValue()) << ");\n";
+ ss << name << ".setLockPreviousValue(" <<
+ (outputVariable->isLockPreviousValue() ? "true" : "false") << ");\n";
+ for (std::size_t i = 0; i < outputVariable->numberOfTerms(); ++i) {
+ ss << name << ".addTerm(" <<
+ toString(outputVariable->getTerm(i)) << ");\n";
+ }
+ ss << "engine.addOutputVariable(" << name << ");\n";
+ return ss.str();
+ }
+
+ std::string JavaExporter::toString(const RuleBlock* ruleBlock, const Engine* engine) const {
+ std::ostringstream ss;
+ std::string name;
+
+ if (isUsingVariableNames() and not ruleBlock->getName().empty()) {
+ name = Op::validName(ruleBlock->getName());
+ } else {
+ name = "ruleBlock";
+ if (engine->numberOfRuleBlocks() > 1) {
+ std::size_t index = std::distance(engine->ruleBlocks().begin(),
+ std::find(engine->ruleBlocks().begin(),
+ engine->ruleBlocks().end(), ruleBlock));
+ name += Op::str(index + 1);
+ }
+ }
+
+ ss << "RuleBlock " << name << " = new RuleBlock();\n";
+ ss << name << ".setName(\"" << ruleBlock->getName() << "\");\n";
+ ss << name << ".setDescription(\"" << ruleBlock->getDescription() << "\");\n";
+ ss << name << ".setEnabled(" << (ruleBlock->isEnabled() ? "true" : "false") << ");\n";
+ ss << name << ".setConjunction("
+ << toString(ruleBlock->getConjunction()) << ");\n";
+ ss << name << ".setDisjunction("
+ << toString(ruleBlock->getDisjunction()) << ");\n";
+ ss << name << ".setImplication("
+ << toString(ruleBlock->getImplication()) << ");\n";
+ ss << name << ".setActivation("
+ << toString(ruleBlock->getActivation()) << ");\n";
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ Rule* rule = ruleBlock->getRule(i);
+ ss << name << ".addRule(Rule.parse(\"" << rule->getText() << "\", engine));\n";
+ }
+ ss << "engine.addRuleBlock(" << name << ");\n";
+ return ss.str();
+ }
+
+ std::string JavaExporter::toString(const Term* term) const {
+ if (not term) {
+ return "null";
+ }
+
+ if (const Discrete * discrete = dynamic_cast<const Discrete*> (term)) {
+ std::ostringstream ss;
+ std::vector<scalar> xy;
+ ss << term->className() << ".create(\"" << term->getName() << "\", "
+ << Op::join(Discrete::toVector(discrete->xy()), ", ") << ")";
+ return ss.str();
+ }
+
+ if (const Function * function = dynamic_cast<const Function*> (term)) {
+ std::ostringstream ss;
+ ss << term->className() << ".create(\"" << term->getName() << "\", "
+ << "\"" << function->getFormula() << "\", engine)";
+ return ss.str();
+ }
+
+ if (const Linear * linear = dynamic_cast<const Linear*> (term)) {
+ std::ostringstream ss;
+ ss << term->className() << ".create(\"" << term->getName() << "\", "
+ << "engine, " << Op::join(linear->coefficients(), ", ") << ")";
+ return ss.str();
+ }
+
+ std::ostringstream ss;
+ ss << "new " << term->className() << "(\"" << term->getName() << "\", "
+ << Op::findReplace(term->parameters(), " ", ", ") << ")";
+ return ss.str();
+ }
+
+ std::string JavaExporter::toString(const Defuzzifier* defuzzifier) const {
+ if (not defuzzifier) return "null";
+
+ if (const IntegralDefuzzifier * integralDefuzzifier =
+ dynamic_cast<const IntegralDefuzzifier*> (defuzzifier)) {
+ return "new " + integralDefuzzifier->className() + "("
+ + Op::str(integralDefuzzifier->getResolution()) + ")";
+ }
+ if (const WeightedDefuzzifier * weightedDefuzzifier =
+ dynamic_cast<const WeightedDefuzzifier*> (defuzzifier)) {
+ return "new " + weightedDefuzzifier->className() +
+ "(\"" + weightedDefuzzifier->getTypeName() + "\")";
+ }
+ return "new " + defuzzifier->className() + "()";
+ }
+
+ std::string JavaExporter::toString(const Norm* norm) const {
+ if (not norm) return "null";
+ return "new " + norm->className() + "()";
+ }
+
+ std::string JavaExporter::toString(const Activation* activation) const {
+ if (not activation) return "null";
+ std::string parameters = Op::trim(activation->parameters());
+ if (parameters.empty()) return "new " + activation->className() + "()";
+
+ std::vector<std::string> values = Op::split(parameters, " ");
+ for (std::size_t i = 0; i < values.size(); ++i) {
+ std::string parameter = values.at(i);
+ values.at(i) = (Op::isNumeric(parameter) ? parameter : ("\"" + parameter + "\""));
+ }
+ return "new " + activation->className() + "(" + Op::join(values, ", ") + ")";
+ }
+
+ std::string JavaExporter::toString(scalar value) const {
+ if (Op::isNaN(value)) {
+ return "Double.NaN";
+ } else if (Op::isInf(value)) {
+ return (value > 0
+ ? "Double.POSITIVE_INFINITY"
+ : "Double.NEGATIVE_INFINITY");
+ }
+ return Op::str(value);
+ }
+
+ JavaExporter* JavaExporter::clone() const {
+ return new JavaExporter(*this);
+ }
+
+}
diff --git a/fuzzylite/src/imex/RScriptExporter.cpp b/fuzzylite/src/imex/RScriptExporter.cpp
new file mode 100644
index 0000000..5fe53c7
--- /dev/null
+++ b/fuzzylite/src/imex/RScriptExporter.cpp
@@ -0,0 +1,234 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/imex/RScriptExporter.h"
+
+#include "fl/Engine.h"
+#include "fl/imex/FllExporter.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#include <fstream>
+namespace fl {
+
+ RScriptExporter::RScriptExporter() : Exporter(),
+ _minimumColor("yellow"), _maximumColor("red"), _contourColor("black") { }
+
+ RScriptExporter::~RScriptExporter() { }
+
+ std::string RScriptExporter::name() const {
+ return "RScriptExporter";
+ }
+
+ void RScriptExporter::setMinimumColor(const std::string& minimumColor) {
+ this->_minimumColor = minimumColor;
+ }
+
+ std::string RScriptExporter::getMinimumColor() const {
+ return this->_minimumColor;
+ }
+
+ void RScriptExporter::setMaximumColor(const std::string& maximumColor) {
+ this->_maximumColor = maximumColor;
+ }
+
+ std::string RScriptExporter::getMaximumColor() const {
+ return _maximumColor;
+ }
+
+ void RScriptExporter::setContourColor(const std::string& contourColor) {
+ this->_contourColor = contourColor;
+ }
+
+ std::string RScriptExporter::getContourColor() const {
+ return this->_contourColor;
+ }
+
+ RScriptExporter* RScriptExporter::clone() const {
+ return new RScriptExporter(*this);
+ }
+
+ std::string RScriptExporter::toString(const Engine* engine) const {
+ if (engine->inputVariables().empty()) {
+ throw Exception("[exporter error] engine has no input variables to export the surface", FL_AT);
+ }
+ if (engine->outputVariables().empty()) {
+ throw Exception("[exporter error] engine has no output variables to export the surface", FL_AT);
+ }
+ InputVariable* a = engine->inputVariables().at(0);
+ InputVariable* b = engine->inputVariables().at(1 % engine->numberOfInputVariables());
+ return toString(const_cast<Engine*> (engine), a, b,
+ 1024, FldExporter::AllVariables, engine->outputVariables());
+ }
+
+ std::string RScriptExporter::toString(Engine* engine, InputVariable* a, InputVariable* b,
+ int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ostringstream writer;
+ writeScriptExportingDataFrame(engine, writer, a, b, values, scope, outputVariables);
+ return writer.str();
+ }
+
+ std::string RScriptExporter::toString(Engine* engine, InputVariable* a, InputVariable* b,
+ std::istream& reader, const std::vector<OutputVariable*>& outputVariables) const {
+ std::ostringstream writer;
+ writeScriptExportingDataFrame(engine, writer, a, b, reader, outputVariables);
+ return writer.str();
+ }
+
+ void RScriptExporter::toFile(const std::string& filePath, const Engine* engine) const {
+ if (engine->inputVariables().empty()) {
+ throw Exception("[exporter error] engine has no input variables to export the surface", FL_AT);
+ }
+ if (engine->outputVariables().empty()) {
+ throw Exception("[exporter error] engine has no output variables to export the surface", FL_AT);
+ }
+ InputVariable* a = engine->inputVariables().at(0);
+ InputVariable* b = engine->inputVariables().at(1 % engine->numberOfInputVariables());
+
+ toFile(filePath, const_cast<Engine*> (engine), a, b,
+ 1024, FldExporter::AllVariables, engine->outputVariables());
+ }
+
+ void RScriptExporter::toFile(const std::string& filePath, Engine* engine,
+ InputVariable* a, InputVariable* b, int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ofstream writer(filePath.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + filePath + "> could not be created", FL_AT);
+ }
+ writeScriptExportingDataFrame(engine, writer, a, b, values, scope, outputVariables);
+ writer.close();
+ }
+
+ void RScriptExporter::toFile(const std::string& filePath, Engine* engine,
+ InputVariable* a, InputVariable* b, std::istream& reader,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ofstream writer(filePath.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + filePath + "> could not be created", FL_AT);
+ }
+ writeScriptExportingDataFrame(engine, writer, a, b, reader, outputVariables);
+ writer.close();
+ }
+
+ void RScriptExporter::writeScriptImportingDataFrame(const Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, const std::string& dfPath,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ writeScriptHeader(writer, engine);
+
+ writer << "engine.fldFile = \"" << dfPath << "\"\n";
+ writer << "if (require(data.table)) {\n"
+ << " engine.df = data.table::fread(engine.fldFile, sep=\"auto\", header=\"auto\")\n"
+ << "} else {\n"
+ << " engine.df = read.table(engine.fldFile, header=TRUE)\n"
+ << "}\n";
+ writer << "\n";
+
+ writeScriptPlots(writer, a, b, outputVariables);
+ }
+
+ void RScriptExporter::writeScriptExportingDataFrame(Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ writeScriptHeader(writer, engine);
+
+ std::vector<InputVariable*> activeVariables = engine->inputVariables();
+ for (std::size_t i = 0; i < activeVariables.size(); ++i) {
+ if (activeVariables.at(i) != a and activeVariables.at(i) != b) {
+ activeVariables.at(i) = fl::null;
+ }
+ }
+ writer << "engine.fld = \"";
+ FldExporter().write(engine, writer, values, scope, activeVariables);
+ writer << "\"\n\n";
+ writer << "engine.df = read.delim(textConnection(engine.fld), header=TRUE, "
+ "sep=\" \", strip.white=TRUE)\n\n";
+
+ writeScriptPlots(writer, a, b, outputVariables);
+ }
+
+ void RScriptExporter::writeScriptExportingDataFrame(Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, std::istream& reader,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ writeScriptHeader(writer, engine);
+
+ writer << "engine.fld = \"";
+ FldExporter().write(engine, writer, reader);
+ writer << "\"\n\n";
+
+ writer << "engine.df = read.delim(textConnection(engine.fld), header=TRUE, "
+ "sep=\" \", strip.white=TRUE)\n\n";
+
+ writeScriptPlots(writer, a, b, outputVariables);
+ }
+
+ void RScriptExporter::writeScriptHeader(std::ostream& writer, const Engine* engine) const {
+ writer << "#Code automatically generated with " << fuzzylite::library() << ".\n\n"
+ << "library(ggplot2);\n"
+ << "\n";
+ writer << "engine.name = \"" << engine->getName() << "\"\n";
+ if (not engine->getDescription().empty())
+ writer << "engine.description = \"" << engine->getDescription() << "\"\n";
+ writer << "engine.fll = \"" << FllExporter().toString(engine) << "\"\n\n";
+ }
+
+ void RScriptExporter::writeScriptPlots(std::ostream& writer,
+ InputVariable* a, InputVariable* b,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ostringstream arrangeGrob;
+ arrangeGrob << "arrangeGrob(";
+ for (std::size_t i = 0; i < outputVariables.size(); ++i) {
+ OutputVariable* z = outputVariables.at(i);
+ if (a != b) {
+ writer << "engine.plot.i1i2_o" << (i + 1) << " = ggplot(engine.df, aes(" << a->getName() << ", " << b->getName() << ")) + \n"
+ << " geom_tile(aes(fill=" << z->getName() << ")) + \n"
+ << " scale_fill_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " stat_contour(aes(x=" << a->getName() << ", y=" << b->getName() << ", z=" << z->getName() << "), color=\"" << _contourColor << "\") + \n"
+ << " ggtitle(\"(" << a->getName() << ", " << b->getName() << ") = " << z->getName() << "\")\n\n";
+
+ writer << "engine.plot.i2i1_o" << (i + 1) << " = ggplot(engine.df, aes(" << b->getName() << ", " << a->getName() << ")) + \n"
+ << " geom_tile(aes(fill=" << z->getName() << ")) + \n"
+ << " scale_fill_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " stat_contour(aes(x=" << b->getName() << ", y=" << a->getName() << ", z=" << z->getName() << "), color=\"" << _contourColor << "\") + \n"
+ << " ggtitle(\"(" << b->getName() << ", " << a->getName() << ") = " << z->getName() << "\")\n\n";
+ arrangeGrob << "engine.plot.i1i2_o" << (i + 1) << ", " << "engine.plot.i2i1_o" << (i + 1) << ", ";
+ } else {
+ writer << "engine.plot.i1_o" << (i + 1) << " = ggplot(engine.df, aes(" << a->getName() << ", " << z->getName() << ")) + \n"
+ << " geom_line(aes(color=" << z->getName() << "), size=3, lineend=\"round\", linejoin=\"mitre\") + \n"
+ << " scale_color_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " ggtitle(\"" << a->getName() << " vs " << z->getName() << "\")\n\n";
+
+ writer << "engine.plot.o" << (i + 1) << "_i1 = ggplot(engine.df, aes(" << a->getName() << ", " << z->getName() << ")) + \n"
+ << " geom_line(aes(color=" << z->getName() << "), size=3, lineend=\"round\", linejoin=\"mitre\") + \n"
+ << " scale_color_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " coord_flip() + \n"
+ << " ggtitle(\"" << z->getName() << " vs " << a->getName() << "\")\n\n";
+ arrangeGrob << "engine.plot.i1_o" << (i + 1) << ", " << "engine.plot.o" << (i + 1) << "_i1, ";
+ }
+
+ }
+ arrangeGrob << "ncol=2, top=engine.name)";
+ writer << "if (require(gridExtra)) {\n"
+ << " engine.plots = " << arrangeGrob.str() << "\n"
+ << " ggsave(paste0(engine.name, \".pdf\"), engine.plots)\n"
+ << " if (require(grid)) {\n"
+ << " grid.newpage()\n"
+ << " grid.draw(engine.plots)\n"
+ << " }\n"
+ << "}\n";
+ }
+}
diff --git a/fuzzylite/src/main.cpp b/fuzzylite/src/main.cpp
new file mode 100644
index 0000000..06ca139
--- /dev/null
+++ b/fuzzylite/src/main.cpp
@@ -0,0 +1,50 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Headers.h"
+
+#include <fstream>
+#include <csignal>
+
+int main(int argc, const char* argv[]) {
+ std::set_terminate(fl::Exception::terminate);
+ std::set_unexpected(fl::Exception::terminate);
+ ::signal(SIGSEGV, fl::Exception::signalHandler);
+ ::signal(SIGABRT, fl::Exception::signalHandler);
+ ::signal(SIGILL, fl::Exception::signalHandler);
+ ::signal(SIGSEGV, fl::Exception::signalHandler);
+ ::signal(SIGFPE, fl::Exception::signalHandler);
+#ifdef FL_UNIX
+ ::signal(SIGBUS, fl::Exception::signalHandler);
+ ::signal(SIGPIPE, fl::Exception::signalHandler);
+#endif
+#ifdef FL_WINDOWS
+ //SetConsoleCtrlHandler(flSignalHandler, TRUE);
+#endif
+ fl::fuzzylite::setDebugging(false);
+
+ try {
+ fl::Console::main(argc, argv);
+ } catch (std::exception& ex) {
+ std::cout << ex.what() << "\nBACKTRACE:\n" <<
+ fl::Exception::btCallStack() << std::endl;
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+
+
diff --git a/fuzzylite/src/norm/s/AlgebraicSum.cpp b/fuzzylite/src/norm/s/AlgebraicSum.cpp
new file mode 100644
index 0000000..0497f23
--- /dev/null
+++ b/fuzzylite/src/norm/s/AlgebraicSum.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/AlgebraicSum.h"
+
+namespace fl {
+
+ std::string AlgebraicSum::className() const {
+ return "AlgebraicSum";
+ }
+
+ Complexity AlgebraicSum::complexity() const {
+ return Complexity().arithmetic(3);
+ }
+
+ scalar AlgebraicSum::compute(scalar a, scalar b) const {
+ return a + b - (a * b);
+ }
+
+ AlgebraicSum* AlgebraicSum::clone() const {
+ return new AlgebraicSum(*this);
+ }
+
+ SNorm* AlgebraicSum::constructor() {
+ return new AlgebraicSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/BoundedSum.cpp b/fuzzylite/src/norm/s/BoundedSum.cpp
new file mode 100644
index 0000000..b1cb42b
--- /dev/null
+++ b/fuzzylite/src/norm/s/BoundedSum.cpp
@@ -0,0 +1,43 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/BoundedSum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string BoundedSum::className() const {
+ return "BoundedSum";
+ }
+
+ Complexity BoundedSum::complexity() const {
+ return Complexity().arithmetic(1).function(1);
+ }
+
+ scalar BoundedSum::compute(scalar a, scalar b) const {
+ return Op::min(scalar(1.0), a + b);
+ }
+
+ BoundedSum* BoundedSum::clone() const {
+ return new BoundedSum(*this);
+ }
+
+ SNorm* BoundedSum::constructor() {
+ return new BoundedSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/DrasticSum.cpp b/fuzzylite/src/norm/s/DrasticSum.cpp
new file mode 100644
index 0000000..b0d9f1e
--- /dev/null
+++ b/fuzzylite/src/norm/s/DrasticSum.cpp
@@ -0,0 +1,46 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/DrasticSum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string DrasticSum::className() const {
+ return "DrasticSum";
+ }
+
+ Complexity DrasticSum::complexity() const {
+ return Complexity().comparison(1).function(2);
+ }
+
+ scalar DrasticSum::compute(scalar a, scalar b) const {
+ if (Op::isEq(Op::min(a, b), 0.0)) {
+ return Op::max(a, b);
+ }
+ return 1.0;
+ }
+
+ DrasticSum* DrasticSum::clone() const {
+ return new DrasticSum(*this);
+ }
+
+ SNorm* DrasticSum::constructor() {
+ return new DrasticSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/EinsteinSum.cpp b/fuzzylite/src/norm/s/EinsteinSum.cpp
new file mode 100644
index 0000000..a638c7b
--- /dev/null
+++ b/fuzzylite/src/norm/s/EinsteinSum.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/EinsteinSum.h"
+
+namespace fl {
+
+ std::string EinsteinSum::className() const {
+ return "EinsteinSum";
+ }
+
+ Complexity EinsteinSum::complexity() const {
+ return Complexity().arithmetic(4);
+ }
+
+ scalar EinsteinSum::compute(scalar a, scalar b) const {
+ return (a + b) / (1.0 + a * b);
+ }
+
+ EinsteinSum* EinsteinSum::clone() const {
+ return new EinsteinSum(*this);
+ }
+
+ SNorm* EinsteinSum::constructor() {
+ return new EinsteinSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/HamacherSum.cpp b/fuzzylite/src/norm/s/HamacherSum.cpp
new file mode 100644
index 0000000..41242ee
--- /dev/null
+++ b/fuzzylite/src/norm/s/HamacherSum.cpp
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/HamacherSum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string HamacherSum::className() const {
+ return "HamacherSum";
+ }
+
+ Complexity HamacherSum::complexity() const {
+ return Complexity().arithmetic(7);
+ }
+
+ scalar HamacherSum::compute(scalar a, scalar b) const {
+ if (Op::isEq(a * b, 1.0)) return 1.0;
+ return (a + b - 2.0 * a * b) / (1.0 - a * b);
+ }
+
+ HamacherSum* HamacherSum::clone() const {
+ return new HamacherSum(*this);
+ }
+
+ SNorm* HamacherSum::constructor() {
+ return new HamacherSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/Maximum.cpp b/fuzzylite/src/norm/s/Maximum.cpp
new file mode 100644
index 0000000..5277d49
--- /dev/null
+++ b/fuzzylite/src/norm/s/Maximum.cpp
@@ -0,0 +1,43 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/Maximum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string Maximum::className() const {
+ return "Maximum";
+ }
+
+ Complexity Maximum::complexity() const {
+ return Complexity().function(1);
+ }
+
+ scalar Maximum::compute(scalar a, scalar b) const {
+ return Op::max(a, b);
+ }
+
+ Maximum* Maximum::clone() const {
+ return new Maximum(*this);
+ }
+
+ SNorm* Maximum::constructor() {
+ return new Maximum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/NilpotentMaximum.cpp b/fuzzylite/src/norm/s/NilpotentMaximum.cpp
new file mode 100644
index 0000000..7c63999
--- /dev/null
+++ b/fuzzylite/src/norm/s/NilpotentMaximum.cpp
@@ -0,0 +1,46 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/NilpotentMaximum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string NilpotentMaximum::className() const {
+ return "NilpotentMaximum";
+ }
+
+ Complexity NilpotentMaximum::complexity() const {
+ return Complexity().comparison(1).arithmetic(1).function(1);
+ }
+
+ scalar NilpotentMaximum::compute(scalar a, scalar b) const {
+ if (Op::isLt(a + b, 1.0)) {
+ return Op::max(a, b);
+ }
+ return 1.0;
+ }
+
+ NilpotentMaximum* NilpotentMaximum::clone() const {
+ return new NilpotentMaximum(*this);
+ }
+
+ SNorm* NilpotentMaximum::constructor() {
+ return new NilpotentMaximum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/NormalizedSum.cpp b/fuzzylite/src/norm/s/NormalizedSum.cpp
new file mode 100644
index 0000000..c420ed1
--- /dev/null
+++ b/fuzzylite/src/norm/s/NormalizedSum.cpp
@@ -0,0 +1,43 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/NormalizedSum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string NormalizedSum::className() const {
+ return "NormalizedSum";
+ }
+
+ Complexity NormalizedSum::complexity() const {
+ return Complexity().arithmetic(3).function(1);
+ }
+
+ scalar NormalizedSum::compute(scalar a, scalar b) const {
+ return (a + b) / Op::max(scalar(1.0), a + b);
+ }
+
+ NormalizedSum* NormalizedSum::clone() const {
+ return new NormalizedSum(*this);
+ }
+
+ SNorm* NormalizedSum::constructor() {
+ return new NormalizedSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/SNormFunction.cpp b/fuzzylite/src/norm/s/SNormFunction.cpp
new file mode 100644
index 0000000..f8d9e42
--- /dev/null
+++ b/fuzzylite/src/norm/s/SNormFunction.cpp
@@ -0,0 +1,65 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/SNormFunction.h"
+
+namespace fl {
+
+ SNormFunction::SNormFunction(const std::string& formula) : SNorm() {
+ _function.variables["a"] = fl::nan;
+ _function.variables["b"] = fl::nan;
+ if (not formula.empty()) {
+ _function.load(formula);
+ }
+ }
+
+ std::string SNormFunction::className() const {
+ return "SNormFunction";
+ }
+
+ Complexity SNormFunction::complexity() const {
+ if (_function.root())
+ return _function.complexity().function(2 * std::log(scalar(_function.variables.size())));
+ return _function.complexity();
+ }
+
+ scalar SNormFunction::compute(scalar a, scalar b) const {
+ _function.variables["a"] = a;
+ _function.variables["b"] = b;
+ return _function.evaluate();
+ }
+
+ Function& SNormFunction::function() {
+ return this->_function;
+ }
+
+ void SNormFunction::setFormula(const std::string& formula) {
+ this->_function.load(formula);
+ }
+
+ std::string SNormFunction::getFormula() const {
+ return _function.getFormula();
+ }
+
+ SNormFunction* SNormFunction::clone() const {
+ return new SNormFunction(*this);
+ }
+
+ SNorm* SNormFunction::constructor() {
+ return new SNormFunction;
+ }
+
+}
diff --git a/fuzzylite/src/norm/s/UnboundedSum.cpp b/fuzzylite/src/norm/s/UnboundedSum.cpp
new file mode 100644
index 0000000..adee6ad
--- /dev/null
+++ b/fuzzylite/src/norm/s/UnboundedSum.cpp
@@ -0,0 +1,43 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/s/UnboundedSum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string UnboundedSum::className() const {
+ return "UnboundedSum";
+ }
+
+ Complexity UnboundedSum::complexity() const {
+ return Complexity().arithmetic(1);
+ }
+
+ scalar UnboundedSum::compute(scalar a, scalar b) const {
+ return a + b;
+ }
+
+ UnboundedSum* UnboundedSum::clone() const {
+ return new UnboundedSum(*this);
+ }
+
+ SNorm* UnboundedSum::constructor() {
+ return new UnboundedSum;
+ }
+
+}
diff --git a/fuzzylite/src/norm/t/AlgebraicProduct.cpp b/fuzzylite/src/norm/t/AlgebraicProduct.cpp
new file mode 100644
index 0000000..eefe309
--- /dev/null
+++ b/fuzzylite/src/norm/t/AlgebraicProduct.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/AlgebraicProduct.h"
+
+namespace fl {
+
+ std::string AlgebraicProduct::className() const {
+ return "AlgebraicProduct";
+ }
+
+ Complexity AlgebraicProduct::complexity() const {
+ return Complexity().arithmetic(1);
+ }
+
+ scalar AlgebraicProduct::compute(scalar a, scalar b) const {
+ return a * b;
+ }
+
+ AlgebraicProduct* AlgebraicProduct::clone() const {
+ return new AlgebraicProduct(*this);
+ }
+
+ TNorm* AlgebraicProduct::constructor() {
+ return new AlgebraicProduct;
+ }
+
+}
diff --git a/fuzzylite/src/norm/t/BoundedDifference.cpp b/fuzzylite/src/norm/t/BoundedDifference.cpp
new file mode 100644
index 0000000..3775aa4
--- /dev/null
+++ b/fuzzylite/src/norm/t/BoundedDifference.cpp
@@ -0,0 +1,43 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/BoundedDifference.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string BoundedDifference::className() const {
+ return "BoundedDifference";
+ }
+
+ Complexity BoundedDifference::complexity() const {
+ return Complexity().arithmetic(2).function(1);
+ }
+
+ scalar BoundedDifference::compute(scalar a, scalar b) const {
+ return Op::max(scalar(0.0), a + b - scalar(1.0));
+ }
+
+ BoundedDifference* BoundedDifference::clone() const {
+ return new BoundedDifference(*this);
+ }
+
+ TNorm* BoundedDifference::constructor() {
+ return new BoundedDifference;
+ }
+
+}
diff --git a/fuzzylite/src/norm/t/DrasticProduct.cpp b/fuzzylite/src/norm/t/DrasticProduct.cpp
new file mode 100644
index 0000000..5bfdc87
--- /dev/null
+++ b/fuzzylite/src/norm/t/DrasticProduct.cpp
@@ -0,0 +1,46 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/DrasticProduct.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string DrasticProduct::className() const {
+ return "DrasticProduct";
+ }
+
+ Complexity DrasticProduct::complexity() const {
+ return Complexity().comparison(1).function(2);
+ }
+
+ scalar DrasticProduct::compute(scalar a, scalar b) const {
+ if (Op::isEq(Op::max(a, b), 1.0)) {
+ return Op::min(a, b);
+ }
+ return 0.0;
+ }
+
+ DrasticProduct* DrasticProduct::clone() const {
+ return new DrasticProduct(*this);
+ }
+
+ TNorm* DrasticProduct::constructor() {
+ return new DrasticProduct;
+ }
+
+}
diff --git a/fuzzylite/src/norm/t/EinsteinProduct.cpp b/fuzzylite/src/norm/t/EinsteinProduct.cpp
new file mode 100644
index 0000000..bbb3966
--- /dev/null
+++ b/fuzzylite/src/norm/t/EinsteinProduct.cpp
@@ -0,0 +1,41 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/EinsteinProduct.h"
+
+namespace fl {
+
+ std::string EinsteinProduct::className() const {
+ return "EinsteinProduct";
+ }
+
+ Complexity EinsteinProduct::complexity() const {
+ return Complexity().arithmetic(6);
+ }
+
+ scalar EinsteinProduct::compute(scalar a, scalar b) const {
+ return (a * b) / (2.0 - (a + b - a * b));
+ }
+
+ EinsteinProduct* EinsteinProduct::clone() const {
+ return new EinsteinProduct(*this);
+ }
+
+ TNorm* EinsteinProduct::constructor() {
+ return new EinsteinProduct;
+ }
+
+}
diff --git a/fuzzylite/src/norm/t/HamacherProduct.cpp b/fuzzylite/src/norm/t/HamacherProduct.cpp
new file mode 100644
index 0000000..9416084
--- /dev/null
+++ b/fuzzylite/src/norm/t/HamacherProduct.cpp
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/HamacherProduct.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string HamacherProduct::className() const {
+ return "HamacherProduct";
+ }
+
+ Complexity HamacherProduct::complexity() const {
+ return Complexity().arithmetic(5);
+ }
+
+ scalar HamacherProduct::compute(scalar a, scalar b) const {
+ if (Op::isEq(a + b, 0.0)) return 0.0;
+ return (a * b) / (a + b - a * b);
+ }
+
+ HamacherProduct* HamacherProduct::clone() const {
+ return new HamacherProduct(*this);
+ }
+
+ TNorm* HamacherProduct::constructor() {
+ return new HamacherProduct;
+ }
+
+}
diff --git a/fuzzylite/src/norm/t/Minimum.cpp b/fuzzylite/src/norm/t/Minimum.cpp
new file mode 100644
index 0000000..1a63658
--- /dev/null
+++ b/fuzzylite/src/norm/t/Minimum.cpp
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/Minimum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string Minimum::className() const {
+ return "Minimum";
+ }
+
+ Complexity Minimum::complexity() const {
+ return Complexity().function(1);
+ }
+
+ scalar Minimum::compute(scalar a, scalar b) const {
+ return Op::min(a, b);
+ }
+
+ Minimum* Minimum::clone() const {
+ return new Minimum(*this);
+ }
+
+ TNorm* Minimum::constructor() {
+ return new Minimum;
+ }
+
+
+}
diff --git a/fuzzylite/src/norm/t/NilpotentMinimum.cpp b/fuzzylite/src/norm/t/NilpotentMinimum.cpp
new file mode 100644
index 0000000..7ab906b
--- /dev/null
+++ b/fuzzylite/src/norm/t/NilpotentMinimum.cpp
@@ -0,0 +1,47 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/NilpotentMinimum.h"
+
+#include "fl/Operation.h"
+
+namespace fl {
+
+ std::string NilpotentMinimum::className() const {
+ return "NilpotentMinimum";
+ }
+
+ Complexity NilpotentMinimum::complexity() const {
+ return Complexity().comparison(1).arithmetic(1).function(1);
+ }
+
+ scalar NilpotentMinimum::compute(scalar a, scalar b) const {
+ if (Op::isGt(a + b, 1.0)) {
+ return Op::min(a, b);
+ }
+ return 0.0;
+ }
+
+ NilpotentMinimum* NilpotentMinimum::clone() const {
+ return new NilpotentMinimum(*this);
+ }
+
+ TNorm* NilpotentMinimum::constructor() {
+ return new NilpotentMinimum;
+ }
+
+
+}
diff --git a/fuzzylite/src/norm/t/TNormFunction.cpp b/fuzzylite/src/norm/t/TNormFunction.cpp
new file mode 100644
index 0000000..1e0563e
--- /dev/null
+++ b/fuzzylite/src/norm/t/TNormFunction.cpp
@@ -0,0 +1,66 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/norm/t/TNormFunction.h"
+
+namespace fl {
+
+ TNormFunction::TNormFunction(const std::string& formula) : TNorm() {
+ _function.variables["a"] = fl::nan;
+ _function.variables["b"] = fl::nan;
+ if (not formula.empty()) {
+ _function.load(formula);
+ }
+ }
+
+ std::string TNormFunction::className() const {
+ return "TNormFunction";
+ }
+
+ Complexity TNormFunction::complexity() const {
+ if (_function.root())
+ return _function.complexity().function(2 * std::log(scalar(_function.variables.size())));
+ return _function.complexity();
+ }
+
+ scalar TNormFunction::compute(scalar a, scalar b) const {
+ _function.variables["a"] = a;
+ _function.variables["b"] = b;
+ return _function.evaluate();
+ }
+
+ Function& TNormFunction::function() {
+ return this->_function;
+ }
+
+ void TNormFunction::setFormula(const std::string& formula) {
+ this->_function.load(formula);
+ }
+
+ std::string TNormFunction::getFormula() const {
+ return _function.getFormula();
+ }
+
+ TNormFunction* TNormFunction::clone() const {
+ return new TNormFunction(*this);
+ }
+
+ TNorm* TNormFunction::constructor() {
+ return new TNormFunction;
+ }
+
+
+}
diff --git a/fuzzylite/src/rule/Antecedent.cpp b/fuzzylite/src/rule/Antecedent.cpp
new file mode 100644
index 0000000..5f0b0be
--- /dev/null
+++ b/fuzzylite/src/rule/Antecedent.cpp
@@ -0,0 +1,447 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/rule/Antecedent.h"
+
+#include "fl/Engine.h"
+#include "fl/factory/HedgeFactory.h"
+#include "fl/factory/FactoryManager.h"
+#include "fl/hedge/Any.h"
+#include "fl/rule/Expression.h"
+#include "fl/rule/Rule.h"
+#include "fl/term/Aggregated.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#include <stack>
+
+namespace fl {
+
+ Antecedent::Antecedent()
+ : _text(""), _expression(fl::null) { }
+
+ Antecedent::~Antecedent() {
+ _expression.reset(fl::null);
+ }
+
+ void Antecedent::setText(const std::string& text) {
+ this->_text = text;
+ }
+
+ std::string Antecedent::getText() const {
+ return this->_text;
+ }
+
+ Expression* Antecedent::getExpression() const {
+ return this->_expression.get();
+ }
+
+ void Antecedent::setExpression(Expression* expression) {
+ this->_expression.reset(expression);
+ }
+
+ bool Antecedent::isLoaded() const {
+ return _expression.get() != fl::null;
+ }
+
+ scalar Antecedent::activationDegree(const TNorm* conjunction, const SNorm* disjunction) const {
+ return this->activationDegree(conjunction, disjunction, _expression.get());
+ }
+
+ scalar Antecedent::activationDegree(const TNorm* conjunction, const SNorm* disjunction,
+ const Expression* node) const {
+ if (not isLoaded()) {
+ throw Exception("[antecedent error] antecedent <" + getText() + "> is not loaded", FL_AT);
+ }
+ const Expression::Type expression = node->type();
+ if (expression == Expression::Proposition) {
+ const Proposition* proposition = static_cast<const Proposition*> (node);
+ if (not proposition->variable->isEnabled()) {
+ return 0.0;
+ }
+
+ if (not proposition->hedges.empty()) {
+ //if last hedge is "Any", apply hedges in reverse order and return degree
+ std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ if (dynamic_cast<Any*> (*rit)) {
+ scalar result = (*rit)->hedge(fl::nan);
+ while (++rit != proposition->hedges.rend()) {
+ result = (*rit)->hedge(result);
+ }
+ return result;
+ }
+ }
+ scalar result = fl::nan;
+ Variable::Type variableType = proposition->variable->type();
+ if (variableType == Variable::Input) {
+ result = proposition->term->membership(proposition->variable->getValue());
+ } else if (variableType == Variable::Output) {
+ result = static_cast<OutputVariable*> (proposition->variable)
+ ->fuzzyOutput()->activationDegree(proposition->term);
+ }
+
+ if (not proposition->hedges.empty()) {
+ for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ rit != proposition->hedges.rend(); ++rit) {
+ result = (*rit)->hedge(result);
+ }
+ }
+ return result;
+ }
+ //if node is an operator
+ if (expression == Expression::Operator) {
+ const Operator* fuzzyOperator = static_cast<const Operator*> (node);
+ if (not (fuzzyOperator->left and fuzzyOperator->right)) {
+ std::ostringstream ex;
+ ex << "[syntax error] left and right operands must exist";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (fuzzyOperator->name == Rule::andKeyword()) {
+ if (not conjunction) throw Exception("[conjunction error] "
+ "the following rule requires a conjunction operator:\n" + _text, FL_AT);
+ return conjunction->compute(
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->left),
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->right));
+ }
+
+ if (fuzzyOperator->name == Rule::orKeyword()) {
+ if (not disjunction) throw Exception("[disjunction error] "
+ "the following rule requires a disjunction operator:\n" + _text, FL_AT);
+ return disjunction->compute(
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->left),
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->right));
+ }
+ std::ostringstream ex;
+ ex << "[syntax error] operator <" << fuzzyOperator->name << "> not recognized";
+ throw Exception(ex.str(), FL_AT);
+
+ } else {
+ std::ostringstream ss;
+ ss << "[antecedent error] expected a Proposition or Operator, but found <";
+ if (node) ss << node->toString();
+ ss << ">";
+ throw Exception(ss.str(), FL_AT);
+ }
+ }
+
+
+ Complexity Antecedent::complexity(const TNorm* conjunction, const SNorm* disjunction) const {
+ return complexity(conjunction, disjunction, _expression.get());
+ }
+
+ Complexity Antecedent::complexity(const TNorm* conjunction, const SNorm* disjunction,
+ const Expression* node) const {
+ if (not isLoaded()) {
+ return Complexity();
+ }
+
+ Complexity result;
+ const Expression::Type expression = node->type();
+ if (expression == Expression::Proposition) {
+ const Proposition* proposition = static_cast<const Proposition*> (node);
+ if (not proposition->variable->isEnabled()) {
+ return result;
+ }
+
+ if (not proposition->hedges.empty()) {
+ //if last hedge is "Any", apply hedges in reverse order and return degree
+ std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ if (dynamic_cast<Any*> (*rit)) {
+ result += (*rit)->complexity();
+ while (++rit != proposition->hedges.rend()) {
+ result = (*rit)->complexity();
+ }
+ return result;
+ }
+ }
+ Variable::Type variableType = proposition->variable->type();
+ if (variableType == Variable::Input) {
+ result += proposition->term->complexity();
+ } else if (variableType == Variable::Output) {
+ OutputVariable* outputVariable = static_cast<OutputVariable*> (proposition->variable);
+ result += outputVariable->fuzzyOutput()->complexityOfActivationDegree();
+ }
+
+ if (not proposition->hedges.empty()) {
+ for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ rit != proposition->hedges.rend(); ++rit) {
+ result += (*rit)->complexity();
+ }
+ }
+ return result;
+ }
+ //if node is an operator
+ if (expression == Expression::Operator) {
+ const Operator* fuzzyOperator = static_cast<const Operator*> (node);
+ if (not (fuzzyOperator->left and fuzzyOperator->right)) {
+ std::ostringstream ex;
+ ex << "[syntax error] left and right operands must exist";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (fuzzyOperator->name == Rule::andKeyword()) {
+ if (conjunction) {
+ result += conjunction->complexity();
+ }
+ result += complexity(conjunction, disjunction, fuzzyOperator->left)
+ + complexity(conjunction, disjunction, fuzzyOperator->right);
+ return result;
+ }
+
+ if (fuzzyOperator->name == Rule::orKeyword()) {
+ if (disjunction) {
+ result += disjunction->complexity();
+ }
+ result += complexity(conjunction, disjunction, fuzzyOperator->left)
+ + complexity(conjunction, disjunction, fuzzyOperator->right);
+ return result;
+ }
+ }
+ return Complexity();
+ }
+
+ void Antecedent::unload() {
+ _expression.reset(fl::null);
+ }
+
+ void Antecedent::load(const Engine* engine) {
+ load(getText(), engine);
+ }
+
+ void Antecedent::load(const std::string& antecedent, const Engine* engine) {
+ FL_DBG("Antecedent: " << antecedent);
+ unload();
+ setText(antecedent);
+ if (Op::trim(antecedent).empty()) {
+ throw Exception("[syntax error] antecedent is empty", FL_AT);
+ }
+ /*
+ Builds an proposition tree from the antecedent of a fuzzy rule.
+ The rules are:
+ 1) After a variable comes 'is',
+ 2) After 'is' comes a hedge or a term
+ 3) After a hedge comes a hedge or a term
+ 4) After a term comes a variable or an operator
+ */
+
+ Function function;
+
+ std::string postfix = function.toPostfix(antecedent);
+ FL_DBG("Postfix: " << postfix);
+ std::stringstream tokenizer(postfix);
+ std::string token;
+
+ enum FSM {
+ S_VARIABLE = 1, S_IS = 2, S_HEDGE = 4, S_TERM = 8, S_AND_OR = 16
+ };
+ int state = S_VARIABLE;
+ std::stack<Expression*> expressionStack;
+ Proposition* proposition = fl::null;
+ try {
+ while (tokenizer >> token) {
+ if (state bitand S_VARIABLE) {
+ Variable* variable = fl::null;
+ if (engine->hasInputVariable(token))
+ variable = engine->getInputVariable(token);
+ else if (engine->hasOutputVariable(token))
+ variable = engine->getOutputVariable(token);
+ if (variable) {
+ proposition = new Proposition;
+ proposition->variable = variable;
+ expressionStack.push(proposition);
+
+ state = S_IS;
+ FL_DBG("Token <" << token << "> is variable");
+ continue;
+ }
+ }
+
+ if (state bitand S_IS) {
+ if (token == Rule::isKeyword()) {
+ state = S_HEDGE bitor S_TERM;
+ FL_DBG("Token <" << token << "> is keyword");
+ continue;
+ }
+ }
+
+ if (state bitand S_HEDGE) {
+ HedgeFactory* factory = FactoryManager::instance()->hedge();
+ if (factory->hasConstructor(token)) {
+ Hedge* hedge = factory->constructObject(token);
+ proposition->hedges.push_back(hedge);
+ if (dynamic_cast<Any*> (hedge)) {
+ state = S_VARIABLE bitor S_AND_OR;
+ } else {
+ state = S_HEDGE bitor S_TERM;
+ }
+ FL_DBG("Token <" << token << "> is hedge");
+ continue;
+ }
+ }
+
+ if (state bitand S_TERM) {
+ if (proposition->variable->hasTerm(token)) {
+ proposition->term = proposition->variable->getTerm(token);
+ state = S_VARIABLE bitor S_AND_OR;
+ FL_DBG("Token <" << token << "> is term");
+ continue;
+ }
+ }
+
+ if (state bitand S_AND_OR) {
+ if (token == Rule::andKeyword() or token == Rule::orKeyword()) {
+ if (expressionStack.size() < 2) {
+ std::ostringstream ex;
+ ex << "[syntax error] logical operator <" << token << "> expects two operands,"
+ << "but found <" << expressionStack.size() << "> in antecedent";
+ throw Exception(ex.str(), FL_AT);
+ }
+ Operator* fuzzyOperator = new Operator;
+ fuzzyOperator->name = token;
+ fuzzyOperator->right = expressionStack.top();
+ expressionStack.pop();
+ fuzzyOperator->left = expressionStack.top();
+ expressionStack.pop();
+ expressionStack.push(fuzzyOperator);
+
+ state = S_VARIABLE bitor S_AND_OR;
+ FL_DBG("Subtree: " << fuzzyOperator->toString() <<
+ "(" << fuzzyOperator->left->toString() << ") " <<
+ "(" << fuzzyOperator->right->toString() << ")");
+ continue;
+ }
+ }
+
+ //If reached this point, there was an error
+ if ((state bitand S_VARIABLE) or (state bitand S_AND_OR)) {
+ std::ostringstream ex;
+ ex << "[syntax error] antecedent expected variable or logical operator, but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (state bitand S_IS) {
+ std::ostringstream ex;
+ ex << "[syntax error] antecedent expected keyword <" << Rule::isKeyword() << ">, but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if ((state bitand S_HEDGE) or (state bitand S_TERM)) {
+ std::ostringstream ex;
+ ex << "[syntax error] antecedent expected hedge or term, but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected token <" << token << "> in antecedent";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ if (not ((state bitand S_VARIABLE) or (state bitand S_AND_OR))) { //only acceptable final state
+ if (state bitand S_IS) {
+ std::ostringstream ex;
+ ex << "[syntax error] antecedent expected keyword <" << Rule::isKeyword() << "> after <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if ((state bitand S_HEDGE) or (state bitand S_TERM)) {
+ std::ostringstream ex;
+ ex << "[syntax error] antecedent expected hedge or term after <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+
+ if (expressionStack.size() != 1) {
+ std::vector<std::string> errors;
+ while (expressionStack.size() > 1) {
+ Expression* expression = expressionStack.top();
+ expressionStack.pop();
+ errors.push_back(expression->toString());
+ delete expression;
+ }
+ std::ostringstream ex;
+ ex << "[syntax error] unable to parse the following expressions in antecedent <"
+ << Op::join(errors, " ") << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ } catch (...) {
+ for (std::size_t i = 0; i < expressionStack.size(); ++i) {
+ delete expressionStack.top();
+ expressionStack.pop();
+ }
+ throw;
+ }
+ setExpression(expressionStack.top());
+ }
+
+ std::string Antecedent::toString() const {
+ return toInfix(getExpression());
+ }
+
+ std::string Antecedent::toPrefix(const Expression* node) const {
+ if (not isLoaded()) {
+ throw Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ }
+ if (not node) node = getExpression();
+
+ if (dynamic_cast<const Proposition*> (node)) {
+ return node->toString();
+ }
+ std::stringstream ss;
+ if (const Operator * fuzzyOperator = dynamic_cast<const Operator*> (node)) {
+ ss << fuzzyOperator->toString() << " "
+ << toPrefix(fuzzyOperator->left) << " "
+ << toPrefix(fuzzyOperator->right) << " ";
+ } else {
+ ss << "[antecedent error] unknown class of Expression <" << (node ? node->toString() : "null") << ">";
+ }
+ return ss.str();
+ }
+
+ std::string Antecedent::toInfix(const Expression* node) const {
+ if (not isLoaded()) {
+ throw Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ }
+ if (not node) node = getExpression();
+ if (dynamic_cast<const Proposition*> (node)) {
+ return node->toString();
+ }
+ std::stringstream ss;
+ if (const Operator * fuzzyOperator = dynamic_cast<const Operator*> (node)) {
+ ss << toInfix(fuzzyOperator->left) << " "
+ << fuzzyOperator->toString() << " "
+ << toInfix(fuzzyOperator->right) << " ";
+ } else {
+ ss << "[antecedent error] unknown class of Expression <" << (node ? node->toString() : "null") << ">";
+ }
+ return ss.str();
+ }
+
+ std::string Antecedent::toPostfix(const Expression* node) const {
+ if (not isLoaded()) {
+ throw Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ }
+ if (not node) node = getExpression();
+ if (dynamic_cast<const Proposition*> (node)) {
+ return node->toString();
+ }
+ std::stringstream ss;
+ if (const Operator * fuzzyOperator = dynamic_cast<const Operator*> (node)) {
+ ss << toPostfix(fuzzyOperator->left) << " "
+ << toPostfix(fuzzyOperator->right) << " "
+ << fuzzyOperator->toString() << " ";
+ } else {
+ ss << "[antecedent error] unknown class of Expression <" << (node ? node->toString() : "null") << ">";
+ }
+ return ss.str();
+ }
+
+
+}
diff --git a/fuzzylite/src/rule/Consequent.cpp b/fuzzylite/src/rule/Consequent.cpp
new file mode 100644
index 0000000..a90b1a9
--- /dev/null
+++ b/fuzzylite/src/rule/Consequent.cpp
@@ -0,0 +1,244 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/rule/Consequent.h"
+
+#include "fl/Engine.h"
+#include "fl/factory/HedgeFactory.h"
+#include "fl/factory/FactoryManager.h"
+#include "fl/hedge/Any.h"
+#include "fl/rule/Expression.h"
+#include "fl/rule/Rule.h"
+#include "fl/term/Aggregated.h"
+#include "fl/variable/OutputVariable.h"
+
+namespace fl {
+
+ Consequent::Consequent() { }
+
+ Consequent::~Consequent() {
+ for (std::size_t i = 0; i < _conclusions.size(); ++i) {
+ delete _conclusions.at(i);
+ }
+ _conclusions.clear();
+ }
+
+ std::string Consequent::getText() const {
+ return this->_text;
+ }
+
+ void Consequent::setText(const std::string& text) {
+ this->_text = text;
+ }
+
+ const std::vector<Proposition*>& Consequent::conclusions() const {
+ return this->_conclusions;
+ }
+
+ std::vector<Proposition*>& Consequent::conclusions() {
+ return this->_conclusions;
+ }
+
+ Complexity Consequent::complexity(const TNorm* implication) const {
+ Complexity result;
+ result.comparison(1);
+
+ for (std::size_t i = 0; i < _conclusions.size(); ++i) {
+ Proposition* proposition = _conclusions.at(i);
+ result.comparison(2);
+ for (std::size_t h = 0; h < proposition->hedges.size(); ++h) {
+ result += proposition->hedges.at(h)->complexity();
+ }
+ result += static_cast<OutputVariable*> (proposition->variable)
+ ->complexity(Activated(proposition->term, fl::nan, implication));
+ }
+ return result;
+ }
+
+ void Consequent::modify(scalar activationDegree, const TNorm* implication) {
+ if (not isLoaded()) {
+ throw Exception("[consequent error] consequent <" + getText() + "> is not loaded", FL_AT);
+ }
+ for (std::size_t i = 0; i < _conclusions.size(); ++i) {
+ Proposition* proposition = _conclusions.at(i);
+ if (proposition->variable->isEnabled()) {
+ if (not proposition->hedges.empty()) {
+ for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ rit != proposition->hedges.rend(); ++rit) {
+ activationDegree = (*rit)->hedge(activationDegree);
+ }
+ }
+
+ static_cast<OutputVariable*> (proposition->variable)->fuzzyOutput()
+ ->addTerm(proposition->term, activationDegree, implication);
+ }
+ }
+ }
+
+ bool Consequent::isLoaded() {
+ return not _conclusions.empty();
+ }
+
+ void Consequent::unload() {
+ for (std::size_t i = 0; i < _conclusions.size(); ++i) {
+ delete _conclusions.at(i);
+ }
+ _conclusions.clear();
+ }
+
+ void Consequent::load(const Engine* engine) {
+ load(getText(), engine);
+ }
+
+ void Consequent::load(const std::string& consequent, const Engine* engine) {
+ unload();
+ setText(consequent);
+
+ if (Op::trim(consequent).empty()) {
+ throw Exception("[syntax error] consequent is empty", FL_AT);
+ }
+
+ /**
+ Extracts the list of propositions from the consequent
+ The rules are:
+ 1) After a variable comes 'is' or '=',
+ 2) After 'is' comes a hedge or a term
+ 3) After a hedge comes a hedge or a term
+ 4) After a term comes operators 'and' or 'with'
+ 5) After operator 'and' comes a variable
+ 6) After operator 'with' comes a float
+ */
+ enum FSM {
+ S_VARIABLE = 1, S_IS = 2, S_HEDGE = 4, S_TERM = 8,
+ S_AND = 16, S_WITH = 32
+ };
+ int state = S_VARIABLE;
+
+ Proposition* proposition = fl::null;
+
+ std::stringstream tokenizer(consequent);
+ std::string token;
+ try {
+ while (tokenizer >> token) {
+ if (state bitand S_VARIABLE) {
+ if (engine->hasOutputVariable(token)) {
+ proposition = new Proposition;
+ proposition->variable = engine->getOutputVariable(token);
+ conclusions().push_back(proposition);
+ state = S_IS;
+ continue;
+ }
+ }
+
+ if (state bitand S_IS) {
+ if (token == Rule::isKeyword()) {
+ state = S_HEDGE bitor S_TERM;
+ continue;
+ }
+ }
+
+ if (state bitand S_HEDGE) {
+ HedgeFactory* factory = FactoryManager::instance()->hedge();
+ if (factory->hasConstructor(token)) {
+ Hedge* hedge = factory->constructObject(token);
+ proposition->hedges.push_back(hedge);
+ state = S_HEDGE bitor S_TERM;
+ continue;
+ }
+ }
+
+ if (state bitand S_TERM) {
+ if (proposition->variable->hasTerm(token)) {
+ proposition->term = proposition->variable->getTerm(token);
+ state = S_AND bitor S_WITH;
+ continue;
+ }
+ }
+
+ if (state bitand S_AND) {
+ if (token == Rule::andKeyword()) {
+ state = S_VARIABLE;
+ continue;
+ }
+ }
+
+ //if reached this point, there was an error:
+ if (state bitand S_VARIABLE) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected output variable, but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (state bitand S_IS) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected keyword <" << Rule::isKeyword() << ">, "
+ "but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ if ((state bitand S_HEDGE) or (state bitand S_TERM)) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected hedge or term, but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ if ((state bitand S_AND) or (state bitand S_WITH)) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected operator <" << Rule::andKeyword() << "> "
+ << "or keyword <" << Rule::withKeyword() << ">, "
+ << "but found <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected token <" << token << "> in consequent";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ if (not ((state bitand S_AND) or (state bitand S_WITH))) { //only acceptable final state
+ if (state bitand S_VARIABLE) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected output variable after <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (state bitand S_IS) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected keyword <" << Rule::isKeyword() << "> "
+ "after <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if ((state bitand S_HEDGE) or (state bitand S_TERM)) {
+ std::ostringstream ex;
+ ex << "[syntax error] consequent expected hedge or term after <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+ } catch (...) {
+ unload();
+ throw;
+ }
+ }
+
+ std::string Consequent::toString() const {
+ std::stringstream ss;
+ for (std::size_t i = 0; i < conclusions().size(); ++i) {
+ ss << conclusions().at(i)->toString();
+ if (i + 1 < conclusions().size())
+ ss << " " << Rule::andKeyword() << " ";
+ }
+ return ss.str();
+ }
+
+}
diff --git a/fuzzylite/src/rule/Expression.cpp b/fuzzylite/src/rule/Expression.cpp
new file mode 100644
index 0000000..9b0ab81
--- /dev/null
+++ b/fuzzylite/src/rule/Expression.cpp
@@ -0,0 +1,83 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/rule/Expression.h"
+
+#include "fl/hedge/Hedge.h"
+#include "fl/term/Term.h"
+#include "fl/rule/Rule.h"
+#include "fl/variable/Variable.h"
+
+namespace fl {
+
+ Expression::Expression() { }
+
+ Expression::~Expression() { }
+
+ Proposition::Proposition() : Expression(),
+ variable(fl::null), term(fl::null) { }
+
+ Proposition::~Proposition() {
+ for (std::size_t i = 0; i < hedges.size(); ++i) {
+ delete hedges.at(i);
+ }
+ hedges.clear();
+ }
+
+ Expression::Type Proposition::type() const {
+ return Expression::Proposition;
+ }
+
+ std::string Proposition::toString() const {
+ std::ostringstream ss;
+ if (variable) {
+ ss << variable->getName();
+ } else {
+ ss << "?";
+ }
+ if (not hedges.empty()) {
+ ss << " " << Rule::isKeyword() << " ";
+ for (std::size_t i = 0; i < hedges.size(); ++i) {
+ ss << hedges.at(i)->name() << " ";
+ }
+ }
+
+ if (term) { //term is fl::null if hedge is any
+ if (hedges.empty()) {
+ ss << " " << Rule::isKeyword() << " ";
+ }
+ ss << term->getName();
+ }
+ return ss.str();
+ }
+
+ Operator::Operator() : Expression(),
+ name(""), left(fl::null), right(fl::null) { }
+
+ Operator::~Operator() {
+ if (left) delete left;
+ if (right) delete right;
+ }
+
+ Expression::Type Operator::type() const {
+ return Expression::Operator;
+ }
+
+ std::string Operator::toString() const {
+ return name;
+ }
+
+}
diff --git a/fuzzylite/src/rule/Rule.cpp b/fuzzylite/src/rule/Rule.cpp
new file mode 100644
index 0000000..0338cd9
--- /dev/null
+++ b/fuzzylite/src/rule/Rule.cpp
@@ -0,0 +1,264 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/rule/Rule.h"
+
+#include "fl/Exception.h"
+#include "fl/imex/FllExporter.h"
+#include "fl/norm/Norm.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ Rule::Rule(const std::string& text, scalar weight)
+ : _enabled(true), _text(text), _weight(weight), _activationDegree(0.0), _triggered(false),
+ _antecedent(new Antecedent), _consequent(new Consequent) { }
+
+ Rule::Rule(const Rule& other) : _enabled(other._enabled), _text(other._text),
+ _weight(other._weight), _activationDegree(other._activationDegree), _triggered(false),
+ _antecedent(new Antecedent), _consequent(new Consequent) { }
+
+ Rule& Rule::operator=(const Rule& other) {
+ if (this != &other) {
+ _enabled = other._enabled;
+ _text = other._text;
+ _weight = other._weight;
+ _activationDegree = other._activationDegree;
+ _triggered = other._triggered;
+ _antecedent.reset(new Antecedent);
+ _consequent.reset(new Consequent);
+ }
+ return *this;
+ }
+
+ Rule::~Rule() {
+ if (_antecedent.get()) _antecedent->unload();
+ if (_consequent.get()) _consequent->unload();
+ }
+
+ void Rule::setText(const std::string& text) {
+ this->_text = text;
+ }
+
+ std::string Rule::getText() const {
+ return this->_text;
+ }
+
+ void Rule::setWeight(scalar weight) {
+ this->_weight = weight;
+ }
+
+ scalar Rule::getWeight() const {
+ return this->_weight;
+ }
+
+ void Rule::setAntecedent(Antecedent* antecedent) {
+ this->_antecedent.reset(antecedent);
+ }
+
+ Antecedent* Rule::getAntecedent() const {
+ return this->_antecedent.get();
+ }
+
+ void Rule::setConsequent(Consequent* consequent) {
+ this->_consequent.reset(consequent);
+ }
+
+ Consequent* Rule::getConsequent() const {
+ return this->_consequent.get();
+ }
+
+ void Rule::setEnabled(bool active) {
+ this->_enabled = active;
+ }
+
+ bool Rule::isEnabled() const {
+ return this->_enabled;
+ }
+
+ void Rule::setActivationDegree(scalar activationDegree) {
+ this->_activationDegree = activationDegree;
+ }
+
+ scalar Rule::getActivationDegree() const {
+ return this->_activationDegree;
+ }
+
+ void Rule::deactivate() {
+ _activationDegree = 0.0;
+ _triggered = false;
+ }
+
+ scalar Rule::activateWith(const TNorm* conjunction, const SNorm* disjunction) {
+ if (not isLoaded()) {
+ throw Exception("[rule error] the following rule is not loaded: " + getText(), FL_AT);
+ }
+ _activationDegree = _weight * _antecedent->activationDegree(conjunction, disjunction);
+ return _activationDegree;
+ }
+
+ void Rule::trigger(const TNorm* implication) {
+ if (not isLoaded()) {
+ throw Exception("[rule error] the following rule is not loaded: " + getText(), FL_AT);
+ }
+ if (_enabled and Op::isGt(_activationDegree, 0.0)) {
+ FL_DBG("[firing with " << Op::str(_activationDegree) << "] " << toString());
+ _consequent->modify(_activationDegree, implication);
+ _triggered = true;
+ }
+ }
+
+ bool Rule::isTriggered() const {
+ return this->_triggered;
+ }
+
+ Complexity Rule::complexityOfActivation(const TNorm* conjunction, const SNorm* disjunction) const {
+ Complexity result;
+ result.comparison(1).arithmetic(1);
+ if (isLoaded()) {
+ result += _antecedent->complexity(conjunction, disjunction);
+ }
+ return result;
+ }
+
+ Complexity Rule::complexityOfFiring(const TNorm* implication) const {
+ Complexity result;
+ result.comparison(3);
+ if (isLoaded()) {
+ result += _consequent->complexity(implication);
+ }
+ return result;
+ }
+
+ Complexity Rule::complexity(const TNorm* conjunction, const SNorm* disjunction,
+ const TNorm* implication) const {
+ return complexityOfActivation(conjunction, disjunction)
+ + complexityOfFiring(implication);
+ }
+
+ bool Rule::isLoaded() const {
+ return _antecedent.get() and _consequent.get()
+ and _antecedent->isLoaded() and _consequent->isLoaded();
+ }
+
+ void Rule::unload() {
+ deactivate();
+ if (getAntecedent()) getAntecedent()->unload();
+ if (getConsequent()) getConsequent()->unload();
+ }
+
+ void Rule::load(const Engine* engine) {
+ load(getText(), engine);
+ }
+
+ void Rule::load(const std::string& rule, const Engine* engine) {
+ deactivate();
+ setEnabled(true);
+ setText(rule);
+ std::istringstream tokenizer(rule.substr(0, rule.find_first_of('#')));
+ std::string token;
+ std::ostringstream ossAntecedent, ossConsequent;
+ scalar weight = 1.0;
+
+ enum FSM {
+ S_NONE, S_IF, S_THEN, S_WITH, S_END
+ };
+ FSM state = S_NONE;
+ try {
+ while (tokenizer >> token) {
+
+ switch (state) {
+ case S_NONE:
+ if (token == Rule::ifKeyword()) state = S_IF;
+ else {
+ std::ostringstream ex;
+ ex << "[syntax error] expected keyword <" << Rule::ifKeyword() <<
+ ">, but found <" << token << "> in rule: " << rule;
+ throw Exception(ex.str(), FL_AT);
+ }
+ break;
+ case S_IF:
+ if (token == Rule::thenKeyword()) state = S_THEN;
+ else ossAntecedent << token << " ";
+ break;
+ case S_THEN:
+ if (token == Rule::withKeyword()) state = S_WITH;
+ else ossConsequent << token << " ";
+ break;
+ case S_WITH:
+ try {
+ weight = Op::toScalar(token);
+ state = S_END;
+ } catch (Exception& e) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected a numeric value as the weight of the rule: "
+ << rule;
+ e.append(ex.str(), FL_AT);
+ throw;
+ }
+ break;
+ case S_END:
+ {
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected token <" << token << "> at the end of rule";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ default:
+ std::ostringstream ex;
+ ex << "[syntax error] unexpected state <" << state << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+ if (state == S_NONE) {
+ std::ostringstream ex;
+ ex << "[syntax error] " << (rule.empty() ? "empty rule" : ("ignored rule: " + rule));
+ throw Exception(ex.str(), FL_AT);
+ } else if (state == S_IF) {
+ std::ostringstream ex;
+ ex << "[syntax error] keyword <" << Rule::thenKeyword() << "> not found in rule: " << rule;
+ throw Exception(ex.str(), FL_AT);
+ } else if (state == S_WITH) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected a numeric value as the weight of the rule: " << rule;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ getAntecedent()->load(ossAntecedent.str(), engine);
+ getConsequent()->load(ossConsequent.str(), engine);
+ setWeight(weight);
+
+ } catch (...) {
+ unload();
+ throw;
+ }
+ }
+
+ std::string Rule::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ Rule* Rule::clone() const {
+ return new Rule(*this);
+ }
+
+ Rule* Rule::parse(const std::string& rule, const Engine* engine) {
+ FL_unique_ptr<Rule> result(new Rule);
+ result->load(rule, engine);
+ return result.release();
+ }
+
+}
diff --git a/fuzzylite/src/rule/RuleBlock.cpp b/fuzzylite/src/rule/RuleBlock.cpp
new file mode 100644
index 0000000..d4e2a82
--- /dev/null
+++ b/fuzzylite/src/rule/RuleBlock.cpp
@@ -0,0 +1,227 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/rule/RuleBlock.h"
+
+#include "fl/activation/General.h"
+#include "fl/imex/FllExporter.h"
+#include "fl/norm/TNorm.h"
+#include "fl/norm/SNorm.h"
+#include "fl/rule/Rule.h"
+#include "fl/Operation.h"
+
+namespace fl {
+
+ RuleBlock::RuleBlock(const std::string& name)
+ : _enabled(true), _name(name), _description("") { }
+
+ RuleBlock::RuleBlock(const RuleBlock& other) : _enabled(true), _name(other._name),
+ _description(other._description) {
+ copyFrom(other);
+ }
+
+ RuleBlock& RuleBlock::operator=(const RuleBlock& other) {
+ if (this != &other) {
+ for (std::size_t i = 0; i < _rules.size(); ++i) {
+ delete _rules.at(i);
+ }
+ _rules.clear();
+ _conjunction.reset(fl::null);
+ _disjunction.reset(fl::null);
+ _implication.reset(fl::null);
+ _activation.reset(fl::null);
+
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ void RuleBlock::copyFrom(const RuleBlock& source) {
+ _enabled = source._enabled;
+ _name = source._name;
+ _description = source._description;
+ if (source._conjunction.get()) _conjunction.reset(source._conjunction->clone());
+ if (source._disjunction.get()) _disjunction.reset(source._disjunction->clone());
+ if (source._implication.get()) _implication.reset(source._implication->clone());
+ if (source._activation.get()) _activation.reset(source._activation->clone());
+ for (std::size_t i = 0; i < source._rules.size(); ++i) {
+ _rules.push_back(source._rules.at(i)->clone());
+ }
+ }
+
+ RuleBlock::~RuleBlock() {
+ for (std::size_t i = 0; i < _rules.size(); ++i) {
+ delete _rules.at(i);
+ }
+ _rules.clear();
+ }
+
+ Complexity RuleBlock::complexity() const {
+ Complexity result;
+ result.comparison(1);
+ if (_activation.get()) {
+ result += _activation->complexity(this);
+ } else {
+ for (std::size_t i = 0; i < _rules.size(); ++i) {
+ result += _rules.at(i)->complexity(
+ _conjunction.get(), _disjunction.get(), _implication.get());
+ }
+ }
+ return result;
+ }
+
+ void RuleBlock::activate() {
+ if (not _activation.get()) {
+ _activation.reset(new General);
+ }
+ _activation->activate(this);
+ }
+
+ void RuleBlock::unloadRules() const {
+ for (std::size_t i = 0; i < _rules.size(); ++i) {
+ _rules.at(i)->unload();
+ }
+ }
+
+ void RuleBlock::loadRules(const Engine* engine) {
+ std::ostringstream exceptions;
+ bool throwException = false;
+ for (std::size_t i = 0; i < _rules.size(); ++i) {
+ Rule* rule = _rules.at(i);
+ if (rule->isLoaded()) {
+ rule->unload();
+ }
+ try {
+ rule->load(engine);
+ } catch (std::exception& ex) {
+ throwException = true;
+ exceptions << ex.what() << "\n";
+ }
+ }
+ if (throwException) {
+ Exception exception("[ruleblock error] the following "
+ "rules could not be loaded:\n" + exceptions.str(), FL_AT);
+ throw exception;
+ }
+ }
+
+ void RuleBlock::reloadRules(const Engine* engine) {
+ unloadRules();
+ loadRules(engine);
+ }
+
+ void RuleBlock::setName(std::string name) {
+ this->_name = name;
+ }
+
+ std::string RuleBlock::getName() const {
+ return this->_name;
+ }
+
+ void RuleBlock::setDescription(const std::string& description) {
+ this->_description = description;
+ }
+
+ std::string RuleBlock::getDescription() const {
+ return this->_description;
+ }
+
+ void RuleBlock::setConjunction(TNorm* tnorm) {
+ this->_conjunction.reset(tnorm);
+ }
+
+ TNorm* RuleBlock::getConjunction() const {
+ return this->_conjunction.get();
+ }
+
+ void RuleBlock::setDisjunction(SNorm* snorm) {
+ this->_disjunction.reset(snorm);
+ }
+
+ SNorm* RuleBlock::getDisjunction() const {
+ return this->_disjunction.get();
+ }
+
+ void RuleBlock::setImplication(TNorm* implication) {
+ this->_implication.reset(implication);
+ }
+
+ TNorm* RuleBlock::getImplication() const {
+ return this->_implication.get();
+ }
+
+ void RuleBlock::setActivation(Activation* activation) {
+ this->_activation.reset(activation);
+ }
+
+ Activation* RuleBlock::getActivation() const {
+ return this->_activation.get();
+ }
+
+ void RuleBlock::setEnabled(bool enabled) {
+ this->_enabled = enabled;
+ }
+
+ bool RuleBlock::isEnabled() const {
+ return this->_enabled;
+ }
+
+ std::string RuleBlock::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ /**
+ * Operations for std::vector _rules
+ */
+ void RuleBlock::addRule(Rule* rule) {
+ _rules.push_back(rule);
+ }
+
+ void RuleBlock::insertRule(Rule* rule, std::size_t index) {
+ _rules.insert(_rules.begin() + index, rule);
+ }
+
+ Rule* RuleBlock::getRule(std::size_t index) const {
+ return _rules.at(index);
+ }
+
+ Rule* RuleBlock::removeRule(std::size_t index) {
+ Rule* result = _rules.at(index);
+ _rules.erase(_rules.begin() + index);
+ return result;
+ }
+
+ std::size_t RuleBlock::numberOfRules() const {
+ return _rules.size();
+ }
+
+ const std::vector<Rule*>& RuleBlock::rules() const {
+ return this->_rules;
+ }
+
+ void RuleBlock::setRules(const std::vector<Rule*>& rules) {
+ this->_rules = rules;
+ }
+
+ std::vector<Rule*>& RuleBlock::rules() {
+ return this->_rules;
+ }
+
+ RuleBlock* RuleBlock::clone() const {
+ return new RuleBlock(*this);
+ }
+
+}
diff --git a/fuzzylite/src/term/Activated.cpp b/fuzzylite/src/term/Activated.cpp
new file mode 100644
index 0000000..80eda6c
--- /dev/null
+++ b/fuzzylite/src/term/Activated.cpp
@@ -0,0 +1,110 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Activated.h"
+
+#include "fl/imex/FllExporter.h"
+
+namespace fl {
+
+ Activated::Activated(const Term* term, scalar degree, const TNorm* implication)
+ : Term(""), _term(term), _degree(degree), _implication(implication) {
+ if (term) setName(term->getName());
+ }
+
+ Activated::~Activated() { }
+
+ std::string Activated::className() const {
+ return "Activated";
+ }
+
+ Complexity Activated::complexity() const {
+ Complexity result;
+ result.comparison(3);
+ if (_implication) {
+ result += _implication->complexity();
+ }
+ if (_term) {
+ result += _term->complexity();
+ }
+ return result;
+ }
+
+ scalar Activated::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (not _term)
+ throw Exception("[activation error] no term available to activate", FL_AT);
+ if (not _implication)
+ throw Exception("[implication error] implication operator needed "
+ "to activate " + getTerm()->toString(), FL_AT);
+ return _implication->compute(_term->membership(x), _degree);
+ }
+
+ std::string Activated::parameters() const {
+ FllExporter exporter;
+ std::ostringstream ss;
+ ss << Op::str(getDegree()) << " " << exporter.toString(getImplication()) << " "
+ << exporter.toString(getTerm());
+ return ss.str();
+ }
+
+ void Activated::configure(const std::string& parameters) {
+ FL_IUNUSED(parameters);
+ }
+
+ std::string Activated::toString() const {
+ FllExporter exporter;
+ std::ostringstream ss;
+ if (getImplication()) {
+ ss << exporter.toString(getImplication()) << "("
+ << Op::str(getDegree()) << ","
+ << getTerm()->getName() << ")";
+ } else {
+ ss << "(" << Op::str(getDegree()) << "*" //"\u2297: (*)"
+ << getTerm()->getName() << ")";
+ }
+ return ss.str();
+ }
+
+ void Activated::setTerm(const Term* term) {
+ this->_term = term;
+ }
+
+ const Term* Activated::getTerm() const {
+ return this->_term;
+ }
+
+ void Activated::setDegree(scalar degree) {
+ this->_degree = degree;
+ }
+
+ scalar Activated::getDegree() const {
+ return this->_degree;
+ }
+
+ void Activated::setImplication(const TNorm* implication) {
+ this->_implication = implication;
+ }
+
+ const TNorm* Activated::getImplication() const {
+ return this->_implication;
+ }
+
+ Activated* Activated::clone() const {
+ return new Activated(*this);
+ }
+
+}
diff --git a/fuzzylite/src/term/Aggregated.cpp b/fuzzylite/src/term/Aggregated.cpp
new file mode 100644
index 0000000..d1e2c89
--- /dev/null
+++ b/fuzzylite/src/term/Aggregated.cpp
@@ -0,0 +1,247 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Aggregated.h"
+
+#include "fl/imex/FllExporter.h"
+#include "fl/norm/s/Maximum.h"
+
+namespace fl {
+
+ Aggregated::Aggregated(const std::string& name, scalar minimum, scalar maximum,
+ SNorm* aggregation)
+ : Term(name), _minimum(minimum), _maximum(maximum), _aggregation(aggregation) { }
+
+ Aggregated::Aggregated(const Aggregated& other) : Term(other) {
+ copyFrom(other);
+ }
+
+ Aggregated& Aggregated::operator=(const Aggregated& other) {
+ if (this != &other) {
+ clear();
+ _aggregation.reset(fl::null);
+
+ Term::operator=(other);
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ Aggregated::~Aggregated() { }
+
+ void Aggregated::copyFrom(const Aggregated& source) {
+ _minimum = source._minimum;
+ _maximum = source._maximum;
+
+ if (source._aggregation.get())
+ _aggregation.reset(source._aggregation->clone());
+
+ for (std::size_t i = 0; i < source._terms.size(); ++i) {
+ _terms.push_back(source._terms.at(i));
+ }
+ }
+
+ std::string Aggregated::className() const {
+ return "Aggregated";
+ }
+
+ Complexity Aggregated::complexity() const {
+ return complexityOfMembership();
+ }
+
+ Complexity Aggregated::complexityOfMembership() const {
+ Complexity result;
+ result.comparison(3);
+ if (_aggregation.get()) {
+ result += _aggregation->complexity().multiply(scalar(_terms.size()));
+ }
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ result += _terms.at(i).complexity();
+ }
+ return result;
+ }
+
+ scalar Aggregated::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (not (_terms.empty() or _aggregation.get())) { //Exception for IntegralDefuzzifiers
+ throw Exception("[aggregation error] "
+ "aggregation operator needed to aggregate variable "
+ "<" + getName() + ">", FL_AT);
+ }
+ scalar mu = 0.0;
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ mu = _aggregation->compute(mu, _terms.at(i).membership(x));
+ }
+ return mu;
+ }
+
+ Complexity Aggregated::complexityOfActivationDegree() const {
+ Complexity result;
+ result.comparison(2);
+ if (_aggregation.get()) {
+ result += _aggregation->complexity();
+ } else result.arithmetic(1);
+ result.multiply(scalar(_terms.size()));
+ return result;
+ }
+
+ scalar Aggregated::activationDegree(const Term* forTerm) const {
+ scalar result = 0.0;
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ const Activated& activatedTerm = _terms.at(i);
+ if (activatedTerm.getTerm() == forTerm) {
+ if (_aggregation.get())
+ result = _aggregation->compute(result, activatedTerm.getDegree());
+ else
+ result += activatedTerm.getDegree(); //Default for WeightDefuzzifier
+ }
+ }
+ return result;
+ }
+
+ const Activated* Aggregated::highestActivatedTerm() const {
+ const Activated* maximumTerm = fl::null;
+ scalar maximumActivation = -fl::inf;
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ const Activated& activated = _terms.at(i);
+ if (Op::isGt(activated.getDegree(), maximumActivation)) {
+ maximumActivation = activated.getDegree();
+ maximumTerm = &activated;
+ }
+ }
+ return maximumTerm;
+ }
+
+ std::string Aggregated::parameters() const {
+ FllExporter exporter;
+ std::ostringstream ss;
+ ss << exporter.toString(getAggregation());
+ ss << " " << Op::str(getMinimum()) << " " << Op::str(getMaximum()) << " ";
+ for (std::size_t i = 0; i < terms().size(); ++i) {
+ ss << " " << exporter.toString(&terms().at(i));
+ }
+ return ss.str();
+ }
+
+ void Aggregated::configure(const std::string& parameters) {
+ FL_IUNUSED(parameters);
+ }
+
+ Aggregated* Aggregated::clone() const {
+ return new Aggregated(*this);
+ }
+
+ std::string Aggregated::toString() const {
+ std::vector<std::string> aggregate;
+ for (std::size_t i = 0; i < terms().size(); ++i) {
+ aggregate.push_back(terms().at(i).toString());
+ }
+ FllExporter exporter;
+ std::ostringstream ss;
+ if (getAggregation()) {
+ ss << getName() << ": " << className() << " "
+ << exporter.toString(getAggregation()) << "["
+ << Op::join(aggregate, ",") << "]";
+ } else {
+ ss << getName() << ": " << className() << " " << "["
+ << Op::join(aggregate, "+") << "]"; //\u2295: (+)
+ }
+ return ss.str();
+ }
+
+ void Aggregated::setMinimum(scalar minimum) {
+ this->_minimum = minimum;
+ }
+
+ scalar Aggregated::getMinimum() const {
+ return this->_minimum;
+ }
+
+ void Aggregated::setMaximum(scalar maximum) {
+ this->_maximum = maximum;
+ }
+
+ scalar Aggregated::getMaximum() const {
+ return this->_maximum;
+ }
+
+ void Aggregated::setRange(scalar minimum, scalar maximum) {
+ setMinimum(minimum);
+ setMaximum(maximum);
+ }
+
+ scalar Aggregated::range() const {
+ return getMaximum() - getMinimum();
+ }
+
+ void Aggregated::setAggregation(SNorm* aggregation) {
+ this->_aggregation.reset(aggregation);
+ }
+
+ SNorm* Aggregated::getAggregation() const {
+ return this->_aggregation.get();
+ }
+
+ /**
+ * Operations for std::vector _terms
+ */
+
+
+ void Aggregated::addTerm(const Term* term, scalar degree, const TNorm* implication) {
+ _terms.push_back(Activated(term, degree, implication));
+ FL_DBG("Aggregating " << _terms.back().toString());
+ }
+
+ void Aggregated::addTerm(const Activated& term) {
+ _terms.push_back(term);
+ FL_DBG("Aggregating " << _terms.back().toString());
+ }
+
+ const Activated& Aggregated::removeTerm(std::size_t index) {
+ const Activated& term = _terms.at(index);
+ _terms.erase(_terms.begin() + index);
+ return term;
+ }
+
+ void Aggregated::clear() {
+ _terms.clear();
+ }
+
+ const Activated& Aggregated::getTerm(std::size_t index) const {
+ return _terms.at(index);
+ }
+
+ void Aggregated::setTerms(const std::vector<Activated>& terms) {
+ this->_terms = terms;
+ }
+
+ const std::vector<Activated>& Aggregated::terms() const {
+ return this->_terms;
+ }
+
+ std::vector<Activated>& Aggregated::terms() {
+ return this->_terms;
+ }
+
+ std::size_t Aggregated::numberOfTerms() const {
+ return _terms.size();
+ }
+
+ bool Aggregated::isEmpty() const {
+ return _terms.empty();
+ }
+
+}
diff --git a/fuzzylite/src/term/Bell.cpp b/fuzzylite/src/term/Bell.cpp
new file mode 100644
index 0000000..bd63753
--- /dev/null
+++ b/fuzzylite/src/term/Bell.cpp
@@ -0,0 +1,93 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Bell.h"
+
+namespace fl {
+
+ Bell::Bell(const std::string& name, scalar center, scalar width, scalar slope, scalar height)
+ : Term(name, height), _center(center), _width(width), _slope(slope) { }
+
+ Bell::~Bell() { }
+
+ std::string Bell::className() const {
+ return "Bell";
+ }
+
+ Complexity Bell::complexity() const {
+ return Complexity().comparison(1).arithmetic(6).function(2);
+ }
+
+ scalar Bell::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ return Term::_height * (1.0 / (1.0 + std::pow(std::abs((x - _center) / _width), 2.0 * _slope)));
+ }
+
+ std::string Bell::parameters() const {
+ return Op::join(3, " ", _center, _width, _slope) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Bell::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 3;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setCenter(Op::toScalar(values.at(0)));
+ setWidth(Op::toScalar(values.at(1)));
+ setSlope(Op::toScalar(values.at(2)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Bell::setWidth(scalar a) {
+ this->_width = a;
+ }
+
+ scalar Bell::getWidth() const {
+ return this->_width;
+ }
+
+ void Bell::setSlope(scalar b) {
+ this->_slope = b;
+ }
+
+ scalar Bell::getSlope() const {
+ return this->_slope;
+ }
+
+ void Bell::setCenter(scalar c) {
+ this->_center = c;
+ }
+
+ scalar Bell::getCenter() const {
+ return this->_center;
+ }
+
+ Bell* Bell::clone() const {
+ return new Bell(*this);
+ }
+
+ Term* Bell::constructor() {
+ return new Bell;
+ }
+
+}
diff --git a/fuzzylite/src/term/Binary.cpp b/fuzzylite/src/term/Binary.cpp
new file mode 100644
index 0000000..368530b
--- /dev/null
+++ b/fuzzylite/src/term/Binary.cpp
@@ -0,0 +1,96 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Binary.h"
+
+namespace fl {
+
+ Binary::Binary(const std::string& name, scalar start, scalar direction, scalar height)
+ : Term(name, height), _start(start), _direction(direction) { }
+
+ Binary::~Binary() { }
+
+ std::string Binary::className() const {
+ return "Binary";
+ }
+
+ Complexity Binary::complexity() const {
+ return Complexity().comparison(5).arithmetic(1);
+ }
+
+ scalar Binary::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (_direction > _start and Op::isGE(x, _start)) {
+ return Term::_height * 1.0;
+ }
+ if (_direction < _start and Op::isLE(x, _start)) {
+ return Term::_height * 1.0;
+ }
+ return Term::_height * 0.0;
+ }
+
+ std::string Binary::parameters() const {
+ return Op::join(2, " ", _start, _direction) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Binary::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setDirection(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Binary::setStart(scalar minimum) {
+ this->_start = minimum;
+ }
+
+ scalar Binary::getStart() const {
+ return this->_start;
+ }
+
+ void Binary::setDirection(scalar direction) {
+ this->_direction = direction;
+ }
+
+ scalar Binary::getDirection() const {
+ return this->_direction;
+ }
+
+ Binary::Direction Binary::direction() const {
+ if (this->_direction > _start) return Positive;
+ if (this->_direction < _start) return Negative;
+ return Undefined;
+ }
+
+ Binary* Binary::clone() const {
+ return new Binary(*this);
+ }
+
+ Term* Binary::constructor() {
+ return new Binary;
+ }
+
+}
diff --git a/fuzzylite/src/term/Concave.cpp b/fuzzylite/src/term/Concave.cpp
new file mode 100644
index 0000000..c585edc
--- /dev/null
+++ b/fuzzylite/src/term/Concave.cpp
@@ -0,0 +1,107 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Concave.h"
+
+namespace fl {
+
+ Concave::Concave(const std::string& name, scalar inflection, scalar end, scalar height)
+ : Term(name, height), _inflection(inflection), _end(end) { }
+
+ Concave::~Concave() { }
+
+ std::string Concave::className() const {
+ return "Concave";
+ }
+
+ Complexity Concave::complexity() const {
+ return Complexity().comparison(1 + 3).arithmetic(1 + 5);
+ }
+
+ scalar Concave::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (Op::isLE(_inflection, _end)) { //Concave increasing
+ if (Op::isLt(x, _end)) {
+ return Term::_height * (_end - _inflection) / (2.0 * _end - _inflection - x);
+ }
+ } else { //Concave decreasing
+ if (Op::isGt(x, _end)) {
+ return Term::_height * (_inflection - _end) / (_inflection - 2.0 * _end + x);
+ }
+ }
+ return Term::_height * 1.0;
+ }
+
+ scalar Concave::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const {
+ FL_IUNUSED(minimum);
+ FL_IUNUSED(maximum);
+ scalar i = _inflection;
+ scalar e = _end;
+ return (i - e) / membership(activationDegree) + 2 * e - i;
+ }
+
+ bool Concave::isMonotonic() const {
+ return true;
+ }
+
+ std::string Concave::parameters() const {
+ return Op::join(2, " ", _inflection, _end) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+
+ }
+
+ void Concave::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setInflection(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+
+ }
+
+ void Concave::setInflection(scalar start) {
+ this->_inflection = start;
+ }
+
+ scalar Concave::getInflection() const {
+ return this->_inflection;
+ }
+
+ void Concave::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar Concave::getEnd() const {
+ return this->_end;
+ }
+
+ Concave* Concave::clone() const {
+ return new Concave(*this);
+ }
+
+ Term* Concave::constructor() {
+ return new Concave;
+ }
+
+}
diff --git a/fuzzylite/src/term/Constant.cpp b/fuzzylite/src/term/Constant.cpp
new file mode 100644
index 0000000..7c0422e
--- /dev/null
+++ b/fuzzylite/src/term/Constant.cpp
@@ -0,0 +1,64 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Constant.h"
+
+namespace fl {
+
+ Constant::Constant(const std::string& name, scalar value)
+ : Term(name), _value(value) { }
+
+ Constant::~Constant() { }
+
+ std::string Constant::className() const {
+ return "Constant";
+ }
+
+ Complexity Constant::complexity() const {
+ return Complexity();
+ }
+
+ scalar Constant::membership(scalar x) const {
+ FL_IUNUSED(x);
+ return this->_value;
+ }
+
+ std::string Constant::parameters() const {
+ return Op::str(_value);
+ }
+
+ void Constant::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ setValue(Op::toScalar(parameters));
+ }
+
+ void Constant::setValue(scalar value) {
+ this->_value = value;
+ }
+
+ scalar Constant::getValue() const {
+ return this->_value;
+ }
+
+ Constant* Constant::clone() const {
+ return new Constant(*this);
+ }
+
+ Term* Constant::constructor() {
+ return new Constant;
+ }
+
+}
diff --git a/fuzzylite/src/term/Cosine.cpp b/fuzzylite/src/term/Cosine.cpp
new file mode 100644
index 0000000..78162ea
--- /dev/null
+++ b/fuzzylite/src/term/Cosine.cpp
@@ -0,0 +1,89 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Cosine.h"
+
+namespace fl {
+
+ Cosine::Cosine(const std::string& name, scalar center, scalar width, scalar height)
+ : Term(name, height), _center(center), _width(width) { }
+
+ Cosine::~Cosine() { }
+
+ std::string Cosine::className() const {
+ return "Cosine";
+ }
+
+ std::string Cosine::parameters() const {
+ return Op::join(2, " ", _center, _width) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Cosine::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setCenter(Op::toScalar(values.at(0)));
+ setWidth(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+
+ }
+
+ Complexity Cosine::complexity() const {
+ return Complexity().comparison(3).arithmetic(4 + 1 + 7).function(2);
+ }
+
+ scalar Cosine::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (Op::isLt(x, _center - 0.5 * _width)
+ or Op::isGt(x, _center + 0.5 * _width))
+ return Term::_height * 0.0;
+ const scalar pi = 4.0 * std::atan(1.0);
+ return Term::_height * (0.5 * (1.0 + std::cos(2.0 / _width * pi * (x - _center))));
+ }
+
+ void Cosine::setCenter(scalar center) {
+ this->_center = center;
+ }
+
+ scalar Cosine::getCenter() const {
+ return this->_center;
+ }
+
+ void Cosine::setWidth(scalar width) {
+ this->_width = width;
+ }
+
+ scalar Cosine::getWidth() const {
+ return this->_width;
+ }
+
+ Cosine* Cosine::clone() const {
+ return new Cosine(*this);
+ }
+
+ Term* Cosine::constructor() {
+ return new Cosine;
+ }
+
+}
diff --git a/fuzzylite/src/term/Discrete.cpp b/fuzzylite/src/term/Discrete.cpp
new file mode 100644
index 0000000..9951867
--- /dev/null
+++ b/fuzzylite/src/term/Discrete.cpp
@@ -0,0 +1,230 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Discrete.h"
+
+namespace fl {
+
+ Discrete::Discrete(const std::string& name, const std::vector<Pair>& xy, scalar height)
+ : Term(name, height), _xy(xy) { }
+
+ Discrete::~Discrete() { }
+
+ std::string Discrete::className() const {
+ return "Discrete";
+ }
+
+ bool compare(const Discrete::Pair& a, const Discrete::Pair& b) {
+ return a.first < b.first;
+ }
+
+ void Discrete::sort(std::vector<Pair>& pairs) {
+ std::sort(pairs.begin(), pairs.end(), compare);
+ }
+
+ void Discrete::sort() {
+ std::sort(_xy.begin(), _xy.end(), compare);
+ }
+
+ Complexity Discrete::complexity() const {
+ return Complexity().comparison(1 + 4).arithmetic(1 + 1 + 1).function(1)
+ .function(2 * std::log(scalar(_xy.size())));
+ }
+
+ scalar Discrete::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (_xy.empty())
+ throw Exception("[discrete error] term is empty", FL_AT);
+
+ /* ______________________
+ / \
+ / \
+ ____________/ \____________
+ x[0] x[n-1]
+ */
+
+ if (Op::isLE(x, _xy.front().first))
+ return Term::_height * _xy.front().second;
+ if (Op::isGE(x, _xy.back().first))
+ return Term::_height * _xy.back().second;
+
+ const Pair value(x, fl::nan);
+ typedef std::vector<Discrete::Pair>::const_iterator Bound;
+ //std::lower_bound finds the first number greater than or equal to x
+ Bound lowerBound(std::lower_bound(_xy.begin(), _xy.end(), value, compare));
+
+ //if the lower bound is equal to x
+ if (Op::isEq(x, lowerBound->first)) {
+ return Term::_height * lowerBound->second;
+ }
+ //find the upper bound starting from a copy of lowerBound
+ const Bound upperBound(std::upper_bound(_xy.begin(), _xy.end(), value, compare));
+ --lowerBound; //One arithmetic
+ return Term::_height * Op::scale(x, lowerBound->first, upperBound->first,
+ lowerBound->second, upperBound->second);
+ }
+
+ std::string Discrete::parameters() const {
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < _xy.size(); ++i) {
+ ss << Op::str(_xy.at(i).first) << " " << Op::str(_xy.at(i).second);
+ if (i + 1 < _xy.size()) ss << " ";
+ }
+ if (not Op::isEq(getHeight(), 1.0)) ss << " " << Op::str(getHeight());
+ return ss.str();
+ }
+
+ void Discrete::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> strValues = Op::split(parameters, " ");
+ std::vector<scalar> values(strValues.size());
+ for (std::size_t i = 0; i < strValues.size(); ++i) {
+ values.at(i) = Op::toScalar(strValues.at(i));
+ }
+ if (values.size() % 2 == 0) {
+ setHeight(1.0);
+ } else {
+ setHeight(values.back());
+ values.pop_back();
+ }
+ this->_xy = toPairs(values);
+ }
+
+ void Discrete::setXY(const std::vector<Pair>& xy) {
+ this->_xy = xy;
+ }
+
+ const std::vector<Discrete::Pair>& Discrete::xy() const {
+ return this->_xy;
+ }
+
+ std::vector<Discrete::Pair>& Discrete::xy() {
+ return this->_xy;
+ }
+
+ const Discrete::Pair& Discrete::xy(std::size_t index) const {
+ return this->_xy.at(index);
+ }
+
+ Discrete::Pair& Discrete::xy(std::size_t index) {
+ return this->_xy.at(index);
+ }
+
+ std::vector<scalar> Discrete::x() const {
+ std::vector<scalar> result(_xy.size());
+ for (std::size_t i = 0; i < result.size(); ++i) {
+ result.at(i) = _xy.at(i).first;
+ }
+ return result;
+ }
+
+ std::vector<scalar> Discrete::y() const {
+ std::vector<scalar> result(_xy.size());
+ for (std::size_t i = 0; i < result.size(); ++i) {
+ result.at(i) = _xy.at(i).second;
+ }
+ return result;
+ }
+
+ scalar Discrete::x(std::size_t index) const {
+ return _xy.at(index).first;
+ }
+
+ scalar& Discrete::x(std::size_t index) {
+ return _xy.at(index).first;
+ }
+
+ scalar Discrete::y(std::size_t index) const {
+ return _xy.at(index).second;
+ }
+
+ scalar& Discrete::y(std::size_t index) {
+ return _xy.at(index).second;
+ }
+
+ std::vector<Discrete::Pair> Discrete::toPairs(const std::vector<scalar>& xy) {
+ if (xy.size() % 2 != 0) {
+ std::ostringstream os;
+ os << "[discrete error] missing value in set of pairs (|xy|=" << xy.size() << ")";
+ throw Exception(os.str(), FL_AT);
+ }
+
+ std::vector<Pair> result((xy.size() + 1) / 2);
+ for (std::size_t i = 0; i + 1 < xy.size(); i += 2) {
+ result.at(i / 2).first = xy.at(i);
+ result.at(i / 2).second = xy.at(i + 1);
+ }
+ return result;
+ }
+
+ std::vector<Discrete::Pair> Discrete::toPairs(const std::vector<scalar>& xy,
+ scalar missingValue) FL_INOEXCEPT {
+ std::vector<Pair> result((xy.size() + 1) / 2);
+ for (std::size_t i = 0; i + 1 < xy.size(); i += 2) {
+ result.at(i / 2).first = xy.at(i);
+ result.at(i / 2).second = xy.at(i + 1);
+ }
+ if (xy.size() % 2 != 0) {
+ result.back().first = xy.back();
+ result.back().second = missingValue;
+ }
+ return result;
+ }
+
+ std::vector<scalar> Discrete::toVector(const std::vector<Pair>& xy) {
+ std::vector<scalar> result(xy.size() * 2);
+ for (std::size_t i = 0; i < xy.size(); ++i) {
+ result.at(2 * i) = xy.at(i).first;
+ result.at(2 * i + 1) = xy.at(i).second;
+ }
+ return result;
+ }
+
+ std::string Discrete::formatXY(const std::vector<Pair>& xy, const std::string& prefix,
+ const std::string& innerSeparator, const std::string& suffix, const std::string& outerSeparator) {
+ std::ostringstream os;
+ for (std::size_t i = 0; i < xy.size(); ++i) {
+ os << prefix << Op::str(xy.at(i).first) << innerSeparator
+ << Op::str(xy.at(i).second) << suffix;
+ if (i + 1 < xy.size()) os << outerSeparator;
+ }
+ return os.str();
+ }
+
+ Discrete* Discrete::discretize(const Term* term, scalar start, scalar end, int resolution,
+ bool boundedMembershipFunction) {
+ FL_unique_ptr<Discrete> result(new Discrete(term->getName()));
+ scalar dx = (end - start) / resolution;
+ scalar x, y;
+ for (int i = 0; i <= resolution; ++i) {
+ x = start + i * dx;
+ y = term->membership(x);
+ if (boundedMembershipFunction)
+ y = Op::bound(y, scalar(0.0), scalar(1.0));
+ result->xy().push_back(Discrete::Pair(x, y));
+ }
+ return result.release();
+ }
+
+ Discrete* Discrete::clone() const {
+ return new Discrete(*this);
+ }
+
+ Term* Discrete::constructor() {
+ return new Discrete;
+ }
+
+}
diff --git a/fuzzylite/src/term/Function.cpp b/fuzzylite/src/term/Function.cpp
new file mode 100644
index 0000000..42f4aaa
--- /dev/null
+++ b/fuzzylite/src/term/Function.cpp
@@ -0,0 +1,578 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Function.h"
+
+#include "fl/Engine.h"
+#include "fl/factory/FactoryManager.h"
+#include "fl/rule/Rule.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#include <queue>
+#include <stack>
+
+namespace fl {
+
+ /**
+ * Parsing elements
+ */
+
+
+ Function::Element::Element(const std::string& name, const std::string& description, Type type)
+ : name(name), description(description), type(type), unary(fl::null), binary(fl::null), arity(0),
+ precedence(0), associativity(-1) { }
+
+ Function::Element::Element(const std::string& name, const std::string& description,
+ Type type, Unary unary, int precedence, int associativity)
+ : name(name), description(description), type(type), unary(unary), binary(fl::null), arity(1),
+ precedence(precedence), associativity(associativity) { }
+
+ Function::Element::Element(const std::string& name, const std::string& description,
+ Type type, Binary binary, int precedence, int associativity)
+ : name(name), description(description), type(type), unary(fl::null), binary(binary), arity(2),
+ precedence(precedence), associativity(associativity) { }
+
+ Function::Element::~Element() { }
+
+ bool Function::Element::isOperator() const {
+ return type == Operator;
+ }
+
+ bool Function::Element::isFunction() const {
+ return type == Function;
+ }
+
+ Function::Element* Function::Element::clone() const {
+ return new Element(*this);
+ }
+
+ std::string Function::Element::toString() const {
+ std::ostringstream ss;
+
+ if (type == Operator) {
+ ss << "Operator (name=" << name << ", "
+ << "description=" << description << ", "
+ << "precedence=" << precedence << ", "
+ << "arity=" << arity << ", "
+ << "associativity=" << associativity << ", ";
+ if (arity == 1) ss << "pointer=" << unary;
+ else if (arity == 2) ss << "pointer=" << binary;
+ else ss << "pointer=error";
+ ss << ")";
+ } else if (type == Function) {
+ ss << "Function (name=" << name << ", "
+ << "description=" << description << ", "
+ << "arity=" << arity << ", "
+ << "associativity=" << associativity << ", ";
+ if (arity == 1) ss << "pointer=" << unary;
+ else if (arity == 2) ss << "pointer=" << binary;
+ else ss << "pointer=error";
+ ss << ")";
+ }
+ return ss.str();
+ }
+
+ /******************************
+ * Tree Node Elements
+ ******************************/
+
+ Function::Node::Node(Element* element, Node* left, Node* right)
+ : element(element), left(left), right(right), variable(""), value(fl::nan) { }
+
+ Function::Node::Node(const std::string& variable)
+ : element(fl::null), left(fl::null), right(fl::null), variable(variable), value(fl::nan) { }
+
+ Function::Node::Node(scalar value)
+ : element(fl::null), left(fl::null), right(fl::null), variable(""), value(value) { }
+
+ Function::Node::Node(const Node& other)
+ : element(fl::null), left(fl::null), right(fl::null), variable(""), value(fl::nan) {
+ copyFrom(other);
+ }
+
+ Function::Node& Function::Node::operator=(const Node& other) {
+ if (this != &other) {
+ element.reset(fl::null);
+ left.reset(fl::null);
+ right.reset(fl::null);
+
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ void Function::Node::copyFrom(const Node& other) {
+ if (other.element.get()) element.reset(other.element->clone());
+ if (other.left.get()) left.reset(other.left->clone());
+ if (other.right.get()) right.reset(other.right->clone());
+ variable = other.variable;
+ value = other.value;
+ }
+
+ Function::Node::~Node() { }
+
+ scalar Function::Node::evaluate(const std::map<std::string, scalar>* variables) const {
+ scalar result = fl::nan;
+ if (element.get()) {
+ if (element->unary) {
+ result = element->unary(left->evaluate(variables));
+ } else if (element->binary) {
+ result = element->binary(right->evaluate(variables), left->evaluate(variables));
+ } else {
+ std::ostringstream ex;
+ ex << "[function error] arity <" << element->arity << "> of "
+ << (element->isOperator() ? "operator" : "function") <<
+ " <" << element->name << "> is fl::null";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ } else if (not variable.empty()) {
+ if (not variables) {
+ throw Exception("[function error] "
+ "expected a map of variables, but none was provided", FL_AT);
+ }
+ std::map<std::string, scalar>::const_iterator it = variables->find(variable);
+ if (it != variables->end()) result = it->second;
+ else throw Exception("[function error] "
+ "unknown variable <" + variable + ">", FL_AT);
+ } else {
+ result = value;
+ }
+ return result;
+ }
+
+ std::size_t Function::Node::treeSize(const Node* root) const {
+ if (not root) root = this;
+ std::size_t result = 0;
+ if (root->left.get()) {
+ result += treeSize(root->left.get());
+ }
+ if (root->right.get()) {
+ result += treeSize(root->right.get());
+ }
+ if (root->element.get()) {
+ result += 1;
+ }
+ return result;
+ }
+
+ std::size_t Function::Node::treeSize(Element::Type type, const Node* root) const {
+ if (not root) root = this;
+ std::size_t result = 0;
+ if (root->left.get()) {
+ result += treeSize(type, root->left.get());
+ }
+ if (root->right.get()) {
+ result += treeSize(type, root->right.get());
+ }
+ if (root->element.get() and root->element->type == type) {
+ result += 1;
+ }
+ return result;
+ }
+
+ Function::Node* Function::Node::clone() const {
+ return new Node(*this);
+ }
+
+ std::string Function::Node::toString() const {
+ std::ostringstream ss;
+ if (element.get()) ss << element->name;
+ else if (not variable.empty()) ss << variable;
+ else ss << Op::str(value);
+ return ss.str();
+ }
+
+ std::string Function::Node::toPrefix(const Node* node) const {
+ if (not node) node = this;
+ if (not Op::isNaN(node->value)) { //is terminal
+ return Op::str(node->value);
+ }
+ if (not node->variable.empty()) {
+ return node->variable;
+ }
+
+ std::ostringstream ss;
+ ss << node->toString();
+ if (node->left.get())
+ ss << " " << this->toPrefix(node->left.get());
+ if (node->right.get())
+ ss << " " << this->toPrefix(node->right.get());
+ return ss.str();
+ }
+
+ std::string Function::Node::toInfix(const Node* node) const {
+ if (not node) node = this;
+ if (not Op::isNaN(node->value)) { //is proposition
+ return Op::str(node->value);
+ }
+ if (not node->variable.empty()) {
+ return node->variable;
+ }
+
+ std::ostringstream ss;
+ if (node->left.get())
+ ss << this->toInfix(node->left.get()) << " ";
+ ss << node->toString();
+ if (node->right.get())
+ ss << " " << this->toInfix(node->right.get());
+ return ss.str();
+ }
+
+ std::string Function::Node::toPostfix(const Node* node) const {
+ if (not node) node = this;
+ if (not Op::isNaN(node->value)) { //is proposition
+ return Op::str(node->value);
+ }
+ if (not node->variable.empty()) {
+ return node->variable;
+ }
+
+ std::ostringstream ss;
+ if (node->left.get())
+ ss << this->toPostfix(node->left.get()) << " ";
+ if (node->right.get())
+ ss << this->toPostfix(node->right.get()) << " ";
+ ss << node->toString();
+ return ss.str();
+ }
+
+ /**********************************
+ * Function class.
+ **********************************/
+ Function::Function(const std::string& name,
+ const std::string& formula, const Engine* engine)
+ : Term(name), _root(fl::null), _formula(formula), _engine(engine) { }
+
+ Function::Function(const Function& other) : Term(other),
+ _root(fl::null), _formula(other._formula), _engine(other._engine) {
+ if (other._root.get()) _root.reset(other._root->clone());
+ variables = other.variables;
+ }
+
+ Function& Function::operator=(const Function& other) {
+ if (this != &other) {
+ _root.reset(fl::null);
+
+ Term::operator=(other);
+ _formula = other._formula;
+ _engine = other._engine;
+ if (other._root.get()) _root.reset(other._root->clone());
+ variables = other.variables;
+ }
+ return *this;
+ }
+
+ Function::~Function() { }
+
+ std::string Function::className() const {
+ return "Function";
+ }
+
+ Complexity Function::complexity() const {
+ Complexity result;
+ result.comparison(2 + 2); //membership(scalar) + membership(std::map)
+ if (_engine) { //insert variables in map
+ const std::size_t engineVariables = _engine->variables().size();
+ result.function(engineVariables * std::log(scalar(variables.size() + engineVariables)));
+ result.function(1 * std::log(scalar(variables.size() + engineVariables)));
+ }
+ if (_root.get()) {
+ //Node::evaluate multiplies by tree size
+ const scalar treeSize = scalar(_root->treeSize());
+ result.comparison(3 * treeSize); //if element, unary, binary
+ result.function(treeSize * std::log(treeSize)); //only operands in tree
+ }
+ return result;
+ }
+
+ scalar Function::membership(scalar x) const {
+ if (not _root.get()) {
+ throw Exception("[function error] function <" + _formula + "> not loaded.", FL_AT);
+ }
+ if (_engine) {
+ for (std::size_t i = 0; i < _engine->numberOfInputVariables(); ++i) {
+ InputVariable* input = _engine->getInputVariable(i);
+ this->variables[input->getName()] = input->getValue();
+ }
+ for (std::size_t i = 0; i < _engine->numberOfOutputVariables(); ++i) {
+ OutputVariable* output = _engine->getOutputVariable(i);
+ this->variables[output->getName()] = output->getValue();
+ }
+ }
+ this->variables["x"] = x;
+ return this->evaluate(&this->variables);
+ }
+
+ scalar Function::evaluate(const std::map<std::string, scalar>* localVariables) const {
+ if (not _root.get())
+ throw Exception("[function error] evaluation failed because the function is not loaded", FL_AT);
+ if (localVariables)
+ return _root->evaluate(localVariables);
+ return _root->evaluate(&this->variables);
+ }
+
+ std::string Function::parameters() const {
+ return getFormula();
+ }
+
+ void Function::configure(const std::string& parameters) {
+ load(parameters);
+ }
+
+ Function* Function::create(const std::string& name,
+ const std::string& infix, const Engine* engine) {
+ FL_unique_ptr<Function> result(new Function(name));
+ result->load(infix, engine);
+ return result.release();
+ }
+
+ bool Function::isLoaded() const {
+ return this->_root.get() != fl::null;
+ }
+
+ void Function::unload() {
+ this->_root.reset(fl::null);
+ this->variables.clear();
+ }
+
+ void Function::load() {
+ load(getFormula());
+ }
+
+ void Function::load(const std::string& formula) {
+ load(formula, getEngine());
+ }
+
+ void Function::load(const std::string& formula,
+ const Engine* engine) {
+ setFormula(formula);
+ setEngine(engine);
+ this->_root.reset(parse(formula));
+ membership(0.0); //make sure function evaluates without throwing exception.
+ }
+
+ void Function::setFormula(const std::string& formula) {
+ this->_formula = formula;
+ }
+
+ std::string Function::getFormula() const {
+ return this->_formula;
+ }
+
+ void Function::setEngine(const Engine* engine) {
+ this->_engine = engine;
+ }
+
+ const Engine* Function::getEngine() const {
+ return this->_engine;
+ }
+
+ Function::Node* Function::root() const {
+ return this->_root.get();
+ }
+
+ Function* Function::clone() const {
+ return new Function(*this);
+ }
+
+ Term* Function::constructor() {
+ return new Function;
+ }
+
+ void Function::updateReference(const Engine* engine) {
+ setEngine(engine);
+ try {
+ load();
+ } catch (...) {
+ //ignore
+ }
+ }
+
+ std::string Function::space(const std::string& formula) const {
+ std::vector<std::string> chars;
+ chars.push_back("(");
+ chars.push_back(")");
+ chars.push_back(",");
+
+ std::vector<std::string> operators = FactoryManager::instance()->function()->availableOperators();
+ for (std::size_t i = 0; i < operators.size(); ++i) {
+ if (not (operators.at(i) == Rule::andKeyword() or
+ operators.at(i) == Rule::orKeyword())) {
+ chars.push_back(operators.at(i));
+ }
+ }
+
+ std::string result = formula;
+ for (std::size_t i = 0; i < chars.size(); ++i) {
+ result = Op::findReplace(result, chars.at(i), " " + chars.at(i) + " ");
+ }
+ return result;
+ }
+
+ /****************************************
+ * The Glorious Parser
+ * Shunting-yard algorithm
+ * @todo: maybe change it for http://en.wikipedia.org/wiki/Operator-precedence_parser
+ ***************************************/
+
+ std::string Function::toPostfix(const std::string& formula) const {
+ std::string spacedFormula = space(formula);
+
+ std::queue<std::string> queue;
+ std::stack<std::string> stack;
+
+ std::stringstream tokenizer(spacedFormula);
+ std::string token;
+ FunctionFactory* factory = FactoryManager::instance()->function();
+ while (tokenizer >> token) {
+ Element* element = factory->getObject(token);
+ bool isOperand = not element and token != "(" and token != ")" and token != ",";
+
+ if (isOperand) {
+ queue.push(token);
+
+ } else if (element and element->isFunction()) {
+ stack.push(token);
+
+ } else if (token == ",") {
+ while (not stack.empty() and stack.top() != "(") {
+ queue.push(stack.top());
+ stack.pop();
+ }
+ if (stack.empty() or stack.top() != "(") {
+ std::ostringstream ex;
+ ex << "[parsing error] mismatching parentheses in: " << formula;
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ } else if (element and element->isOperator()) {
+ Element* op1 = element;
+ for (;;) {
+ Element* op2 = fl::null;
+ if (not stack.empty()) op2 = factory->getObject(stack.top());
+ if (not op2) break;
+
+ if ((op1->associativity < 0 and op1->precedence == op2->precedence)
+ or op1->precedence < op2->precedence) {
+ queue.push(stack.top());
+ stack.pop();
+ } else
+ break;
+ }
+ stack.push(token);
+
+ } else if (token == "(") {
+ stack.push(token);
+
+ } else if (token == ")") {
+ while (not stack.empty() and stack.top() != "(") {
+ queue.push(stack.top());
+ stack.pop();
+ }
+ if (stack.empty() or stack.top() != "(") {
+ std::ostringstream ex;
+ ex << "[parsing error] mismatching parentheses in: " << formula;
+ throw Exception(ex.str(), FL_AT);
+ }
+ stack.pop(); //get rid of "("
+
+ Element* top = fl::null;
+ if (not stack.empty()) top = factory->getObject(stack.top());
+ if (top and top->isFunction()) {
+ queue.push(stack.top());
+ stack.pop();
+ }
+ } else {
+ std::ostringstream ex;
+ ex << "[parsing error] unexpected error with token <" << token << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+ }
+
+ while (not stack.empty()) {
+ if (stack.top() == "(" or stack.top() == ")") {
+ std::ostringstream ex;
+ ex << "[parsing error] mismatching parentheses in: " << formula;
+ throw Exception(ex.str(), FL_AT);
+ }
+ queue.push(stack.top());
+ stack.pop();
+ }
+
+ std::stringstream ssPostfix;
+ while (not queue.empty()) {
+ ssPostfix << queue.front();
+ queue.pop();
+ if (not queue.empty()) ssPostfix << " ";
+ }
+ return ssPostfix.str();
+ }
+
+ Function::Node* Function::parse(const std::string& formula) {
+ if (formula.empty())
+ throw Exception("[function error] formula is empty", FL_AT);
+ std::string postfix = toPostfix(formula);
+
+ std::stack<Node*> stack;
+
+ std::istringstream tokenizer(postfix);
+ std::string token;
+ FunctionFactory* factory = FactoryManager::instance()->function();
+ while (tokenizer >> token) {
+ Element* element = factory->getObject(token);
+ bool isOperand = not element and token != "(" and token != ")" and token != ",";
+
+ if (element) {
+ if (element->arity > static_cast<int> (stack.size())) {
+ std::ostringstream ss;
+ ss << "[function error] " << (element->isOperator() ? "operator" : "function") <<
+ " <" << element->name << "> has arity <" << element->arity << ">, "
+ "but found <" << stack.size() << "> element" <<
+ (stack.size() == 1 ? "" : "s");
+ throw Exception(ss.str(), FL_AT);
+ }
+
+ Node* node = new Node(element->clone());
+ node->left.reset(stack.top());
+ stack.pop();
+ if (element->arity == 2) {
+ node->right.reset(stack.top());
+ stack.pop();
+ }
+ stack.push(node);
+
+ } else if (isOperand) {
+ Node* node;
+ try {
+ scalar value = Op::toScalar(token);
+ node = new Node(value);
+ } catch (std::exception& ex) {
+ FL_IUNUSED(ex);
+ node = new Node(token);
+ }
+ stack.push(node);
+ }
+ }
+
+ if (stack.size() != 1)
+ throw Exception("[function error] ill-formed formula <" + formula + ">", FL_AT);
+
+ return stack.top();
+ }
+
+}
diff --git a/fuzzylite/src/term/Gaussian.cpp b/fuzzylite/src/term/Gaussian.cpp
new file mode 100644
index 0000000..8413b59
--- /dev/null
+++ b/fuzzylite/src/term/Gaussian.cpp
@@ -0,0 +1,86 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Gaussian.h"
+
+namespace fl {
+
+ Gaussian::Gaussian(const std::string& name,
+ scalar mean, scalar standardDeviation, scalar height)
+ : Term(name, height), _mean(mean), _standardDeviation(standardDeviation) { }
+
+ Gaussian::~Gaussian() { }
+
+ std::string Gaussian::className() const {
+ return "Gaussian";
+ }
+
+ Complexity Gaussian::complexity() const {
+ return Complexity().comparison(1).arithmetic(7).function(1);
+ }
+
+ scalar Gaussian::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ return Term::_height * std::exp((-(x - _mean) * (x - _mean)) / (2.0 * _standardDeviation * _standardDeviation));
+ }
+
+ std::string Gaussian::parameters() const {
+ return Op::join(2, " ", _mean, _standardDeviation) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Gaussian::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setMean(Op::toScalar(values.at(0)));
+ setStandardDeviation(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Gaussian::setMean(scalar mean) {
+ this->_mean = mean;
+ }
+
+ scalar Gaussian::getMean() const {
+ return this->_mean;
+ }
+
+ void Gaussian::setStandardDeviation(scalar standardDeviation) {
+ this->_standardDeviation = standardDeviation;
+ }
+
+ scalar Gaussian::getStandardDeviation() const {
+ return this->_standardDeviation;
+ }
+
+ Gaussian* Gaussian::clone() const {
+ return new Gaussian(*this);
+ }
+
+ Term* Gaussian::constructor() {
+ return new Gaussian;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/GaussianProduct.cpp b/fuzzylite/src/term/GaussianProduct.cpp
new file mode 100644
index 0000000..791790c
--- /dev/null
+++ b/fuzzylite/src/term/GaussianProduct.cpp
@@ -0,0 +1,117 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/GaussianProduct.h"
+
+namespace fl {
+
+ GaussianProduct::GaussianProduct(const std::string& name,
+ scalar meanA, scalar standardDeviationA, scalar meanB, scalar standardDeviationB,
+ scalar height)
+ : Term(name, height), _meanA(meanA), _standardDeviationA(standardDeviationA),
+ _meanB(meanB), _standardDeviationB(standardDeviationB) { }
+
+ GaussianProduct::~GaussianProduct() { }
+
+ std::string GaussianProduct::className() const {
+ return "GaussianProduct";
+ }
+
+ Complexity GaussianProduct::complexity() const {
+ return Complexity().comparison(1 + 2).arithmetic(9 + 9 + 2).function(2);
+ }
+
+ scalar GaussianProduct::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ scalar a = 1.0, b = 1.0;
+ if (Op::isLt(x, _meanA)) {
+ a = std::exp((-(x - _meanA) * (x - _meanA)) /
+ (2.0 * _standardDeviationA * _standardDeviationA));
+ }
+ if (Op::isGt(x, _meanB)) {
+ b = std::exp((-(x - _meanB) * (x - _meanB)) /
+ (2.0 * _standardDeviationB * _standardDeviationB));
+ }
+
+ return Term::_height * a * b;
+ }
+
+ std::string GaussianProduct::parameters() const {
+ return Op::join(4, " ", _meanA, _standardDeviationA, _meanB, _standardDeviationB) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void GaussianProduct::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setMeanA(Op::toScalar(values.at(0)));
+ setStandardDeviationA(Op::toScalar(values.at(1)));
+ setMeanB(Op::toScalar(values.at(2)));
+ setStandardDeviationB(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void GaussianProduct::setMeanA(scalar meanA) {
+ this->_meanA = meanA;
+ }
+
+ scalar GaussianProduct::getMeanA() const {
+ return this->_meanA;
+ }
+
+ void GaussianProduct::setStandardDeviationA(scalar sigmaA) {
+ this->_standardDeviationA = sigmaA;
+ }
+
+ scalar GaussianProduct::getStandardDeviationA() const {
+ return this->_standardDeviationA;
+ }
+
+ void GaussianProduct::setMeanB(scalar meanB) {
+ this->_meanB = meanB;
+ }
+
+ scalar GaussianProduct::getMeanB() const {
+ return this->_meanB;
+ }
+
+ void GaussianProduct::setStandardDeviationB(scalar sigmaB) {
+ this->_standardDeviationB = sigmaB;
+ }
+
+ scalar GaussianProduct::getStandardDeviationB() const {
+ return this->_standardDeviationB;
+ }
+
+ GaussianProduct* GaussianProduct::clone() const {
+ return new GaussianProduct(*this);
+ }
+
+ Term* GaussianProduct::constructor() {
+ return new GaussianProduct;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/Linear.cpp b/fuzzylite/src/term/Linear.cpp
new file mode 100644
index 0000000..e6efb43
--- /dev/null
+++ b/fuzzylite/src/term/Linear.cpp
@@ -0,0 +1,115 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Linear.h"
+
+#include "fl/variable/InputVariable.h"
+
+namespace fl {
+
+ Linear::Linear(const std::string& name,
+ const std::vector<scalar>& coefficients,
+ const Engine* engine)
+ : Term(name), _coefficients(coefficients), _engine(engine) { }
+
+ Linear::~Linear() { }
+
+ std::string Linear::className() const {
+ return "Linear";
+ }
+
+ Complexity Linear::complexity() const {
+ Complexity result;
+ result.comparison(1 + 1);
+ if (_engine) {
+ result.arithmetic(scalar(_engine->variables().size()));
+ result.comparison(scalar(_engine->variables().size())); //if (i < coefficients)
+ }
+ return result;
+ }
+
+ scalar Linear::membership(scalar x) const {
+ FL_IUNUSED(x);
+ if (not _engine)
+ throw Exception("[linear error] term <" + getName() + "> "
+ "is missing a reference to the engine", FL_AT);
+
+ scalar result = 0.0;
+ const std::size_t numberOfInputVariables = _engine->inputVariables().size();
+ const std::size_t numberOfCoefficients = _coefficients.size();
+ for (std::size_t i = 0; i < numberOfInputVariables; ++i) {
+ if (i < numberOfCoefficients)
+ result += _coefficients.at(i) * _engine->inputVariables().at(i)->getValue();
+ }
+ if (numberOfCoefficients > numberOfInputVariables) {
+ result += _coefficients.back();
+ }
+ return result;
+ }
+
+ void Linear::set(const std::vector<scalar>& coefficients, const Engine* engine) {
+ setCoefficients(coefficients);
+ setEngine(engine);
+ }
+
+ void Linear::setCoefficients(const std::vector<scalar>& coefficients) {
+ this->_coefficients = coefficients;
+ }
+
+ const std::vector<scalar>& Linear::coefficients() const {
+ return this->_coefficients;
+ }
+
+ std::vector<scalar>& Linear::coefficients() {
+ return this->_coefficients;
+ }
+
+ void Linear::setEngine(const Engine* engine) {
+ this->_engine = engine;
+ }
+
+ const Engine* Linear::getEngine() const {
+ return this->_engine;
+ }
+
+ std::string Linear::parameters() const {
+ return Op::join(this->_coefficients, " ");
+ }
+
+ void Linear::configure(const std::string& parameters) {
+ this->_coefficients.clear();
+ if (parameters.empty()) return;
+ std::vector<std::string> strValues = Op::split(parameters, " ");
+ std::vector<scalar> values;
+ for (std::size_t i = 0; i < strValues.size(); ++i) {
+ values.push_back(Op::toScalar(strValues.at(i)));
+ }
+ this->_coefficients = values;
+ }
+
+ Linear* Linear::clone() const {
+ return new Linear(*this);
+ }
+
+ void Linear::updateReference(const Engine* engine) {
+ setEngine(engine);
+ }
+
+ Term* Linear::constructor() {
+ return new Linear;
+ }
+
+}
diff --git a/fuzzylite/src/term/PiShape.cpp b/fuzzylite/src/term/PiShape.cpp
new file mode 100644
index 0000000..6c91f54
--- /dev/null
+++ b/fuzzylite/src/term/PiShape.cpp
@@ -0,0 +1,123 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/PiShape.h"
+
+namespace fl {
+
+ PiShape::PiShape(const std::string& name, scalar bottomLeft, scalar topLeft,
+ scalar topRight, scalar bottomRight, scalar height)
+ : Term(name, height), _bottomLeft(bottomLeft), _topLeft(topLeft),
+ _topRight(topRight), _bottomRight(bottomRight) { }
+
+ PiShape::~PiShape() { }
+
+ std::string PiShape::className() const {
+ return "PiShape";
+ }
+
+ Complexity PiShape::complexity() const {
+ return Complexity().comparison(1 + 6).arithmetic(1 + 5 + 5).function(1 + 1);
+ }
+
+ scalar PiShape::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ scalar sshape;
+ if (Op::isLE(x, _bottomLeft))
+ sshape = 0.0;
+ else if (Op::isLE(x, 0.5 * (_bottomLeft + _topLeft)))
+ sshape = 2.0 * std::pow((x - _bottomLeft) / (_topLeft - _bottomLeft), 2);
+ else if (Op::isLt(x, _topLeft))
+ sshape = 1.0 - 2.0 * std::pow((x - _topLeft) / (_topLeft - _bottomLeft), 2);
+ else sshape = 1.0;
+
+ scalar zshape;
+ if (Op::isLE(x, _topRight))
+ zshape = 1.0;
+ else if (Op::isLE(x, 0.5 * (_topRight + _bottomRight)))
+ zshape = 1.0 - 2.0 * std::pow((x - _topRight) / (_bottomRight - _topRight), 2);
+ else if (Op::isLt(x, _bottomRight))
+ zshape = 2.0 * std::pow((x - _bottomRight) / (_bottomRight - _topRight), 2);
+ else zshape = 0.0;
+
+ return Term::_height * sshape * zshape;
+ }
+
+ std::string PiShape::parameters() const {
+ return Op::join(4, " ", _bottomLeft, _topLeft, _topRight, _bottomRight) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void PiShape::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setBottomLeft(Op::toScalar(values.at(0)));
+ setTopLeft(Op::toScalar(values.at(1)));
+ setTopRight(Op::toScalar(values.at(2)));
+ setBottomRight(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void PiShape::setBottomLeft(scalar a) {
+ this->_bottomLeft = a;
+ }
+
+ scalar PiShape::getBottomLeft() const {
+ return this->_bottomLeft;
+ }
+
+ void PiShape::setTopLeft(scalar b) {
+ this->_topLeft = b;
+ }
+
+ scalar PiShape::getTopLeft() const {
+ return this->_topLeft;
+ }
+
+ void PiShape::setTopRight(scalar d) {
+ this->_topRight = d;
+ }
+
+ scalar PiShape::getTopRight() const {
+ return this->_topRight;
+ }
+
+ void PiShape::setBottomRight(scalar c) {
+ this->_bottomRight = c;
+ }
+
+ scalar PiShape::getBottomRight() const {
+ return this->_bottomRight;
+ }
+
+ PiShape* PiShape::clone() const {
+ return new PiShape(*this);
+ }
+
+ Term* PiShape::constructor() {
+ return new PiShape;
+ }
+
+}
diff --git a/fuzzylite/src/term/Ramp.cpp b/fuzzylite/src/term/Ramp.cpp
new file mode 100644
index 0000000..d29233d
--- /dev/null
+++ b/fuzzylite/src/term/Ramp.cpp
@@ -0,0 +1,119 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Ramp.h"
+
+namespace fl {
+
+ Ramp::Ramp(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) { }
+
+ Ramp::~Ramp() { }
+
+ std::string Ramp::className() const {
+ return "Ramp";
+ }
+
+ Complexity Ramp::complexity() const {
+ return Complexity().comparison(1 + 4).arithmetic(1 + 3);
+ }
+
+ scalar Ramp::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ if (Op::isEq(_start, _end))
+ return Term::_height * 0.0;
+
+ if (Op::isLt(_start, _end)) {
+ if (Op::isLE(x, _start))
+ return Term::_height * 0.0;
+ if (Op::isGE(x, _end))
+ return Term::_height * 1.0;
+ return Term::_height * (x - _start) / (_end - _start);
+ } else {
+ if (Op::isGE(x, _start))
+ return Term::_height * 0.0;
+ if (Op::isLE(x, _end))
+ return Term::_height * 1.0;
+ return Term::_height * (_start - x) / (_start - _end);
+ }
+ }
+
+ scalar Ramp::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const {
+ FL_IUNUSED(minimum);
+ FL_IUNUSED(maximum);
+ return Op::scale(activationDegree, 0, 1, _start, _end);
+ }
+
+ bool Ramp::isMonotonic() const {
+ return true;
+ }
+
+ std::string Ramp::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Ramp::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Ramp::setStart(scalar start) {
+ this->_start = start;
+ }
+
+ scalar Ramp::getStart() const {
+ return this->_start;
+ }
+
+ void Ramp::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar Ramp::getEnd() const {
+ return this->_end;
+ }
+
+ Ramp::Direction Ramp::direction() const {
+ scalar range = this->_end - this->_start;
+ if (not Op::isFinite(range) or Op::isEq(range, 0.0)) return Zero;
+
+ if (Op::isGt(range, 0.0)) return Positive;
+
+ return Negative;
+ }
+
+ Ramp* Ramp::clone() const {
+ return new Ramp(*this);
+ }
+
+ Term* Ramp::constructor() {
+ return new Ramp;
+ }
+
+}
diff --git a/fuzzylite/src/term/Rectangle.cpp b/fuzzylite/src/term/Rectangle.cpp
new file mode 100644
index 0000000..4f975d0
--- /dev/null
+++ b/fuzzylite/src/term/Rectangle.cpp
@@ -0,0 +1,87 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Rectangle.h"
+
+namespace fl {
+
+ Rectangle::Rectangle(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) { }
+
+ Rectangle::~Rectangle() { }
+
+ std::string Rectangle::className() const {
+ return "Rectangle";
+ }
+
+ Complexity Rectangle::complexity() const {
+ return Complexity().comparison(1 + 2).arithmetic(1);
+ }
+
+ scalar Rectangle::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ if (Op::isGE(x, _start) and Op::isLE(x, _end))
+ return Term::_height * 1.0;
+ return Term::_height * 0.0;
+ }
+
+ std::string Rectangle::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Rectangle::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Rectangle::setStart(scalar minimum) {
+ this->_start = minimum;
+ }
+
+ scalar Rectangle::getStart() const {
+ return this->_start;
+ }
+
+ void Rectangle::setEnd(scalar maximum) {
+ this->_end = maximum;
+ }
+
+ scalar Rectangle::getEnd() const {
+ return this->_end;
+ }
+
+ Rectangle* Rectangle::clone() const {
+ return new Rectangle(*this);
+ }
+
+ Term* Rectangle::constructor() {
+ return new Rectangle;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/SShape.cpp b/fuzzylite/src/term/SShape.cpp
new file mode 100644
index 0000000..65dfd2b
--- /dev/null
+++ b/fuzzylite/src/term/SShape.cpp
@@ -0,0 +1,116 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/SShape.h"
+
+namespace fl {
+
+ SShape::SShape(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) { }
+
+ SShape::~SShape() { }
+
+ std::string SShape::className() const {
+ return "SShape";
+ }
+
+ Complexity SShape::complexity() const {
+ return Complexity().comparison(1 + 3).arithmetic(1 + 3 + 4).function(1);
+ }
+
+ scalar SShape::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ if (Op::isLE(x, _start))
+ return Term::_height * 0.0;
+
+ if (Op::isLE(x, 0.5 * (_start + _end)))
+ return Term::_height * (2.0 * std::pow((x - _start) / (_end - _start), 2));
+
+ if (Op::isLt(x, _end))
+ return Term::_height * (1.0 - 2.0 * std::pow((x - _end) / (_end - _start), 2));
+
+ return Term::_height * 1.0;
+ }
+
+ scalar SShape::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const {
+ FL_IUNUSED(minimum);
+ FL_IUNUSED(maximum);
+
+ scalar w = activationDegree;
+ scalar z = fl::nan;
+
+ scalar difference = _end - _start;
+ scalar a = _start + std::sqrt(0.5 * w * difference * difference);
+ scalar b = _end + std::sqrt(-0.5 * (w - 1.0) * difference * difference);
+ if (std::abs(w - membership(a)) < std::abs(w - membership(b))) {
+ z = a;
+ } else {
+ z = b;
+ }
+ return z;
+ }
+
+ bool SShape::isMonotonic() const {
+ return true;
+ }
+
+ std::string SShape::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void SShape::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void SShape::setStart(scalar start) {
+ this->_start = start;
+ }
+
+ scalar SShape::getStart() const {
+ return this->_start;
+ }
+
+ void SShape::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar SShape::getEnd() const {
+ return this->_end;
+ }
+
+ SShape* SShape::clone() const {
+ return new SShape(*this);
+ }
+
+ Term* SShape::constructor() {
+ return new SShape;
+ }
+
+}
diff --git a/fuzzylite/src/term/Sigmoid.cpp b/fuzzylite/src/term/Sigmoid.cpp
new file mode 100644
index 0000000..fcf165e
--- /dev/null
+++ b/fuzzylite/src/term/Sigmoid.cpp
@@ -0,0 +1,124 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Sigmoid.h"
+
+namespace fl {
+
+ Sigmoid::Sigmoid(const std::string& name, scalar inflection, scalar slope, scalar height)
+ : Term(name, height), _inflection(inflection), _slope(slope) { }
+
+ Sigmoid::~Sigmoid() { }
+
+ std::string Sigmoid::className() const {
+ return "Sigmoid";
+ }
+
+ Complexity Sigmoid::complexity() const {
+ return Complexity().comparison(1).arithmetic(1 + 4).function(1);
+ }
+
+ scalar Sigmoid::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ return Term::_height * 1.0 / (1.0 + std::exp(-_slope * (x - _inflection)));
+ }
+
+ scalar Sigmoid::tsukamoto(scalar activationDegree,
+ scalar minimum, scalar maximum) const {
+
+ scalar w = activationDegree;
+ scalar z = fl::nan;
+
+ if (Op::isEq(w, 1.0)) {
+ if (Op::isGE(_slope, 0.0)) {
+ z = maximum;
+ } else {
+ z = minimum;
+ }
+
+ } else if (Op::isEq(w, 0.0)) {
+ if (Op::isGE(_slope, 0.0)) {
+ z = minimum;
+ } else {
+ z = maximum;
+ }
+ } else {
+ scalar a = _slope;
+ scalar b = _inflection;
+ z = b + (std::log(1.0 / w - 1.0) / -a);
+ }
+
+ return z;
+ }
+
+ bool Sigmoid::isMonotonic() const {
+ return true;
+ }
+
+ std::string Sigmoid::parameters() const {
+ return Op::join(2, " ", _inflection, _slope) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Sigmoid::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setInflection(Op::toScalar(values.at(0)));
+ setSlope(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Sigmoid::setSlope(scalar a) {
+ this->_slope = a;
+ }
+
+ scalar Sigmoid::getSlope() const {
+ return this->_slope;
+ }
+
+ void Sigmoid::setInflection(scalar c) {
+ this->_inflection = c;
+ }
+
+ scalar Sigmoid::getInflection() const {
+ return this->_inflection;
+ }
+
+ Sigmoid::Direction Sigmoid::direction() const {
+ if (not Op::isFinite(_slope) or Op::isEq(_slope, 0.0)) return Zero;
+
+ if (Op::isGt(_slope, 0.0)) return Positive;
+
+ return Negative;
+ }
+
+ Sigmoid* Sigmoid::clone() const {
+ return new Sigmoid(*this);
+ }
+
+ Term* Sigmoid::constructor() {
+ return new Sigmoid;
+ }
+
+}
diff --git a/fuzzylite/src/term/SigmoidDifference.cpp b/fuzzylite/src/term/SigmoidDifference.cpp
new file mode 100644
index 0000000..8f7ee80
--- /dev/null
+++ b/fuzzylite/src/term/SigmoidDifference.cpp
@@ -0,0 +1,108 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/SigmoidDifference.h"
+
+namespace fl {
+
+ SigmoidDifference::SigmoidDifference(const std::string& name,
+ scalar left, scalar rising,
+ scalar falling, scalar right, scalar height)
+ : Term(name, height), _left(left), _rising(rising), _falling(falling), _right(right) { }
+
+ SigmoidDifference::~SigmoidDifference() { }
+
+ std::string SigmoidDifference::className() const {
+ return "SigmoidDifference";
+ }
+
+ Complexity SigmoidDifference::complexity() const {
+ return Complexity().comparison(1).arithmetic(2 + 4 + 4).function(2 + 1);
+ }
+
+ scalar SigmoidDifference::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ const scalar a = 1.0 / (1.0 + std::exp(-_rising * (x - _left)));
+ const scalar b = 1.0 / (1.0 + std::exp(-_falling * (x - _right)));
+ return Term::_height * std::abs(a - b);
+ }
+
+ std::string SigmoidDifference::parameters() const {
+ return Op::join(4, " ", _left, _rising, _falling, _right) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void SigmoidDifference::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setLeft(Op::toScalar(values.at(0)));
+ setRising(Op::toScalar(values.at(1)));
+ setFalling(Op::toScalar(values.at(2)));
+ setRight(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void SigmoidDifference::setLeft(scalar leftInflection) {
+ this->_left = leftInflection;
+ }
+
+ scalar SigmoidDifference::getLeft() const {
+ return this->_left;
+ }
+
+ void SigmoidDifference::setRising(scalar risingSlope) {
+ this->_rising = risingSlope;
+ }
+
+ scalar SigmoidDifference::getRising() const {
+ return this->_rising;
+ }
+
+ void SigmoidDifference::setFalling(scalar fallingSlope) {
+ this->_falling = fallingSlope;
+ }
+
+ scalar SigmoidDifference::getFalling() const {
+ return this->_falling;
+ }
+
+ void SigmoidDifference::setRight(scalar rightInflection) {
+ this->_right = rightInflection;
+ }
+
+ scalar SigmoidDifference::getRight() const {
+ return this->_right;
+ }
+
+ SigmoidDifference* SigmoidDifference::clone() const {
+ return new SigmoidDifference(*this);
+ }
+
+ Term* SigmoidDifference::constructor() {
+ return new SigmoidDifference;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/SigmoidProduct.cpp b/fuzzylite/src/term/SigmoidProduct.cpp
new file mode 100644
index 0000000..5f35750
--- /dev/null
+++ b/fuzzylite/src/term/SigmoidProduct.cpp
@@ -0,0 +1,107 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/SigmoidProduct.h"
+
+namespace fl {
+
+ SigmoidProduct::SigmoidProduct(const std::string& name,
+ scalar left, scalar rising,
+ scalar falling, scalar right, scalar height)
+ : Term(name, height), _left(left), _rising(rising), _falling(falling), _right(right) { }
+
+ SigmoidProduct::~SigmoidProduct() { }
+
+ std::string SigmoidProduct::className() const {
+ return "SigmoidProduct";
+ }
+
+ Complexity SigmoidProduct::complexity() const {
+ return Complexity().comparison(1).arithmetic(2 + 4 + 4).function(2);
+ }
+
+ scalar SigmoidProduct::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ const scalar a = 1.0 + std::exp(-_rising * (x - _left));
+ const scalar b = 1.0 + std::exp(-_falling * (x - _right));
+ return Term::_height * 1.0 / (a * b);
+ }
+
+ std::string SigmoidProduct::parameters() const {
+ return Op::join(4, " ", _left, _rising, _falling, _right) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void SigmoidProduct::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setLeft(Op::toScalar(values.at(0)));
+ setRising(Op::toScalar(values.at(1)));
+ setFalling(Op::toScalar(values.at(2)));
+ setRight(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+
+ }
+
+ void SigmoidProduct::setRising(scalar risingSlope) {
+ this->_rising = risingSlope;
+ }
+
+ scalar SigmoidProduct::getRising() const {
+ return this->_rising;
+ }
+
+ void SigmoidProduct::setLeft(scalar leftInflection) {
+ this->_left = leftInflection;
+ }
+
+ scalar SigmoidProduct::getLeft() const {
+ return this->_left;
+ }
+
+ void SigmoidProduct::setRight(scalar rightInflection) {
+ this->_right = rightInflection;
+ }
+
+ scalar SigmoidProduct::getRight() const {
+ return this->_right;
+ }
+
+ void SigmoidProduct::setFalling(scalar fallingSlope) {
+ this->_falling = fallingSlope;
+ }
+
+ scalar SigmoidProduct::getFalling() const {
+ return this->_falling;
+ }
+
+ SigmoidProduct* SigmoidProduct::clone() const {
+ return new SigmoidProduct(*this);
+ }
+
+ Term* SigmoidProduct::constructor() {
+ return new SigmoidProduct;
+ }
+
+}
diff --git a/fuzzylite/src/term/Spike.cpp b/fuzzylite/src/term/Spike.cpp
new file mode 100644
index 0000000..a19810d
--- /dev/null
+++ b/fuzzylite/src/term/Spike.cpp
@@ -0,0 +1,84 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Spike.h"
+
+namespace fl {
+
+ Spike::Spike(const std::string& name, scalar center, scalar width, scalar height)
+ : Term(name, height), _center(center), _width(width) { }
+
+ Spike::~Spike() { }
+
+ std::string Spike::className() const {
+ return "Spike";
+ }
+
+ Complexity Spike::complexity() const {
+ return Complexity().comparison(1).arithmetic(1 + 3).function(2);
+ }
+
+ scalar Spike::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+ return Term::_height * std::exp(-std::abs(10.0 / _width * (x - _center)));
+ }
+
+ std::string Spike::parameters() const {
+ return Op::join(2, " ", _center, _width) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Spike::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setCenter(Op::toScalar(values.at(0)));
+ setWidth(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Spike::setCenter(scalar center) {
+ this->_center = center;
+ }
+
+ scalar Spike::getCenter() const {
+ return this->_center;
+ }
+
+ void Spike::setWidth(scalar width) {
+ this->_width = width;
+ }
+
+ scalar Spike::getWidth() const {
+ return this->_width;
+ }
+
+ Spike* Spike::clone() const {
+ return new Spike(*this);
+ }
+
+ Term* Spike::constructor() {
+ return new Spike;
+ }
+
+}
diff --git a/fuzzylite/src/term/Term.cpp b/fuzzylite/src/term/Term.cpp
new file mode 100644
index 0000000..bf7520d
--- /dev/null
+++ b/fuzzylite/src/term/Term.cpp
@@ -0,0 +1,65 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Term.h"
+
+#include "fl/imex/FllExporter.h"
+#include "fl/term/Linear.h"
+#include "fl/term/Function.h"
+
+namespace fl {
+
+ Term::Term(const std::string& name, scalar height) : _name(name), _height(height) { }
+
+ Term::~Term() { }
+
+ void Term::setName(const std::string& name) {
+ this->_name = name;
+ }
+
+ std::string Term::getName() const {
+ return this->_name;
+ }
+
+ void Term::setHeight(scalar height) {
+ this->_height = height;
+ }
+
+ scalar Term::getHeight() const {
+ return this->_height;
+ }
+
+ std::string Term::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ void Term::updateReference(const Engine* engine) {
+ FL_IUNUSED(engine);
+ //do nothing
+ }
+
+ scalar Term::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const {
+ FL_IUNUSED(minimum);
+ FL_IUNUSED(maximum);
+ return membership(activationDegree);
+ }
+
+ bool Term::isMonotonic() const {
+ return false;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/Trapezoid.cpp b/fuzzylite/src/term/Trapezoid.cpp
new file mode 100644
index 0000000..4773dbb
--- /dev/null
+++ b/fuzzylite/src/term/Trapezoid.cpp
@@ -0,0 +1,128 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Trapezoid.h"
+
+namespace fl {
+
+ Trapezoid::Trapezoid(const std::string& name,
+ scalar vertexA, scalar vertexB, scalar vertexC, scalar vertexD, scalar height)
+ : Term(name, height), _vertexA(vertexA), _vertexB(vertexB), _vertexC(vertexC), _vertexD(vertexD) {
+ if (Op::isNaN(vertexC) and Op::isNaN(vertexD)) {
+ this->_vertexD = _vertexB;
+ scalar range = _vertexD - _vertexA;
+ this->_vertexB = _vertexA + range * 1.0 / 5.0;
+ this->_vertexC = _vertexA + range * 4.0 / 5.0;
+ }
+ }
+
+ Trapezoid::~Trapezoid() { }
+
+ std::string Trapezoid::className() const {
+ return "Trapezoid";
+ }
+
+ Complexity Trapezoid::complexity() const {
+ return Complexity().comparison(1 + 6).arithmetic(1 + 3).function(1);
+ }
+
+ scalar Trapezoid::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ if (Op::isLt(x, _vertexA) or Op::isGt(x, _vertexD))
+ return Term::_height * 0.0;
+
+ if (Op::isLt(x, _vertexB)) {
+ if (_vertexA == -fl::inf) return Term::_height * 1.0;
+ return Term::_height * Op::min(scalar(1.0), (x - _vertexA) / (_vertexB - _vertexA));
+ }
+ if (Op::isLE(x, _vertexC))
+ return Term::_height * 1.0;
+
+ if (Op::isLt(x, _vertexD)) {
+ if (_vertexD == fl::inf) return Term::_height * 1.0;
+ return Term::_height * (_vertexD - x) / (_vertexD - _vertexC);
+ }
+
+ if (_vertexD == fl::inf) return Term::_height * 1.0;
+ return Term::_height * 0.0;
+ }
+
+ std::string Trapezoid::parameters() const {
+ return Op::join(4, " ", _vertexA, _vertexB, _vertexC, _vertexD)+
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Trapezoid::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setVertexA(Op::toScalar(values.at(0)));
+ setVertexB(Op::toScalar(values.at(1)));
+ setVertexC(Op::toScalar(values.at(2)));
+ setVertexD(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Trapezoid::setVertexA(scalar a) {
+ this->_vertexA = a;
+ }
+
+ scalar Trapezoid::getVertexA() const {
+ return this->_vertexA;
+ }
+
+ void Trapezoid::setVertexB(scalar b) {
+ this->_vertexB = b;
+ }
+
+ scalar Trapezoid::getVertexB() const {
+ return this->_vertexB;
+ }
+
+ void Trapezoid::setVertexC(scalar c) {
+ this->_vertexC = c;
+ }
+
+ scalar Trapezoid::getVertexC() const {
+ return this->_vertexC;
+ }
+
+ void Trapezoid::setVertexD(scalar d) {
+ this->_vertexD = d;
+ }
+
+ scalar Trapezoid::getVertexD() const {
+ return this->_vertexD;
+ }
+
+ Trapezoid* Trapezoid::clone() const {
+ return new Trapezoid(*this);
+ }
+
+ Term* Trapezoid::constructor() {
+ return new Trapezoid;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/Triangle.cpp b/fuzzylite/src/term/Triangle.cpp
new file mode 100644
index 0000000..9d1835c
--- /dev/null
+++ b/fuzzylite/src/term/Triangle.cpp
@@ -0,0 +1,113 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/Triangle.h"
+
+namespace fl {
+
+ Triangle::Triangle(const std::string& name, scalar vertexA, scalar vertexB, scalar vertexC, scalar height)
+ : Term(name, height), _vertexA(vertexA), _vertexB(vertexB), _vertexC(vertexC) {
+ if (Op::isNaN(vertexC)) {
+ this->_vertexC = _vertexB;
+ this->_vertexB = 0.5 * (_vertexA + _vertexB);
+ }
+ }
+
+ Triangle::~Triangle() { }
+
+ std::string Triangle::className() const {
+ return "Triangle";
+ }
+
+ Complexity Triangle::complexity() const {
+ return Complexity().comparison(1 + 5).arithmetic(4);
+ }
+
+ scalar Triangle::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ if (Op::isLt(x, _vertexA) or Op::isGt(x, _vertexC))
+ return Term::_height * 0.0;
+
+ if (Op::isEq(x, _vertexB))
+ return Term::_height * 1.0;
+
+ if (Op::isLt(x, _vertexB)) {
+ if (_vertexA == -fl::inf)
+ return Term::_height * 1.0;
+ return Term::_height * (x - _vertexA) / (_vertexB - _vertexA);
+ }
+ if (_vertexC == fl::inf)
+ return Term::_height * 1.0;
+ return Term::_height * (_vertexC - x) / (_vertexC - _vertexB);
+ }
+
+ std::string Triangle::parameters() const {
+ return Op::join(3, " ", _vertexA, _vertexB, _vertexC) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void Triangle::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 3;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setVertexA(Op::toScalar(values.at(0)));
+ setVertexB(Op::toScalar(values.at(1)));
+ setVertexC(Op::toScalar(values.at(2)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Triangle::setVertexA(scalar a) {
+ this->_vertexA = a;
+ }
+
+ scalar Triangle::getVertexA() const {
+ return this->_vertexA;
+ }
+
+ void Triangle::setVertexB(scalar b) {
+ this->_vertexB = b;
+ }
+
+ scalar Triangle::getVertexB() const {
+ return this->_vertexB;
+ }
+
+ void Triangle::setVertexC(scalar c) {
+ this->_vertexC = c;
+ }
+
+ scalar Triangle::getVertexC() const {
+ return this->_vertexC;
+ }
+
+ Triangle* Triangle::clone() const {
+ return new Triangle(*this);
+ }
+
+ Term* Triangle::constructor() {
+ return new Triangle;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/ZShape.cpp b/fuzzylite/src/term/ZShape.cpp
new file mode 100644
index 0000000..9054b20
--- /dev/null
+++ b/fuzzylite/src/term/ZShape.cpp
@@ -0,0 +1,116 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/term/ZShape.h"
+
+namespace fl {
+
+ ZShape::ZShape(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) { }
+
+ ZShape::~ZShape() { }
+
+ std::string ZShape::className() const {
+ return "ZShape";
+ }
+
+ Complexity ZShape::complexity() const {
+ return Complexity().comparison(1 + 3).arithmetic(3 + 4).function(1);
+ }
+
+ scalar ZShape::membership(scalar x) const {
+ if (Op::isNaN(x)) return fl::nan;
+
+ if (Op::isLE(x, _start))
+ return Term::_height * 1.0;
+
+ if (Op::isLE(x, 0.5 * (_start + _end)))
+ return Term::_height * (1.0 - 2.0 * std::pow((x - _start) / (_end - _start), 2));
+
+ if (Op::isLt(x, _end))
+ return Term::_height * (2.0 * std::pow((x - _end) / (_end - _start), 2));
+
+ return Term::_height * 0.0;
+ }
+
+ scalar ZShape::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const {
+ FL_IUNUSED(minimum);
+ FL_IUNUSED(maximum);
+
+ scalar w = activationDegree;
+ scalar z = fl::nan;
+
+ scalar difference = _end - _start;
+ scalar a = _start + std::sqrt(-0.5 * (w - 1.0) * difference * difference);
+ scalar b = _end + std::sqrt(0.5 * w * difference * difference);
+ if (std::abs(w - membership(a)) < std::abs(w - membership(b))) {
+ z = a;
+ } else {
+ z = b;
+ }
+ return z;
+ }
+
+ bool ZShape::isMonotonic() const {
+ return true;
+ }
+
+ std::string ZShape::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : "");
+ }
+
+ void ZShape::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 2;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void ZShape::setStart(scalar start) {
+ this->_start = start;
+ }
+
+ scalar ZShape::getStart() const {
+ return this->_start;
+ }
+
+ void ZShape::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar ZShape::getEnd() const {
+ return this->_end;
+ }
+
+ ZShape* ZShape::clone() const {
+ return new ZShape(*this);
+ }
+
+ Term* ZShape::constructor() {
+ return new ZShape;
+ }
+
+}
diff --git a/fuzzylite/src/variable/InputVariable.cpp b/fuzzylite/src/variable/InputVariable.cpp
new file mode 100644
index 0000000..1364d8f
--- /dev/null
+++ b/fuzzylite/src/variable/InputVariable.cpp
@@ -0,0 +1,44 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/variable/InputVariable.h"
+
+#include "fl/imex/FllExporter.h"
+
+namespace fl {
+
+ InputVariable::InputVariable(const std::string& name, scalar minimum, scalar maximum)
+ : Variable(name, minimum, maximum) { }
+
+ InputVariable::~InputVariable() { }
+
+ std::string InputVariable::fuzzyInputValue() const {
+ return fuzzify(getValue());
+ }
+
+ Variable::Type InputVariable::type() const {
+ return Variable::Input;
+ }
+
+ std::string InputVariable::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ InputVariable* InputVariable::clone() const {
+ return new InputVariable(*this);
+ }
+
+}
diff --git a/fuzzylite/src/variable/OutputVariable.cpp b/fuzzylite/src/variable/OutputVariable.cpp
new file mode 100644
index 0000000..0f85dc4
--- /dev/null
+++ b/fuzzylite/src/variable/OutputVariable.cpp
@@ -0,0 +1,226 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/variable/OutputVariable.h"
+
+#include "fl/imex/FllExporter.h"
+
+namespace fl {
+
+ OutputVariable::OutputVariable(const std::string& name,
+ scalar minimum, scalar maximum)
+ : Variable(name, minimum, maximum),
+ _fuzzyOutput(new Aggregated(name, minimum, maximum)),
+ _previousValue(fl::nan), _defaultValue(fl::nan),
+ _lockPreviousValue(false) { }
+
+ OutputVariable::OutputVariable(const OutputVariable& other) : Variable(other) {
+ copyFrom(other);
+ }
+
+ OutputVariable& OutputVariable::operator=(const OutputVariable& other) {
+ if (this != &other) {
+ _fuzzyOutput.reset(fl::null);
+ _defuzzifier.reset(fl::null);
+
+ Variable::operator=(other);
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ OutputVariable::~OutputVariable() { }
+
+ void OutputVariable::copyFrom(const OutputVariable& other) {
+ _fuzzyOutput.reset(other._fuzzyOutput->clone());
+ if (other._defuzzifier.get()) _defuzzifier.reset(other._defuzzifier->clone());
+ _previousValue = other._previousValue;
+ _defaultValue = other._defaultValue;
+ _lockPreviousValue = other._lockPreviousValue;
+ }
+
+ void OutputVariable::setName(const std::string& name) {
+ Variable::setName(name);
+ _fuzzyOutput->setName(name);
+ }
+
+ Aggregated* OutputVariable::fuzzyOutput() const {
+ return this->_fuzzyOutput.get();
+ }
+
+ void OutputVariable::setMinimum(scalar minimum) {
+ Variable::setMinimum(minimum);
+ _fuzzyOutput->setMinimum(minimum);
+ }
+
+ void OutputVariable::setMaximum(scalar maximum) {
+ Variable::setMaximum(maximum);
+ _fuzzyOutput->setMaximum(maximum);
+ }
+
+ void OutputVariable::setDefuzzifier(Defuzzifier* defuzzifier) {
+ this->_defuzzifier.reset(defuzzifier);
+ }
+
+ Defuzzifier* OutputVariable::getDefuzzifier() const {
+ return this->_defuzzifier.get();
+ }
+
+ void OutputVariable::setAggregation(SNorm* aggregation) {
+ this->_fuzzyOutput->setAggregation(aggregation);
+ }
+
+ SNorm* OutputVariable::getAggregation() const {
+ return this->_fuzzyOutput->getAggregation();
+ }
+
+ void OutputVariable::setPreviousValue(scalar previousOutputValue) {
+ this->_previousValue = previousOutputValue;
+ }
+
+ scalar OutputVariable::getPreviousValue() const {
+ return this->_previousValue;
+ }
+
+ void OutputVariable::setDefaultValue(scalar defaultValue) {
+ this->_defaultValue = defaultValue;
+ }
+
+ scalar OutputVariable::getDefaultValue() const {
+ return this->_defaultValue;
+ }
+
+ void OutputVariable::setLockPreviousValue(bool lockPreviousValue) {
+ this->_lockPreviousValue = lockPreviousValue;
+ }
+
+ bool OutputVariable::isLockPreviousValue() const {
+ return this->_lockPreviousValue;
+ }
+
+ Variable::Type OutputVariable::type() const {
+ return Variable::Output;
+ }
+
+ Complexity OutputVariable::complexity(const Activated& term) const {
+ Aggregated aggregated;
+ if (_fuzzyOutput->getAggregation()) {
+ aggregated.setAggregation(_fuzzyOutput->getAggregation()->clone());
+ }
+ aggregated.addTerm(term);
+ if (_defuzzifier.get()) {
+ return _defuzzifier->complexity(&aggregated);
+ }
+ return aggregated.complexityOfMembership();
+ }
+
+ Complexity OutputVariable::complexityOfDefuzzification() const {
+ Aggregated term;
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ term.addTerm(_terms.at(i), fl::nan, fl::null);
+ }
+ if (_defuzzifier.get()) {
+ return _defuzzifier->complexity(&term);
+ }
+ return term.complexityOfMembership();
+ }
+
+ Complexity OutputVariable::currentComplexity() const {
+ if (_defuzzifier.get())
+ return _defuzzifier->complexity(_fuzzyOutput.get());
+ return _fuzzyOutput->complexity();
+ }
+
+ void OutputVariable::defuzzify() {
+ if (not _enabled) return;
+
+ if (Op::isFinite(_value)) {
+ _previousValue = _value;
+ }
+
+ std::string exception;
+ scalar result = fl::nan;
+ bool isValid = not _fuzzyOutput->isEmpty();
+ if (isValid) {
+ /* Checks whether the variable can be defuzzified without exceptions.
+ * If it cannot be defuzzified, be that due to a missing defuzzifier
+ * or aggregation operator, the expected behaviour is to leave the
+ * variable in a state that reflects an invalid defuzzification,
+ * that is, apply logic of default values and previous values.*/
+ isValid = false;
+ if (_defuzzifier.get()) {
+ try {
+ result = _defuzzifier->defuzzify(_fuzzyOutput.get(), _minimum, _maximum);
+ isValid = true;
+ } catch (std::exception& ex) {
+ exception = ex.what();
+ }
+ } else {
+ exception = "[defuzzifier error] "
+ "defuzzifier needed to defuzzify output variable <" + getName() + ">";
+ }
+ }
+
+ if (not isValid) {
+ //if a previous defuzzification was successfully performed and
+ //and the output value is supposed not to change when the output is empty
+ if (_lockPreviousValue and not Op::isNaN(_previousValue)) {
+ result = _previousValue;
+ } else {
+ result = _defaultValue;
+ }
+ }
+
+ setValue(result);
+
+ if (not exception.empty()) {
+ throw Exception(exception, FL_AT);
+ }
+ }
+
+ std::string OutputVariable::fuzzyOutputValue() const {
+ std::ostringstream ss;
+ if (not _terms.empty()) {
+ Term* first = _terms.front();
+ ss << Op::str(fuzzyOutput()->activationDegree(first))
+ << "/" << first->getName();
+ }
+ for (std::size_t i = 1; i < _terms.size(); ++i) {
+ scalar degree = fuzzyOutput()->activationDegree(_terms.at(i));
+ if (Op::isNaN(degree) or Op::isGE(degree, 0.0))
+ ss << " + " << Op::str(degree);
+ else
+ ss << " - " << Op::str(std::abs(degree));
+ ss << "/" << terms().at(i)->getName();
+ }
+ return ss.str();
+ }
+
+ void OutputVariable::clear() {
+ fuzzyOutput()->clear();
+ setValue(fl::nan);
+ setPreviousValue(fl::nan);
+ }
+
+ std::string OutputVariable::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ OutputVariable* OutputVariable::clone() const {
+ return new OutputVariable(*this);
+ }
+
+}
diff --git a/fuzzylite/src/variable/Variable.cpp b/fuzzylite/src/variable/Variable.cpp
new file mode 100644
index 0000000..516b466
--- /dev/null
+++ b/fuzzylite/src/variable/Variable.cpp
@@ -0,0 +1,295 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/variable/Variable.h"
+
+#include "fl/imex/FllExporter.h"
+#include "fl/norm/Norm.h"
+#include "fl/term/Constant.h"
+#include "fl/term/Linear.h"
+
+#include <queue>
+
+namespace fl {
+
+ Variable::Variable(const std::string& name, scalar minimum, scalar maximum)
+ : _name(name), _description(""),
+ _value(fl::nan), _minimum(minimum), _maximum(maximum),
+ _enabled(true), _lockValueInRange(false) { }
+
+ Variable::Variable(const Variable& other) {
+ copyFrom(other);
+ }
+
+ Variable& Variable::operator=(const Variable& other) {
+ if (this != &other) {
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ delete _terms.at(i);
+ }
+ _terms.clear();
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ void Variable::copyFrom(const Variable& other) {
+ _name = other._name;
+ _description = other._description;
+ _value = other._value;
+ _minimum = other._minimum;
+ _maximum = other._maximum;
+ _enabled = other._enabled;
+ _lockValueInRange = other._lockValueInRange;
+ for (std::size_t i = 0; i < other._terms.size(); ++i) {
+ _terms.push_back(other._terms.at(i)->clone());
+ }
+ }
+
+ Variable::~Variable() {
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ delete _terms.at(i);
+ }
+ }
+
+ void Variable::setName(const std::string& name) {
+ this->_name = name;
+ }
+
+ std::string Variable::getName() const {
+ return this->_name;
+ }
+
+ void Variable::setDescription(const std::string& description) {
+ this->_description = description;
+ }
+
+ std::string Variable::getDescription() const {
+ return this->_description;
+ }
+
+ void Variable::setValue(scalar value) {
+ this->_value = _lockValueInRange
+ ? Op::bound(value, _minimum, _maximum)
+ : value;
+ }
+
+ scalar Variable::getValue() const {
+ return this->_value;
+ }
+
+ void Variable::setRange(scalar minimum, scalar maximum) {
+ setMinimum(minimum);
+ setMaximum(maximum);
+ }
+
+ scalar Variable::range() const {
+ return getMaximum() - getMinimum();
+ }
+
+ void Variable::setMinimum(scalar minimum) {
+ this->_minimum = minimum;
+ }
+
+ scalar Variable::getMinimum() const {
+ return this->_minimum;
+ }
+
+ void Variable::setMaximum(scalar maximum) {
+ this->_maximum = maximum;
+ }
+
+ scalar Variable::getMaximum() const {
+ return this->_maximum;
+ }
+
+ void Variable::setEnabled(bool enabled) {
+ this->_enabled = enabled;
+ }
+
+ bool Variable::isEnabled() const {
+ return this->_enabled;
+ }
+
+ void Variable::setLockValueInRange(bool lockValueInRange) {
+ this->_lockValueInRange = lockValueInRange;
+ }
+
+ bool Variable::isLockValueInRange() const {
+ return this->_lockValueInRange;
+ }
+
+ Variable::Type Variable::type() const {
+ return None;
+ }
+
+ Complexity Variable::complexity() const {
+ Complexity result;
+ if (isEnabled()) {
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ result += _terms.at(i)->complexity();
+ }
+ }
+ return result;
+ }
+
+ std::string Variable::fuzzify(scalar x) const {
+ std::ostringstream ss;
+ for (std::size_t i = 0; i < terms().size(); ++i) {
+ Term* term = _terms.at(i);
+ scalar fx = fl::nan;
+ try {
+ fx = term->membership(x);
+ } catch (...) {
+ //ignore
+ }
+ if (i == 0) {
+ ss << Op::str(fx);
+ } else {
+ if (Op::isNaN(fx) or Op::isGE(fx, 0.0))
+ ss << " + " << Op::str(fx);
+ else
+ ss << " - " << Op::str(std::abs(fx));
+ }
+ ss << "/" << term->getName();
+ }
+ return ss.str();
+ }
+
+ Term* Variable::highestMembership(scalar x, scalar* yhighest) const {
+ Term* result = fl::null;
+ scalar ymax = 0.0;
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ scalar y = fl::nan;
+ Term* term = _terms.at(i);
+ try {
+ y = term->membership(x);
+ } catch (...) {
+ //ignore
+ }
+ if (Op::isGt(y, ymax)) {
+ ymax = y;
+ result = term;
+ }
+ }
+ if (yhighest) *yhighest = ymax;
+ return result;
+ }
+
+ std::string Variable::toString() const {
+ return FllExporter().toString(this);
+ }
+
+ /**
+ * Operations for datatype _terms
+ */
+
+ typedef std::pair<Term*, scalar> TermCentroid;
+
+ struct Ascending {
+
+ bool operator()(const TermCentroid& a, const TermCentroid& b) const {
+ return a.second > b.second;
+ }
+ };
+
+ void Variable::sort() {
+ std::priority_queue <TermCentroid, std::vector<TermCentroid>, Ascending> termCentroids;
+ Centroid defuzzifier;
+ FL_DBG("Sorting...");
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ Term* term = _terms.at(i);
+ scalar centroid = fl::inf;
+ try {
+ if (dynamic_cast<const Constant*> (term) or dynamic_cast<const Linear*> (term)) {
+ centroid = term->membership(0);
+ } else {
+ centroid = defuzzifier.defuzzify(term, getMinimum(), getMaximum());
+ }
+ } catch (...) { //ignore error possibly due to Function not loaded
+ centroid = fl::inf;
+ }
+ termCentroids.push(TermCentroid(term, centroid));
+ FL_DBG(term->toString() << " -> " << centroid)
+ }
+
+ std::vector<Term*> sortedTerms;
+ while (termCentroids.size() > 0) {
+ sortedTerms.push_back(termCentroids.top().first);
+ FL_DBG(termCentroids.top().first->toString() << " -> " << termCentroids.top().second);
+ termCentroids.pop();
+ }
+ setTerms(sortedTerms);
+ }
+
+ void Variable::addTerm(Term* term) {
+ _terms.push_back(term);
+ }
+
+ void Variable::insertTerm(Term* term, std::size_t index) {
+ _terms.insert(_terms.begin() + index, term);
+ }
+
+ Term* Variable::getTerm(std::size_t index) const {
+ return _terms.at(index);
+ }
+
+ Term* Variable::getTerm(const std::string& name) const {
+ for (std::size_t i = 0; i < terms().size(); ++i) {
+ if (_terms.at(i)->getName() == name) {
+ return terms().at(i);
+ }
+ }
+ throw Exception("[variable error] term <" + name + "> "
+ "not found in variable <" + getName() + ">", FL_AT);
+ }
+
+ bool Variable::hasTerm(const std::string& name) const {
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ if (_terms.at(i)->getName() == name) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Term* Variable::removeTerm(std::size_t index) {
+ Term* result = _terms.at(index);
+ _terms.erase(_terms.begin() + index);
+ return result;
+ }
+
+ std::size_t Variable::numberOfTerms() const {
+ return _terms.size();
+ }
+
+ const std::vector<Term*>& Variable::terms() const {
+ return this->_terms;
+ }
+
+ void Variable::setTerms(const std::vector<Term*>& terms) {
+ this->_terms = terms;
+ }
+
+ std::vector<Term*>& Variable::terms() {
+ return this->_terms;
+ }
+
+ Variable* Variable::clone() const {
+ return new Variable(*this);
+ }
+
+}
+
diff --git a/fuzzylite/test/BenchmarkTest.cpp b/fuzzylite/test/BenchmarkTest.cpp
new file mode 100644
index 0000000..f868ec2
--- /dev/null
+++ b/fuzzylite/test/BenchmarkTest.cpp
@@ -0,0 +1,131 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "fl/Benchmark.h"
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+#include <vector>
+#include <fstream>
+
+namespace fl {
+
+ TEST_CASE("Benchmarks run from Console ", "[benchmark][console]") {
+ // const char* args[] = {"dummy-command", "benchmarks", "../../examples/", "1"};
+ // Console::main(4, args);
+ }
+
+ TEST_CASE("Benchmarks from FLD files", "[benchmark][fld]") {
+ std::string path = "../../examples/";
+ typedef std::pair<std::string, int > Example;
+ std::vector<Example> examples;
+ examples.push_back(Example("mamdani/AllTerms", int(1e4)));
+ examples.push_back(Example("mamdani/SimpleDimmer", int(1e5)));
+ examples.push_back(Example("mamdani/matlab/mam21", 128));
+ examples.push_back(Example("mamdani/matlab/mam22", 128));
+ examples.push_back(Example("mamdani/matlab/shower", 256));
+ examples.push_back(Example("mamdani/matlab/tank", 256));
+ examples.push_back(Example("mamdani/matlab/tank2", 512));
+ examples.push_back(Example("mamdani/matlab/tipper", 256));
+ examples.push_back(Example("mamdani/matlab/tipper1", int(1e5)));
+ examples.push_back(Example("mamdani/octave/investment_portfolio", 256));
+ examples.push_back(Example("mamdani/octave/mamdani_tip_calculator", 256));
+ examples.push_back(Example("takagi-sugeno/approximation", int(1e6)));
+ examples.push_back(Example("takagi-sugeno/SimpleDimmer", int(2e6)));
+ examples.push_back(Example("takagi-sugeno/matlab/fpeaks", 512));
+ examples.push_back(Example("takagi-sugeno/matlab/invkine1", 256));
+ examples.push_back(Example("takagi-sugeno/matlab/invkine2", 256));
+ examples.push_back(Example("takagi-sugeno/matlab/juggler", 512));
+ examples.push_back(Example("takagi-sugeno/matlab/membrn1", 1024));
+ examples.push_back(Example("takagi-sugeno/matlab/membrn2", 512));
+ examples.push_back(Example("takagi-sugeno/matlab/slbb", 20));
+ examples.push_back(Example("takagi-sugeno/matlab/slcp", 20));
+ examples.push_back(Example("takagi-sugeno/matlab/slcp1", 15));
+ examples.push_back(Example("takagi-sugeno/matlab/slcpp1", 9));
+ examples.push_back(Example("takagi-sugeno/matlab/sltbu_fl", 128));
+ examples.push_back(Example("takagi-sugeno/matlab/sugeno1", int(2e6)));
+ examples.push_back(Example("takagi-sugeno/matlab/tanksg", 1024));
+ examples.push_back(Example("takagi-sugeno/matlab/tippersg", 1024));
+ examples.push_back(Example("takagi-sugeno/octave/cubic_approximator", int(2e6)));
+ examples.push_back(Example("takagi-sugeno/octave/heart_disease_risk", 1024));
+ examples.push_back(Example("takagi-sugeno/octave/linear_tip_calculator", 1024));
+ examples.push_back(Example("takagi-sugeno/octave/sugeno_tip_calculator", 512));
+ examples.push_back(Example("tsukamoto/tsukamoto", int(1e6)));
+
+ std::ostringstream writer;
+ std::vector<int> errors = std::vector<int>(examples.size(), 0);
+ for (std::size_t i = 0; i < examples.size(); ++i) {
+ Example example = examples.at(i);
+ FL_LOG("Benchmark " << (i + 1) << "/" << examples.size() << ": "
+ << example.first << ".fll (" << example.second << " values)");
+
+ FL_unique_ptr<Engine> engine(FllImporter().fromFile(path + example.first + ".fll"));
+
+#ifdef FL_USE_FLOAT
+ scalar tolerance = 1e-3;
+#else
+ scalar tolerance = fuzzylite::macheps();
+#endif
+ Benchmark benchmark(example.first, engine.get(), tolerance);
+
+ std::ifstream reader(std::string(path + example.first + ".fld").c_str());
+ if (not reader.is_open()) {
+ throw Exception("File not found: " + path + example.first + ".fld");
+ }
+ benchmark.prepare(reader, 1024);
+ benchmark.run(1);
+ CHECK(benchmark.canComputeErrors() == true);
+ errors.at(i) = benchmark.accuracyErrors();
+
+ if (i == 0) {
+ writer << "\n" << benchmark.format(benchmark.results(),
+ Benchmark::Horizontal, Benchmark::HeaderAndBody) << "\n";
+ } else {
+ writer << benchmark.format(benchmark.results(),
+ Benchmark::Horizontal, Benchmark::Body) << "\n";
+ }
+ }
+ FL_LOG(writer.str());
+ for (std::size_t i = 0; i < errors.size(); ++i) {
+ FL_LOG("Checking for errors in: " << examples.at(i).first);
+ CHECK(errors.at(i) == 0);
+ }
+ }
+
+ TEST_CASE("Time conversions", "[benchmark][time]") {
+ CHECK(Op::isEq(1.0, Benchmark::convert(3600, Benchmark::Seconds, Benchmark::Hours)));
+ FL_LOG(Benchmark::convert(3600, Benchmark::Seconds, Benchmark::Hours));
+ CHECK(Op::isEq(3600, Benchmark::convert(1, Benchmark::Hours, Benchmark::Seconds)));
+ FL_LOG(Benchmark::convert(1, Benchmark::Hours, Benchmark::Seconds));
+
+ CHECK(Op::isEq(1000.0, Benchmark::convert(1.0, Benchmark::Seconds, Benchmark::MilliSeconds)));
+ FL_LOG(Benchmark::convert(1.0, Benchmark::Seconds, Benchmark::MilliSeconds));
+ CHECK(Op::isEq(1.0, Benchmark::convert(1000.0, Benchmark::MilliSeconds, Benchmark::Seconds)));
+ FL_LOG(Benchmark::convert(1000.0, Benchmark::MilliSeconds, Benchmark::Seconds));
+
+ CHECK(Op::isEq(35e9, Benchmark::convert(35, Benchmark::Seconds, Benchmark::NanoSeconds)));
+ CHECK(Op::isEq(35, Benchmark::convert(35e9, Benchmark::NanoSeconds, Benchmark::Seconds)));
+ }
+
+ TEST_CASE("Benchmark headers", "[benchmark][header]") {
+ FL_LOG(Op::join(Benchmark().header(10, true), "\t"));
+ CHECK(Benchmark().header(10).size() == 30);
+
+ FL_LOG(Op::join(Benchmark().header(10, false), "\t"));
+ CHECK(Benchmark().header(10, false).size() == 30 - 8);
+ }
+}
diff --git a/fuzzylite/test/Catch.License b/fuzzylite/test/Catch.License
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/fuzzylite/test/Catch.License
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/fuzzylite/test/MainTest.cpp b/fuzzylite/test/MainTest.cpp
new file mode 100644
index 0000000..c18740a
--- /dev/null
+++ b/fuzzylite/test/MainTest.cpp
@@ -0,0 +1,34 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#define CATCH_CONFIG_RUNNER
+
+#include "test/catch.hpp"
+
+#include "fl/Headers.h"
+
+int main(int argc, char** argv) {
+
+ // global setup...
+ fl::fuzzylite::setDebugging(false);
+ fl::fuzzylite::setLogging(true);
+
+ int result = Catch::Session().run(argc, argv);
+
+ // global clean-up...
+
+ return result;
+}
diff --git a/fuzzylite/test/QuickTest.cpp b/fuzzylite/test/QuickTest.cpp
new file mode 100644
index 0000000..9108fde
--- /dev/null
+++ b/fuzzylite/test/QuickTest.cpp
@@ -0,0 +1,128 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ TEST_CASE("Increment ", "[op][increment]") {
+ std::vector<int> sampleValues, minSampleValues, maxSampleValues;
+ for (std::size_t i = 0; i < 2; ++i) {
+ sampleValues.push_back(0);
+ minSampleValues.push_back(0);
+ if (i == 0)
+ maxSampleValues.push_back(10);
+ else maxSampleValues.push_back(0);
+ }
+ int times = 0;
+ do {
+ times++;
+ FL_LOG(times << " " << Op::join(sampleValues, ","));
+ } while (Op::increment(sampleValues, minSampleValues, maxSampleValues));
+
+ CHECK(times == 10 + 1);
+ }
+
+ TEST_CASE("Op::split splits multiline", "[op][split]") {
+ std::string multiline = "1\n2\n3\n4";
+ std::vector<std::string> split = Op::split(multiline, "\n");
+ CHECK(split.size() == 4);
+ }
+
+ TEST_CASE("Op::str produces correct numbers", "[op][str]") {
+ fuzzylite::setLogging(true);
+ fuzzylite::setDecimals(3);
+
+ FL_LOG(Op::str(1.0));
+ FL_LOG(Op::str((long) 5000));
+ FL_LOG(Op::str((int) 6000));
+ FL_LOG(Op::str(std::size_t(6000)));
+ FL_LOG(Op::str(scalar(0.333333)));
+ FL_LOG(Op::str(float(0.333333)));
+ FL_LOG(Op::str(double(0.333333)));
+ FL_LOG(Op::str(double(0.333333), 9));
+
+ CHECK(Op::str(0) == "0");
+ CHECK(Op::str(1) == "1");
+ CHECK(Op::str(1.0) == "1.000");
+ CHECK(Op::str((long) 5000) == "5000");
+ CHECK(Op::str((int) 6000) == "6000");
+ CHECK(Op::str(std::size_t(6000)) == "6000");
+ CHECK(Op::str(scalar(0.333333)) == "0.333");
+ CHECK(Op::str(float(0.333333)) == "0.333");
+ CHECK(Op::str(double(0.333333)) == "0.333");
+ CHECK(Op::str(double(0.0000333), 9) == "0.000033300");
+
+ CHECK(Op::str(fuzzylite::macheps()) == "0.000");
+ CHECK(Op::str(fuzzylite::macheps(), 6) == "0.000001");
+ CHECK(Op::str(1e-7) == "0.000");
+ CHECK(Op::str(1e-7, 6) == "0.000000");
+ CHECK(Op::str(1e-7, 7) == "0.0000001");
+
+ FL_LOG("scientific");
+ fuzzylite::setScalarFormat(std::ios_base::scientific);
+ FL_LOG(Op::str(1.0));
+ FL_LOG(Op::str((long) 5000));
+ FL_LOG(Op::str((int) 6000));
+ FL_LOG(Op::str(std::size_t(6000)));
+ FL_LOG(Op::str(scalar(0.333333)));
+ FL_LOG(Op::str(float(0.333333)));
+ FL_LOG(Op::str(double(0.333333)));
+ FL_LOG(Op::str(double(0.0000333), 9));
+
+ CHECK(Op::str(0) == "0");
+ CHECK(Op::str(1.0) == "1.000e+00");
+ CHECK(Op::str((long) 5000) == "5000");
+ CHECK(Op::str((int) 6000) == "6000");
+ CHECK(Op::str(std::size_t(6000)) == "6000");
+ CHECK(Op::str(scalar(0.333333)) == "3.333e-01");
+ CHECK(Op::str(float(0.333333)) == "3.333e-01");
+ CHECK(Op::str(double(0.333333)) == "3.333e-01");
+ CHECK(Op::str(double(0.0000333), 9) == "3.330000000e-05");
+
+ CHECK(Op::isEq(fuzzylite::macheps(), 0.0) == false);
+ CHECK(Op::isEq(fuzzylite::macheps(), 0.0, std::pow(10.0, -6)) == false);
+ CHECK(Op::str(fuzzylite::macheps()) == "0.000e+00");
+ CHECK(Op::str(fuzzylite::macheps(), -1) == "1.000000e-06");
+ CHECK(Op::str(fuzzylite::macheps(), -1, std::ios_base::fmtflags(0x0)) == "1e-06");
+ CHECK(Op::str(1e-7, 6) == "0.000000e+00");
+ CHECK(Op::str(1e-7, 7) == "1.0000000e-07");
+ CHECK(Op::str(1e-7, 7, std::ios_base::fmtflags(0x0)) == "1e-07");
+
+
+ fuzzylite::setScalarFormat(std::ios_base::fixed);
+
+ CHECK(Op::str(0.000001, 6, std::ios_base::fmtflags(0x0)) == "1e-06");
+ CHECK(Op::str(1e-6, 6, std::ios_base::fmtflags(0x0)) == "1e-06");
+ CHECK(Op::str(1e6, 3, std::ios_base::fmtflags(0x0)) == "1e+06");
+ CHECK(Op::str(1000000, 3, std::ios_base::fmtflags(0x0)) == "1000000");
+ CHECK(Op::str(1000000.0, 3, std::ios_base::fmtflags(0x0)) == "1e+06");
+ }
+
+ TEST_CASE("macro expansion does not evaluate parameter before expansion", "[op]") {
+ std::ostringstream os;
+#define FL_MACRO1(x) os << x * 5;
+ FL_MACRO1(4 + 10);
+ CHECK(os.str() == "54");
+
+#define xstr(s) str(s)
+#define str(s) #s
+ CHECK(xstr(4 + 10) == "4 + 10");
+ }
+
+
+}
diff --git a/fuzzylite/test/activation/ThresholdTest.cpp b/fuzzylite/test/activation/ThresholdTest.cpp
new file mode 100644
index 0000000..9f6a9e6
--- /dev/null
+++ b/fuzzylite/test/activation/ThresholdTest.cpp
@@ -0,0 +1,65 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: term/Function
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("Treshold can be clone ", "[activation][threshold]") {
+ Threshold* t = new Threshold("<", 1.0);
+ REQUIRE(t->getComparison() == Threshold::LessThan);
+ REQUIRE(Op::isEq(t->getValue(), 1.0));
+ FL_DBG(FllExporter().toString(t));
+
+ Threshold* clone = t->clone();
+ REQUIRE(clone->getComparison() == Threshold::LessThan);
+ REQUIRE(Op::isEq(clone->getValue(), 1.0));
+ FL_DBG(FllExporter().toString(clone));
+ }
+
+ TEST_CASE("Treshold can be copy-constructed", "[activation][threshold]") {
+ Threshold* t = new Threshold(">=", 1.0);
+ REQUIRE(t->getComparison() == Threshold::GreaterThanOrEqualTo);
+ REQUIRE(Op::isEq(t->getValue(), 1.0));
+ FL_DBG(FllExporter().toString(t));
+
+ Threshold clone(*t);
+ REQUIRE(clone.getComparison() == Threshold::GreaterThanOrEqualTo);
+ REQUIRE(Op::isEq(clone.getValue(), 1.0));
+ FL_DBG(FllExporter().toString(&clone));
+ }
+
+ TEST_CASE("Treshold can be assigned", "[activation][threshold]") {
+ Threshold* t = new Threshold(">=", 1.0);
+ REQUIRE(t->getComparison() == Threshold::GreaterThanOrEqualTo);
+ REQUIRE(Op::isEq(t->getValue(), 1.0));
+ FL_DBG(FllExporter().toString(t));
+
+ Threshold clone = *t;
+ REQUIRE(clone.getComparison() == Threshold::GreaterThanOrEqualTo);
+ REQUIRE(Op::isEq(clone.getValue(), 1.0));
+ FL_DBG(FllExporter().toString(&clone));
+ }
+
+}
diff --git a/fuzzylite/test/catch.hpp b/fuzzylite/test/catch.hpp
new file mode 100644
index 0000000..6f9334b
--- /dev/null
+++ b/fuzzylite/test/catch.hpp
@@ -0,0 +1,11282 @@
+/*
+ * Catch v1.8.1
+ * Generated: 2017-03-01 16:04:19.016511
+ * ----------------------------------------------------------
+ * This file has been merged from multiple headers. Please don't edit it directly
+ * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ * Distributed under the Boost Software License, Version 1.0. (See accompanying
+ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+# pragma clang system_header
+#elif defined __GNUC__
+# pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#ifdef __clang__
+# ifdef __ICC // icpc defines the __clang__ macro
+# pragma warning(push)
+# pragma warning(disable: 161 1682)
+# else // __ICC
+# pragma clang diagnostic ignored "-Wglobal-constructors"
+# pragma clang diagnostic ignored "-Wvariadic-macros"
+# pragma clang diagnostic ignored "-Wc99-extensions"
+# pragma clang diagnostic ignored "-Wunused-variable"
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wpadded"
+# pragma clang diagnostic ignored "-Wc++98-compat"
+# pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+# pragma clang diagnostic ignored "-Wswitch-enum"
+# pragma clang diagnostic ignored "-Wcovered-switch-default"
+# endif
+#elif defined __GNUC__
+# pragma GCC diagnostic ignored "-Wvariadic-macros"
+# pragma GCC diagnostic ignored "-Wunused-variable"
+
+ // For newer version we can use __Pragma to disable the warnings locally
+# if __GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ <= 7
+# pragma GCC diagnostic ignored "-Wparentheses"
+# endif
+
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+# define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+# ifndef CLARA_CONFIG_MAIN
+# define CLARA_CONFIG_MAIN_NOT_DEFINED
+# define CLARA_CONFIG_MAIN
+# endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
+// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
+
+#ifdef __cplusplus
+
+# if __cplusplus >= 201103L
+# define CATCH_CPP11_OR_GREATER
+# endif
+
+# if __cplusplus >= 201402L
+# define CATCH_CPP14_OR_GREATER
+# endif
+
+#endif
+
+#ifdef __clang__
+
+# if __has_feature(cxx_nullptr)
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+# endif
+
+# if __has_feature(cxx_noexcept)
+# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+# endif
+
+# if defined(CATCH_CPP11_OR_GREATER)
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic push" ) \
+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic pop" )
+# endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+# endif
+
+// Required for some versions of Cygwin to declare gettimeofday
+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
+# define _BSD_SOURCE
+
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+# define CATCH_GCC_HAS_NEW_PRAGMA
+# endif
+
+# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+# endif
+
+# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_GCC_HAS_NEW_PRAGMA)
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "GCC diagnostic push" ) \
+ _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
+# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "GCC diagnostic pop" )
+# endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
+
+#if (_MSC_VER >= 1600)
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use variadic macros if the compiler supports them
+#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
+ ( defined __GNUC__ && __GNUC__ >= 3 ) || \
+ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
+
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+
+#endif
+
+// Use __COUNTER__ if the compiler supports it
+#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
+ ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
+ ( defined __clang__ && __clang_major__ >= 3 )
+
+#define CATCH_INTERNAL_CONFIG_COUNTER
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(CATCH_CPP11_OR_GREATER)
+
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
+# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+# endif
+
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+# endif
+
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+# endif
+
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+# endif
+
+# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+# endif
+
+# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+# endif
+
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
+# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
+# endif
+
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
+# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
+# endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+# endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
+# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+# endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
+# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+# endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_IS_ENUM
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_TUPLE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
+# define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_LONG_LONG
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for
+// analytics) because, at time of writing, __COUNTER__ is not properly handled by it.
+// This does not affect compilation
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__)
+# define CATCH_CONFIG_COUNTER
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_SHUFFLE
+#endif
+# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
+# define CATCH_CONFIG_CPP11_TYPE_TRAITS
+# endif
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
+# define CATCH_CONFIG_WINDOWS_SEH
+#endif
+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+# define CATCH_CONFIG_POSIX_SIGNALS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+# define CATCH_NOEXCEPT noexcept
+# define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+# define CATCH_NOEXCEPT throw()
+# define CATCH_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+# define CATCH_NULL nullptr
+#else
+# define CATCH_NULL NULL
+#endif
+
+// override support
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
+# define CATCH_OVERRIDE override
+#else
+# define CATCH_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
+# define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+# define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+#endif
+
+#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
+#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
+
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+ struct IConfig;
+
+ struct CaseSensitive { enum Choice {
+ Yes,
+ No
+ }; };
+
+ class NonCopyable {
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ NonCopyable( NonCopyable const& ) = delete;
+ NonCopyable( NonCopyable && ) = delete;
+ NonCopyable& operator = ( NonCopyable const& ) = delete;
+ NonCopyable& operator = ( NonCopyable && ) = delete;
+#else
+ NonCopyable( NonCopyable const& info );
+ NonCopyable& operator = ( NonCopyable const& );
+#endif
+
+ protected:
+ NonCopyable() {}
+ virtual ~NonCopyable();
+ };
+
+ class SafeBool {
+ public:
+ typedef void (SafeBool::*type)() const;
+
+ static type makeSafe( bool value ) {
+ return value ? &SafeBool::trueValue : 0;
+ }
+ private:
+ void trueValue() const {}
+ };
+
+ template<typename ContainerT>
+ inline void deleteAll( ContainerT& container ) {
+ typename ContainerT::const_iterator it = container.begin();
+ typename ContainerT::const_iterator itEnd = container.end();
+ for(; it != itEnd; ++it )
+ delete *it;
+ }
+ template<typename AssociativeContainerT>
+ inline void deleteAllValues( AssociativeContainerT& container ) {
+ typename AssociativeContainerT::const_iterator it = container.begin();
+ typename AssociativeContainerT::const_iterator itEnd = container.end();
+ for(; it != itEnd; ++it )
+ delete it->second;
+ }
+
+ bool startsWith( std::string const& s, std::string const& prefix );
+ bool startsWith( std::string const& s, char prefix );
+ bool endsWith( std::string const& s, std::string const& suffix );
+ bool endsWith( std::string const& s, char suffix );
+ bool contains( std::string const& s, std::string const& infix );
+ void toLowerInPlace( std::string& s );
+ std::string toLower( std::string const& s );
+ std::string trim( std::string const& str );
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+ struct pluralise {
+ pluralise( std::size_t count, std::string const& label );
+
+ friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+ std::size_t m_count;
+ std::string m_label;
+ };
+
+ struct SourceLineInfo {
+
+ SourceLineInfo();
+ SourceLineInfo( char const* _file, std::size_t _line );
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ SourceLineInfo(SourceLineInfo const& other) = default;
+ SourceLineInfo( SourceLineInfo && ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+ SourceLineInfo& operator = ( SourceLineInfo && ) = default;
+# endif
+ bool empty() const;
+ bool operator == ( SourceLineInfo const& other ) const;
+ bool operator < ( SourceLineInfo const& other ) const;
+
+ char const* file;
+ std::size_t line;
+ };
+
+ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+ // This is just here to avoid compiler warnings with macro constants and boolean literals
+ inline bool isTrue( bool value ){ return value; }
+ inline bool alwaysTrue() { return true; }
+ inline bool alwaysFalse() { return false; }
+
+ void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
+
+ void seedRng( IConfig const& config );
+ unsigned int rngSeed();
+
+ // Use this in variadic streaming macros to allow
+ // >> +StreamEndStop
+ // as well as
+ // >> stuff +StreamEndStop
+ struct StreamEndStop {
+ std::string operator+() {
+ return std::string();
+ }
+ };
+ template<typename T>
+ T const& operator + ( T const& value, StreamEndStop ) {
+ return value;
+ }
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
+
+namespace Catch {
+
+ class NotImplementedException : public std::exception
+ {
+ public:
+ NotImplementedException( SourceLineInfo const& lineInfo );
+ NotImplementedException( NotImplementedException const& ) {}
+
+ virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+ virtual const char* what() const CATCH_NOEXCEPT;
+
+ private:
+ std::string m_what;
+ SourceLineInfo m_lineInfo;
+ };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct IGeneratorInfo {
+ virtual ~IGeneratorInfo();
+ virtual bool moveNext() = 0;
+ virtual std::size_t getCurrentIndex() const = 0;
+ };
+
+ struct IGeneratorsForTest {
+ virtual ~IGeneratorsForTest();
+
+ virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
+ virtual bool moveNext() = 0;
+ };
+
+ IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+ // An intrusive reference counting smart pointer.
+ // T must implement addRef() and release() methods
+ // typically implementing the IShared interface
+ template<typename T>
+ class Ptr {
+ public:
+ Ptr() : m_p( CATCH_NULL ){}
+ Ptr( T* p ) : m_p( p ){
+ if( m_p )
+ m_p->addRef();
+ }
+ Ptr( Ptr const& other ) : m_p( other.m_p ){
+ if( m_p )
+ m_p->addRef();
+ }
+ ~Ptr(){
+ if( m_p )
+ m_p->release();
+ }
+ void reset() {
+ if( m_p )
+ m_p->release();
+ m_p = CATCH_NULL;
+ }
+ Ptr& operator = ( T* p ){
+ Ptr temp( p );
+ swap( temp );
+ return *this;
+ }
+ Ptr& operator = ( Ptr const& other ){
+ Ptr temp( other );
+ swap( temp );
+ return *this;
+ }
+ void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
+ T* get() const{ return m_p; }
+ T& operator*() const { return *m_p; }
+ T* operator->() const { return m_p; }
+ bool operator !() const { return m_p == CATCH_NULL; }
+ operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
+
+ private:
+ T* m_p;
+ };
+
+ struct IShared : NonCopyable {
+ virtual ~IShared();
+ virtual void addRef() const = 0;
+ virtual void release() const = 0;
+ };
+
+ template<typename T = IShared>
+ struct SharedImpl : T {
+
+ SharedImpl() : m_rc( 0 ){}
+
+ virtual void addRef() const {
+ ++m_rc;
+ }
+ virtual void release() const {
+ if( --m_rc == 0 )
+ delete this;
+ }
+
+ mutable unsigned int m_rc;
+ };
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+ class TestCase;
+ class Stream;
+ struct IResultCapture;
+ struct IRunner;
+ struct IGeneratorsForTest;
+ struct IConfig;
+
+ struct IContext
+ {
+ virtual ~IContext();
+
+ virtual IResultCapture* getResultCapture() = 0;
+ virtual IRunner* getRunner() = 0;
+ virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
+ virtual bool advanceGeneratorsForCurrentTest() = 0;
+ virtual Ptr<IConfig const> getConfig() const = 0;
+ };
+
+ struct IMutableContext : IContext
+ {
+ virtual ~IMutableContext();
+ virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+ virtual void setRunner( IRunner* runner ) = 0;
+ virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
+ };
+
+ IContext& getCurrentContext();
+ IMutableContext& getCurrentMutableContext();
+ void cleanUpContext();
+ Stream createStream( std::string const& streamName );
+
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+ class TestSpec;
+
+ struct ITestCase : IShared {
+ virtual void invoke () const = 0;
+ protected:
+ virtual ~ITestCase();
+ };
+
+ class TestCase;
+ struct IConfig;
+
+ struct ITestCaseRegistry {
+ virtual ~ITestCaseRegistry();
+ virtual std::vector<TestCase> const& getAllTests() const = 0;
+ virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+ };
+
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+namespace Catch {
+
+template<typename C>
+class MethodTestCase : public SharedImpl<ITestCase> {
+
+public:
+ MethodTestCase( void (C::*method)() ) : m_method( method ) {}
+
+ virtual void invoke() const {
+ C obj;
+ (obj.*m_method)();
+ }
+
+private:
+ virtual ~MethodTestCase() {}
+
+ void (C::*m_method)();
+};
+
+typedef void(*TestFunction)();
+
+struct NameAndDesc {
+ NameAndDesc( const char* _name = "", const char* _description= "" )
+ : name( _name ), description( _description )
+ {}
+
+ const char* name;
+ const char* description;
+};
+
+void registerTestCase
+ ( ITestCase* testCase,
+ char const* className,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo );
+
+struct AutoReg {
+
+ AutoReg
+ ( TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc );
+
+ template<typename C>
+ AutoReg
+ ( void (C::*method)(),
+ char const* className,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo ) {
+
+ registerTestCase
+ ( new MethodTestCase<C>( method ),
+ className,
+ nameAndDesc,
+ lineInfo );
+ }
+
+ ~AutoReg();
+
+private:
+ AutoReg( AutoReg const& );
+ void operator= ( AutoReg const& );
+};
+
+void registerTestCaseFunction
+ ( TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc );
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+ static void TestName(); \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
+ static void TestName()
+ #define INTERNAL_CATCH_TESTCASE( ... ) \
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ namespace{ \
+ struct TestName : ClassName{ \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
+ } \
+ void TestName::test()
+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) );
+
+#else
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
+ static void TestName(); \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+ static void TestName()
+ #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
+ namespace{ \
+ struct TestCaseName : ClassName{ \
+ void test(); \
+ }; \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
+ } \
+ void TestCaseName::test()
+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
+
+ ///////////////////////////////////////////////////////////////////////////////
+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
+ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) );
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+ // ResultWas::OfType enum
+ struct ResultWas { enum OfType {
+ Unknown = -1,
+ Ok = 0,
+ Info = 1,
+ Warning = 2,
+
+ FailureBit = 0x10,
+
+ ExpressionFailed = FailureBit | 1,
+ ExplicitFailure = FailureBit | 2,
+
+ Exception = 0x100 | FailureBit,
+
+ ThrewException = Exception | 1,
+ DidntThrowException = Exception | 2,
+
+ FatalErrorCondition = 0x200 | FailureBit
+
+ }; };
+
+ inline bool isOk( ResultWas::OfType resultType ) {
+ return ( resultType & ResultWas::FailureBit ) == 0;
+ }
+ inline bool isJustInfo( int flags ) {
+ return flags == ResultWas::Info;
+ }
+
+ // ResultDisposition::Flags enum
+ struct ResultDisposition { enum Flags {
+ Normal = 0x01,
+
+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
+ FalseTest = 0x04, // Prefix expression with !
+ SuppressFail = 0x08 // Failures are reported but do not fail the test
+ }; };
+
+ inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+ return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+ }
+
+ inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+ inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
+ inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+ struct DecomposedExpression
+ {
+ virtual ~DecomposedExpression() {}
+ virtual bool isBinaryExpression() const {
+ return false;
+ }
+ virtual void reconstructExpression( std::string& dest ) const = 0;
+
+ // Only simple binary comparisons can be decomposed.
+ // If more complex check is required then wrap sub-expressions in parentheses.
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
+ template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
+
+ private:
+ DecomposedExpression& operator = (DecomposedExpression const&);
+ };
+
+ struct AssertionInfo
+ {
+ AssertionInfo() {}
+ AssertionInfo( std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ std::string const& _capturedExpression,
+ ResultDisposition::Flags _resultDisposition );
+
+ std::string macroName;
+ SourceLineInfo lineInfo;
+ std::string capturedExpression;
+ ResultDisposition::Flags resultDisposition;
+ };
+
+ struct AssertionResultData
+ {
+ AssertionResultData() : decomposedExpression( CATCH_NULL )
+ , resultType( ResultWas::Unknown )
+ , negated( false )
+ , parenthesized( false ) {}
+
+ void negate( bool parenthesize ) {
+ negated = !negated;
+ parenthesized = parenthesize;
+ if( resultType == ResultWas::Ok )
+ resultType = ResultWas::ExpressionFailed;
+ else if( resultType == ResultWas::ExpressionFailed )
+ resultType = ResultWas::Ok;
+ }
+
+ std::string const& reconstructExpression() const {
+ if( decomposedExpression != CATCH_NULL ) {
+ decomposedExpression->reconstructExpression( reconstructedExpression );
+ if( parenthesized ) {
+ reconstructedExpression.insert( 0, 1, '(' );
+ reconstructedExpression.append( 1, ')' );
+ }
+ if( negated ) {
+ reconstructedExpression.insert( 0, 1, '!' );
+ }
+ decomposedExpression = CATCH_NULL;
+ }
+ return reconstructedExpression;
+ }
+
+ mutable DecomposedExpression const* decomposedExpression;
+ mutable std::string reconstructedExpression;
+ std::string message;
+ ResultWas::OfType resultType;
+ bool negated;
+ bool parenthesized;
+ };
+
+ class AssertionResult {
+ public:
+ AssertionResult();
+ AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+ ~AssertionResult();
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ AssertionResult( AssertionResult const& ) = default;
+ AssertionResult( AssertionResult && ) = default;
+ AssertionResult& operator = ( AssertionResult const& ) = default;
+ AssertionResult& operator = ( AssertionResult && ) = default;
+# endif
+
+ bool isOk() const;
+ bool succeeded() const;
+ ResultWas::OfType getResultType() const;
+ bool hasExpression() const;
+ bool hasMessage() const;
+ std::string getExpression() const;
+ std::string getExpressionInMacro() const;
+ bool hasExpandedExpression() const;
+ std::string getExpandedExpression() const;
+ std::string getMessage() const;
+ SourceLineInfo getSourceInfo() const;
+ std::string getTestMacroName() const;
+ void discardDecomposedExpression() const;
+ void expandDecomposedExpression() const;
+
+ protected:
+ AssertionInfo m_info;
+ AssertionResultData m_resultData;
+ };
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+ namespace Impl {
+
+ template<typename ArgT> struct MatchAllOf;
+ template<typename ArgT> struct MatchAnyOf;
+ template<typename ArgT> struct MatchNotOf;
+
+ class MatcherUntypedBase {
+ public:
+ std::string toString() const {
+ if( m_cachedToString.empty() )
+ m_cachedToString = describe();
+ return m_cachedToString;
+ }
+
+ protected:
+ virtual std::string describe() const = 0;
+ mutable std::string m_cachedToString;
+ private:
+ MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
+ };
+
+ template<typename ObjectT, typename ComparatorT = ObjectT>
+ struct MatcherBase : MatcherUntypedBase {
+
+ virtual bool match( ObjectT const& arg ) const = 0;
+
+ MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
+ MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
+ MatchNotOf<ComparatorT> operator ! () const;
+ };
+
+ template<typename ArgT>
+ struct MatchAllOf : MatcherBase<ArgT> {
+ virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+ for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+ if (!m_matchers[i]->match(arg))
+ return false;
+ }
+ return true;
+ }
+ virtual std::string describe() const CATCH_OVERRIDE {
+ std::string description;
+ description.reserve( 4 + m_matchers.size()*32 );
+ description += "( ";
+ for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+ if( i != 0 )
+ description += " and ";
+ description += m_matchers[i]->toString();
+ }
+ description += " )";
+ return description;
+ }
+
+ MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
+ m_matchers.push_back( &other );
+ return *this;
+ }
+
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
+ };
+ template<typename ArgT>
+ struct MatchAnyOf : MatcherBase<ArgT> {
+
+ virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+ for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+ if (m_matchers[i]->match(arg))
+ return true;
+ }
+ return false;
+ }
+ virtual std::string describe() const CATCH_OVERRIDE {
+ std::string description;
+ description.reserve( 4 + m_matchers.size()*32 );
+ description += "( ";
+ for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+ if( i != 0 )
+ description += " or ";
+ description += m_matchers[i]->toString();
+ }
+ description += " )";
+ return description;
+ }
+
+ MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
+ m_matchers.push_back( &other );
+ return *this;
+ }
+
+ std::vector<MatcherBase<ArgT> const*> m_matchers;
+ };
+
+ template<typename ArgT>
+ struct MatchNotOf : MatcherBase<ArgT> {
+
+ MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
+
+ virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+ return !m_underlyingMatcher.match( arg );
+ }
+
+ virtual std::string describe() const CATCH_OVERRIDE {
+ return "not " + m_underlyingMatcher.toString();
+ }
+ MatcherBase<ArgT> const& m_underlyingMatcher;
+ };
+
+ template<typename ObjectT, typename ComparatorT>
+ MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
+ return MatchAllOf<ComparatorT>() && *this && other;
+ }
+ template<typename ObjectT, typename ComparatorT>
+ MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
+ return MatchAnyOf<ComparatorT>() || *this || other;
+ }
+ template<typename ObjectT, typename ComparatorT>
+ MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
+ return MatchNotOf<ComparatorT>( *this );
+ }
+
+ } // namespace Impl
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+ // - deprecated: prefer ||, && and !
+ template<typename T>
+ inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+ return Impl::MatchNotOf<T>( underlyingMatcher );
+ }
+ template<typename T>
+ inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+ return Impl::MatchAllOf<T>() && m1 && m2;
+ }
+ template<typename T>
+ inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+ return Impl::MatchAllOf<T>() && m1 && m2 && m3;
+ }
+ template<typename T>
+ inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+ return Impl::MatchAnyOf<T>() || m1 || m2;
+ }
+ template<typename T>
+ inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+ return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
+ }
+
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+
+namespace Catch {
+
+ struct TestFailureException{};
+
+ template<typename T> class ExpressionLhs;
+
+ struct CopyableStream {
+ CopyableStream() {}
+ CopyableStream( CopyableStream const& other ) {
+ oss << other.oss.str();
+ }
+ CopyableStream& operator=( CopyableStream const& other ) {
+ oss.str(std::string());
+ oss << other.oss.str();
+ return *this;
+ }
+ std::ostringstream oss;
+ };
+
+ class ResultBuilder : public DecomposedExpression {
+ public:
+ ResultBuilder( char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition,
+ char const* secondArg = "" );
+
+ template<typename T>
+ ExpressionLhs<T const&> operator <= ( T const& operand );
+ ExpressionLhs<bool> operator <= ( bool value );
+
+ template<typename T>
+ ResultBuilder& operator << ( T const& value ) {
+ m_stream.oss << value;
+ return *this;
+ }
+
+ ResultBuilder& setResultType( ResultWas::OfType result );
+ ResultBuilder& setResultType( bool result );
+
+ void endExpression( DecomposedExpression const& expr );
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
+
+ AssertionResult build() const;
+ AssertionResult build( DecomposedExpression const& expr ) const;
+
+ void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
+ void captureResult( ResultWas::OfType resultType );
+ void captureExpression();
+ void captureExpectedException( std::string const& expectedMessage );
+ void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
+ void handleResult( AssertionResult const& result );
+ void react();
+ bool shouldDebugBreak() const;
+ bool allowThrows() const;
+
+ template<typename ArgT, typename MatcherT>
+ void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
+
+ private:
+ AssertionInfo m_assertionInfo;
+ AssertionResultData m_data;
+ CopyableStream m_stream;
+
+ bool m_shouldDebugBreak;
+ bool m_shouldThrow;
+ };
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+ enum Operator {
+ IsEqualTo,
+ IsNotEqualTo,
+ IsLessThan,
+ IsGreaterThan,
+ IsLessThanOrEqualTo,
+ IsGreaterThanOrEqualTo
+ };
+
+ template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
+ template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
+ template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
+ template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
+ template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
+ template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
+ template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
+
+ template<typename T>
+ inline T& opCast(T const& t) { return const_cast<T&>(t); }
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+ inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+ // So the compare overloads can be operator agnostic we convey the operator as a template
+ // enum, which is used to specialise an Evaluator for doing the comparison.
+ template<typename T1, typename T2, Operator Op>
+ class Evaluator{};
+
+ template<typename T1, typename T2>
+ struct Evaluator<T1, T2, IsEqualTo> {
+ static bool evaluate( T1 const& lhs, T2 const& rhs) {
+ return bool( opCast( lhs ) == opCast( rhs ) );
+ }
+ };
+ template<typename T1, typename T2>
+ struct Evaluator<T1, T2, IsNotEqualTo> {
+ static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+ return bool( opCast( lhs ) != opCast( rhs ) );
+ }
+ };
+ template<typename T1, typename T2>
+ struct Evaluator<T1, T2, IsLessThan> {
+ static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+ return bool( opCast( lhs ) < opCast( rhs ) );
+ }
+ };
+ template<typename T1, typename T2>
+ struct Evaluator<T1, T2, IsGreaterThan> {
+ static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+ return bool( opCast( lhs ) > opCast( rhs ) );
+ }
+ };
+ template<typename T1, typename T2>
+ struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
+ static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+ return bool( opCast( lhs ) >= opCast( rhs ) );
+ }
+ };
+ template<typename T1, typename T2>
+ struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
+ static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+ return bool( opCast( lhs ) <= opCast( rhs ) );
+ }
+ };
+
+ template<Operator Op, typename T1, typename T2>
+ bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
+ return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+ }
+
+ // This level of indirection allows us to specialise for integer types
+ // to avoid signed/ unsigned warnings
+
+ // "base" overload
+ template<Operator Op, typename T1, typename T2>
+ bool compare( T1 const& lhs, T2 const& rhs ) {
+ return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+ }
+
+ // unsigned X to int
+ template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
+ return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+ }
+ template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
+ return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+ }
+ template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
+ return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+ }
+
+ // unsigned X to long
+ template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
+ return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+ }
+ template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
+ return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+ }
+ template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
+ return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+ }
+
+ // int to unsigned X
+ template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+ }
+
+ // long to unsigned X
+ template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+
+ // pointer to long (when comparing against NULL)
+ template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+ }
+ template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+ }
+
+ // pointer to int (when comparing against NULL)
+ template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+ }
+ template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+ }
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+ // long long to unsigned X
+ template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
+ return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+ }
+
+ // unsigned long long to X
+ template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+ }
+ template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
+ return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+ }
+
+ // pointer to long long (when comparing against NULL)
+ template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+ }
+ template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+ }
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+ // pointer to nullptr_t (when comparing against nullptr)
+ template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
+ return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
+ }
+ template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
+ return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
+ }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <vector>
+#include <cstddef>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+ [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+ if( [obj respondsToSelector: sel] )
+ return [obj performSelector: sel];
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+ if( [obj respondsToSelector: sel] )
+ return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template<typename T>
+std::string toString( T const& value );
+
+// Built in overloads
+
+std::string toString( std::string const& value );
+std::string toString( std::wstring const& value );
+std::string toString( const char* const value );
+std::string toString( char* const value );
+std::string toString( const wchar_t* const value );
+std::string toString( wchar_t* const value );
+std::string toString( int value );
+std::string toString( unsigned long value );
+std::string toString( unsigned int value );
+std::string toString( const double value );
+std::string toString( const float value );
+std::string toString( bool value );
+std::string toString( char value );
+std::string toString( signed char value );
+std::string toString( unsigned char value );
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value );
+std::string toString( unsigned long long value );
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t );
+#endif
+
+#ifdef __OBJC__
+ std::string toString( NSString const * const& nsstring );
+ std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
+ std::string toString( NSObject* const& nsObject );
+#endif
+
+namespace Detail {
+
+ extern const std::string unprintableString;
+
+ struct BorgType {
+ template<typename T> BorgType( T const& );
+ };
+
+ struct TrueType { char sizer[1]; };
+ struct FalseType { char sizer[2]; };
+
+ TrueType& testStreamable( std::ostream& );
+ FalseType testStreamable( FalseType );
+
+ FalseType operator<<( std::ostream const&, BorgType const& );
+
+ template<typename T>
+ struct IsStreamInsertable {
+ static std::ostream &s;
+ static T const&t;
+ enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
+ };
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+ template<typename T,
+ bool IsEnum = std::is_enum<T>::value
+ >
+ struct EnumStringMaker
+ {
+ static std::string convert( T const& ) { return unprintableString; }
+ };
+
+ template<typename T>
+ struct EnumStringMaker<T,true>
+ {
+ static std::string convert( T const& v )
+ {
+ return ::Catch::toString(
+ static_cast<typename std::underlying_type<T>::type>(v)
+ );
+ }
+ };
+#endif
+ template<bool C>
+ struct StringMakerBase {
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+ template<typename T>
+ static std::string convert( T const& v )
+ {
+ return EnumStringMaker<T>::convert( v );
+ }
+#else
+ template<typename T>
+ static std::string convert( T const& ) { return unprintableString; }
+#endif
+ };
+
+ template<>
+ struct StringMakerBase<true> {
+ template<typename T>
+ static std::string convert( T const& _value ) {
+ std::ostringstream oss;
+ oss << _value;
+ return oss.str();
+ }
+ };
+
+ std::string rawMemoryToString( const void *object, std::size_t size );
+
+ template<typename T>
+ inline std::string rawMemoryToString( const T& object ) {
+ return rawMemoryToString( &object, sizeof(object) );
+ }
+
+} // end namespace Detail
+
+template<typename T>
+struct StringMaker :
+ Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
+
+template<typename T>
+struct StringMaker<T*> {
+ template<typename U>
+ static std::string convert( U* p ) {
+ if( !p )
+ return "NULL";
+ else
+ return Detail::rawMemoryToString( p );
+ }
+};
+
+template<typename R, typename C>
+struct StringMaker<R C::*> {
+ static std::string convert( R C::* p ) {
+ if( !p )
+ return "NULL";
+ else
+ return Detail::rawMemoryToString( p );
+ }
+};
+
+namespace Detail {
+ template<typename InputIterator>
+ std::string rangeToString( InputIterator first, InputIterator last );
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+// static std::string convert( std::vector<T,Allocator> const& v ) {
+// return Detail::rangeToString( v.begin(), v.end() );
+// }
+//};
+
+template<typename T, typename Allocator>
+std::string toString( std::vector<T,Allocator> const& v ) {
+ return Detail::rangeToString( v.begin(), v.end() );
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+ template<
+ typename Tuple,
+ std::size_t N = 0,
+ bool = (N < std::tuple_size<Tuple>::value)
+ >
+ struct ElementPrinter {
+ static void print( const Tuple& tuple, std::ostream& os )
+ {
+ os << ( N ? ", " : " " )
+ << Catch::toString(std::get<N>(tuple));
+ ElementPrinter<Tuple,N+1>::print(tuple,os);
+ }
+ };
+
+ template<
+ typename Tuple,
+ std::size_t N
+ >
+ struct ElementPrinter<Tuple,N,false> {
+ static void print( const Tuple&, std::ostream& ) {}
+ };
+
+}
+
+template<typename ...Types>
+struct StringMaker<std::tuple<Types...>> {
+
+ static std::string convert( const std::tuple<Types...>& tuple )
+ {
+ std::ostringstream os;
+ os << '{';
+ TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
+ os << " }";
+ return os.str();
+ }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+ template<typename T>
+ std::string makeString( T const& value ) {
+ return StringMaker<T>::convert( value );
+ }
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template<typename T>
+std::string toString( T const& value ) {
+ return StringMaker<T>::convert( value );
+}
+
+ namespace Detail {
+ template<typename InputIterator>
+ std::string rangeToString( InputIterator first, InputIterator last ) {
+ std::ostringstream oss;
+ oss << "{ ";
+ if( first != last ) {
+ oss << Catch::toString( *first );
+ for( ++first ; first != last ; ++first )
+ oss << ", " << Catch::toString( *first );
+ }
+ oss << " }";
+ return oss.str();
+ }
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression;
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression;
+
+// Wraps the LHS of an expression and overloads comparison operators
+// for also capturing those and RHS (if any)
+template<typename T>
+class ExpressionLhs : public DecomposedExpression {
+public:
+ ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
+
+ ExpressionLhs& operator = ( const ExpressionLhs& );
+
+ template<typename RhsT>
+ BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
+ operator == ( RhsT const& rhs ) {
+ return captureExpression<Internal::IsEqualTo>( rhs );
+ }
+
+ template<typename RhsT>
+ BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
+ operator != ( RhsT const& rhs ) {
+ return captureExpression<Internal::IsNotEqualTo>( rhs );
+ }
+
+ template<typename RhsT>
+ BinaryExpression<T, Internal::IsLessThan, RhsT const&>
+ operator < ( RhsT const& rhs ) {
+ return captureExpression<Internal::IsLessThan>( rhs );
+ }
+
+ template<typename RhsT>
+ BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
+ operator > ( RhsT const& rhs ) {
+ return captureExpression<Internal::IsGreaterThan>( rhs );
+ }
+
+ template<typename RhsT>
+ BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
+ operator <= ( RhsT const& rhs ) {
+ return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
+ }
+
+ template<typename RhsT>
+ BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
+ operator >= ( RhsT const& rhs ) {
+ return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
+ }
+
+ BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
+ return captureExpression<Internal::IsEqualTo>( rhs );
+ }
+
+ BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
+ return captureExpression<Internal::IsNotEqualTo>( rhs );
+ }
+
+ void endExpression() {
+ m_truthy = m_lhs ? true : false;
+ m_rb
+ .setResultType( m_truthy )
+ .endExpression( *this );
+ }
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+ dest = Catch::toString( m_truthy );
+ }
+
+private:
+ template<Internal::Operator Op, typename RhsT>
+ BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
+ return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
+ }
+
+ template<Internal::Operator Op>
+ BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
+ return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
+ }
+
+private:
+ ResultBuilder& m_rb;
+ T m_lhs;
+ bool m_truthy;
+};
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression : public DecomposedExpression {
+public:
+ BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
+ : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
+
+ BinaryExpression& operator = ( BinaryExpression& );
+
+ void endExpression() const {
+ m_rb
+ .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
+ .endExpression( *this );
+ }
+
+ virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+ return true;
+ }
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+ std::string lhs = Catch::toString( m_lhs );
+ std::string rhs = Catch::toString( m_rhs );
+ char delim = lhs.size() + rhs.size() < 40 &&
+ lhs.find('\n') == std::string::npos &&
+ rhs.find('\n') == std::string::npos ? ' ' : '\n';
+ dest.reserve( 7 + lhs.size() + rhs.size() );
+ // 2 for spaces around operator
+ // 2 for operator
+ // 2 for parentheses (conditionally added later)
+ // 1 for negation (conditionally added later)
+ dest = lhs;
+ dest += delim;
+ dest += Internal::OperatorTraits<Op>::getName();
+ dest += delim;
+ dest += rhs;
+ }
+
+private:
+ ResultBuilder& m_rb;
+ LhsT m_lhs;
+ RhsT m_rhs;
+};
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression : public DecomposedExpression {
+public:
+ MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
+ : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
+
+ virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+ return true;
+ }
+
+ virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+ std::string matcherAsString = m_matcher.toString();
+ dest = Catch::toString( m_arg );
+ dest += ' ';
+ if( matcherAsString == Detail::unprintableString )
+ dest += m_matcherString;
+ else
+ dest += matcherAsString;
+ }
+
+private:
+ ArgT m_arg;
+ MatcherT m_matcher;
+ char const* m_matcherString;
+};
+
+} // end namespace Catch
+
+
+namespace Catch {
+
+ template<typename T>
+ inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
+ return ExpressionLhs<T const&>( *this, operand );
+ }
+
+ inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
+ return ExpressionLhs<bool>( *this, value );
+ }
+
+ template<typename ArgT, typename MatcherT>
+ inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+ char const* matcherString ) {
+ MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
+ setResultType( matcher.match( arg ) );
+ endExpression( expr );
+ }
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct MessageInfo {
+ MessageInfo( std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type );
+
+ std::string macroName;
+ SourceLineInfo lineInfo;
+ ResultWas::OfType type;
+ std::string message;
+ unsigned int sequence;
+
+ bool operator == ( MessageInfo const& other ) const {
+ return sequence == other.sequence;
+ }
+ bool operator < ( MessageInfo const& other ) const {
+ return sequence < other.sequence;
+ }
+ private:
+ static unsigned int globalCount;
+ };
+
+ struct MessageBuilder {
+ MessageBuilder( std::string const& macroName,
+ SourceLineInfo const& lineInfo,
+ ResultWas::OfType type )
+ : m_info( macroName, lineInfo, type )
+ {}
+
+ template<typename T>
+ MessageBuilder& operator << ( T const& value ) {
+ m_stream << value;
+ return *this;
+ }
+
+ MessageInfo m_info;
+ std::ostringstream m_stream;
+ };
+
+ class ScopedMessage {
+ public:
+ ScopedMessage( MessageBuilder const& builder );
+ ScopedMessage( ScopedMessage const& other );
+ ~ScopedMessage();
+
+ MessageInfo m_info;
+ };
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ class TestCase;
+ class AssertionResult;
+ struct AssertionInfo;
+ struct SectionInfo;
+ struct SectionEndInfo;
+ struct MessageInfo;
+ class ScopedMessageBuilder;
+ struct Counts;
+
+ struct IResultCapture {
+
+ virtual ~IResultCapture();
+
+ virtual void assertionEnded( AssertionResult const& result ) = 0;
+ virtual bool sectionStarted( SectionInfo const& sectionInfo,
+ Counts& assertions ) = 0;
+ virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+ virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+ virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+ virtual std::string getCurrentTestName() const = 0;
+ virtual const AssertionResult* getLastResult() const = 0;
+
+ virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+ };
+
+ IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# define CATCH_PLATFORM_MAC
+#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+# define CATCH_PLATFORM_IPHONE
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+# define CATCH_PLATFORM_LINUX
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+# define CATCH_PLATFORM_WINDOWS
+# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+# define CATCH_DEFINES_NOMINMAX
+# endif
+# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+# endif
+#endif
+
+#include <string>
+
+namespace Catch{
+
+ bool isDebuggerActive();
+ void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+ // The following code snippet based on:
+ // http://cocoawithlove.com/2008/03/break-into-debugger.html
+ #if defined(__ppc64__) || defined(__ppc__)
+ #define CATCH_TRAP() \
+ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+ : : : "memory","r0","r3","r4" )
+ #else
+ #define CATCH_TRAP() __asm__("int $3\n" : : )
+ #endif
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ // If we can use inline assembler, do it because this allows us to break
+ // directly at the location of the failing check instead of breaking inside
+ // raise() called from it, i.e. one stack frame below.
+ #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+ #define CATCH_TRAP() asm volatile ("int $3")
+ #else // Fall back to the generic way.
+ #include <signal.h>
+
+ #define CATCH_TRAP() raise(SIGTRAP)
+ #endif
+#elif defined(_MSC_VER)
+ #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+ #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+ #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+ class TestCase;
+
+ struct IRunner {
+ virtual ~IRunner();
+ virtual bool aborting() const = 0;
+ };
+}
+
+// #included from: catch_type_traits.hpp
+#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+ template <typename T>
+ using add_lvalue_reference = std::add_lvalue_reference<T>;
+
+ template <typename T>
+ using add_const = std::add_const<T>;
+
+#else
+
+ template <typename T>
+ struct add_const {
+ typedef const T type;
+ };
+
+ template <typename T>
+ struct add_lvalue_reference {
+ typedef T& type;
+ };
+ template <typename T>
+ struct add_lvalue_reference<T&> {
+ typedef T& type;
+ };
+ // No && overload, because that is C++11, in which case we have
+ // proper type_traits implementation from the standard library
+
+#endif
+
+}
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+///////////////////////////////////////////////////////////////////////////////
+// We can speedup compilation significantly by breaking into debugger lower in
+// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
+// macro in each assertion
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+ resultBuilder.react();
+#else
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
+ resultBuilder.react();
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+ try { \
+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ ( __catchResult <= expr ).endExpression(); \
+ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ } \
+ catch( ... ) { \
+ __catchResult.useActiveException( resultDisposition ); \
+ } \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+ // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
+ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+ if( Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
+ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+ if( !Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+ try { \
+ static_cast<void>(expr); \
+ __catchResult.captureResult( Catch::ResultWas::Ok ); \
+ } \
+ catch( ... ) { \
+ __catchResult.useActiveException( resultDisposition ); \
+ } \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
+ if( __catchResult.allowThrows() ) \
+ try { \
+ static_cast<void>(expr); \
+ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+ } \
+ catch( ... ) { \
+ __catchResult.captureExpectedException( matcher ); \
+ } \
+ else \
+ __catchResult.captureResult( Catch::ResultWas::Ok ); \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
+ if( __catchResult.allowThrows() ) \
+ try { \
+ static_cast<void>(expr); \
+ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+ } \
+ catch( Catch::add_const<Catch::add_lvalue_reference<exceptionType>::type>::type ) { \
+ __catchResult.captureResult( Catch::ResultWas::Ok ); \
+ } \
+ catch( ... ) { \
+ __catchResult.useActiveException( resultDisposition ); \
+ } \
+ else \
+ __catchResult.captureResult( Catch::ResultWas::Ok ); \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+ #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+ __catchResult.captureResult( messageType ); \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+#else
+ #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+ __catchResult << log + ::Catch::StreamEndStop(); \
+ __catchResult.captureResult( messageType ); \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( log, macroName ) \
+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
+ try { \
+ __catchResult.captureMatch( arg, matcher, #matcher ); \
+ } catch( ... ) { \
+ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
+ } \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+ struct Counts {
+ Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
+
+ Counts operator - ( Counts const& other ) const {
+ Counts diff;
+ diff.passed = passed - other.passed;
+ diff.failed = failed - other.failed;
+ diff.failedButOk = failedButOk - other.failedButOk;
+ return diff;
+ }
+ Counts& operator += ( Counts const& other ) {
+ passed += other.passed;
+ failed += other.failed;
+ failedButOk += other.failedButOk;
+ return *this;
+ }
+
+ std::size_t total() const {
+ return passed + failed + failedButOk;
+ }
+ bool allPassed() const {
+ return failed == 0 && failedButOk == 0;
+ }
+ bool allOk() const {
+ return failed == 0;
+ }
+
+ std::size_t passed;
+ std::size_t failed;
+ std::size_t failedButOk;
+ };
+
+ struct Totals {
+
+ Totals operator - ( Totals const& other ) const {
+ Totals diff;
+ diff.assertions = assertions - other.assertions;
+ diff.testCases = testCases - other.testCases;
+ return diff;
+ }
+
+ Totals delta( Totals const& prevTotals ) const {
+ Totals diff = *this - prevTotals;
+ if( diff.assertions.failed > 0 )
+ ++diff.testCases.failed;
+ else if( diff.assertions.failedButOk > 0 )
+ ++diff.testCases.failedButOk;
+ else
+ ++diff.testCases.passed;
+ return diff;
+ }
+
+ Totals& operator += ( Totals const& other ) {
+ assertions += other.assertions;
+ testCases += other.testCases;
+ return *this;
+ }
+
+ Counts assertions;
+ Counts testCases;
+ };
+}
+
+#include <string>
+
+namespace Catch {
+
+ struct SectionInfo {
+ SectionInfo
+ ( SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& _description = std::string() );
+
+ std::string name;
+ std::string description;
+ SourceLineInfo lineInfo;
+ };
+
+ struct SectionEndInfo {
+ SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
+ : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
+ {}
+
+ SectionInfo sectionInfo;
+ Counts prevAssertions;
+ double durationInSeconds;
+ };
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef CATCH_PLATFORM_WINDOWS
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace Catch {
+
+ class Timer {
+ public:
+ Timer() : m_ticks( 0 ) {}
+ void start();
+ unsigned int getElapsedMicroseconds() const;
+ unsigned int getElapsedMilliseconds() const;
+ double getElapsedSeconds() const;
+
+ private:
+ uint64_t m_ticks;
+ };
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+ class Section : NonCopyable {
+ public:
+ Section( SectionInfo const& info );
+ ~Section();
+
+ // This indicates whether the section should be executed or not
+ operator bool() const;
+
+ private:
+ SectionInfo m_info;
+
+ std::string m_name;
+ Counts m_assertions;
+ bool m_sectionIncluded;
+ Timer m_timer;
+ };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+ #define INTERNAL_CATCH_SECTION( ... ) \
+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+ #define INTERNAL_CATCH_SECTION( name, desc ) \
+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <iterator>
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+namespace Catch {
+
+template<typename T>
+struct IGenerator {
+ virtual ~IGenerator() {}
+ virtual T getValue( std::size_t index ) const = 0;
+ virtual std::size_t size () const = 0;
+};
+
+template<typename T>
+class BetweenGenerator : public IGenerator<T> {
+public:
+ BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
+
+ virtual T getValue( std::size_t index ) const {
+ return m_from+static_cast<int>( index );
+ }
+
+ virtual std::size_t size() const {
+ return static_cast<std::size_t>( 1+m_to-m_from );
+ }
+
+private:
+
+ T m_from;
+ T m_to;
+};
+
+template<typename T>
+class ValuesGenerator : public IGenerator<T> {
+public:
+ ValuesGenerator(){}
+
+ void add( T value ) {
+ m_values.push_back( value );
+ }
+
+ virtual T getValue( std::size_t index ) const {
+ return m_values[index];
+ }
+
+ virtual std::size_t size() const {
+ return m_values.size();
+ }
+
+private:
+ std::vector<T> m_values;
+};
+
+template<typename T>
+class CompositeGenerator {
+public:
+ CompositeGenerator() : m_totalSize( 0 ) {}
+
+ // *** Move semantics, similar to auto_ptr ***
+ CompositeGenerator( CompositeGenerator& other )
+ : m_fileInfo( other.m_fileInfo ),
+ m_totalSize( 0 )
+ {
+ move( other );
+ }
+
+ CompositeGenerator& setFileInfo( const char* fileInfo ) {
+ m_fileInfo = fileInfo;
+ return *this;
+ }
+
+ ~CompositeGenerator() {
+ deleteAll( m_composed );
+ }
+
+ operator T () const {
+ size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
+
+ typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+ typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+ for( size_t index = 0; it != itEnd; ++it )
+ {
+ const IGenerator<T>* generator = *it;
+ if( overallIndex >= index && overallIndex < index + generator->size() )
+ {
+ return generator->getValue( overallIndex-index );
+ }
+ index += generator->size();
+ }
+ CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
+ return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+ }
+
+ void add( const IGenerator<T>* generator ) {
+ m_totalSize += generator->size();
+ m_composed.push_back( generator );
+ }
+
+ CompositeGenerator& then( CompositeGenerator& other ) {
+ move( other );
+ return *this;
+ }
+
+ CompositeGenerator& then( T value ) {
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add( value );
+ add( valuesGen );
+ return *this;
+ }
+
+private:
+
+ void move( CompositeGenerator& other ) {
+ std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
+ m_totalSize += other.m_totalSize;
+ other.m_composed.clear();
+ }
+
+ std::vector<const IGenerator<T>*> m_composed;
+ std::string m_fileInfo;
+ size_t m_totalSize;
+};
+
+namespace Generators
+{
+ template<typename T>
+ CompositeGenerator<T> between( T from, T to ) {
+ CompositeGenerator<T> generators;
+ generators.add( new BetweenGenerator<T>( from, to ) );
+ return generators;
+ }
+
+ template<typename T>
+ CompositeGenerator<T> values( T val1, T val2 ) {
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add( val1 );
+ valuesGen->add( val2 );
+ generators.add( valuesGen );
+ return generators;
+ }
+
+ template<typename T>
+ CompositeGenerator<T> values( T val1, T val2, T val3 ){
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add( val1 );
+ valuesGen->add( val2 );
+ valuesGen->add( val3 );
+ generators.add( valuesGen );
+ return generators;
+ }
+
+ template<typename T>
+ CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
+ CompositeGenerator<T> generators;
+ ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+ valuesGen->add( val1 );
+ valuesGen->add( val2 );
+ valuesGen->add( val3 );
+ valuesGen->add( val4 );
+ generators.add( valuesGen );
+ return generators;
+ }
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2( line ) #line
+#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
+
+#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ class TestCase;
+ struct ITestCaseRegistry;
+ struct IExceptionTranslatorRegistry;
+ struct IExceptionTranslator;
+ struct IReporterRegistry;
+ struct IReporterFactory;
+
+ struct IRegistryHub {
+ virtual ~IRegistryHub();
+
+ virtual IReporterRegistry const& getReporterRegistry() const = 0;
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+ };
+
+ struct IMutableRegistryHub {
+ virtual ~IMutableRegistryHub();
+ virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
+ virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
+ virtual void registerTest( TestCase const& testInfo ) = 0;
+ virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+ };
+
+ IRegistryHub& getRegistryHub();
+ IMutableRegistryHub& getMutableRegistryHub();
+ void cleanUp();
+ std::string translateActiveException();
+
+}
+
+namespace Catch {
+
+ typedef std::string(*exceptionTranslateFunction)();
+
+ struct IExceptionTranslator;
+ typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+ struct IExceptionTranslator {
+ virtual ~IExceptionTranslator();
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+ };
+
+ struct IExceptionTranslatorRegistry {
+ virtual ~IExceptionTranslatorRegistry();
+
+ virtual std::string translateActiveException() const = 0;
+ };
+
+ class ExceptionTranslatorRegistrar {
+ template<typename T>
+ class ExceptionTranslator : public IExceptionTranslator {
+ public:
+
+ ExceptionTranslator( std::string(*translateFunction)( T& ) )
+ : m_translateFunction( translateFunction )
+ {}
+
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
+ try {
+ if( it == itEnd )
+ throw;
+ else
+ return (*it)->translate( it+1, itEnd );
+ }
+ catch( T& ex ) {
+ return m_translateFunction( ex );
+ }
+ }
+
+ protected:
+ std::string(*m_translateFunction)( T& );
+ };
+
+ public:
+ template<typename T>
+ ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+ getMutableRegistryHub().registerTranslator
+ ( new ExceptionTranslator<T>( translateFunction ) );
+ }
+ };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+ static std::string translatorName( signature ); \
+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
+ static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
+namespace Catch {
+namespace Detail {
+
+ class Approx {
+ public:
+ explicit Approx ( double value )
+ : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+ m_margin( 0.0 ),
+ m_scale( 1.0 ),
+ m_value( value )
+ {}
+
+ Approx( Approx const& other )
+ : m_epsilon( other.m_epsilon ),
+ m_margin( other.m_margin ),
+ m_scale( other.m_scale ),
+ m_value( other.m_value )
+ {}
+
+ static Approx custom() {
+ return Approx( 0 );
+ }
+
+ Approx operator()( double value ) {
+ Approx approx( value );
+ approx.epsilon( m_epsilon );
+ approx.margin( m_margin );
+ approx.scale( m_scale );
+ return approx;
+ }
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator == ( const T& lhs, Approx const& rhs ) {
+ // Thanks to Richard Harris for his help refining this formula
+ auto lhs_v = double(lhs);
+ bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
+ if (relativeOK) {
+ return true;
+ }
+ return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator == ( Approx const& lhs, const T& rhs ) {
+ return operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator != ( T lhs, Approx const& rhs ) {
+ return !operator==( lhs, rhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator != ( Approx const& lhs, T rhs ) {
+ return !operator==( rhs, lhs );
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( T lhs, Approx const& rhs )
+ {
+ return double(lhs) < rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator <= ( Approx const& lhs, T rhs )
+ {
+ return lhs.m_value < double(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( T lhs, Approx const& rhs )
+ {
+ return double(lhs) > rhs.m_value || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ friend bool operator >= ( Approx const& lhs, T rhs )
+ {
+ return lhs.m_value > double(rhs) || lhs == rhs;
+ }
+#else
+ friend bool operator == ( double lhs, Approx const& rhs ) {
+ // Thanks to Richard Harris for his help refining this formula
+ bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
+ if (relativeOK) {
+ return true;
+ }
+ return std::fabs(lhs - rhs.m_value) < rhs.m_margin;
+ }
+
+ friend bool operator == ( Approx const& lhs, double rhs ) {
+ return operator==( rhs, lhs );
+ }
+
+ friend bool operator != ( double lhs, Approx const& rhs ) {
+ return !operator==( lhs, rhs );
+ }
+
+ friend bool operator != ( Approx const& lhs, double rhs ) {
+ return !operator==( rhs, lhs );
+ }
+
+ friend bool operator <= ( double lhs, Approx const& rhs )
+ {
+ return lhs < rhs.m_value || lhs == rhs;
+ }
+
+ friend bool operator <= ( Approx const& lhs, double rhs )
+ {
+ return lhs.m_value < rhs || lhs == rhs;
+ }
+
+ friend bool operator >= ( double lhs, Approx const& rhs )
+ {
+ return lhs > rhs.m_value || lhs == rhs;
+ }
+
+ friend bool operator >= ( Approx const& lhs, double rhs )
+ {
+ return lhs.m_value > rhs || lhs == rhs;
+ }
+#endif
+
+ Approx& epsilon( double newEpsilon ) {
+ m_epsilon = newEpsilon;
+ return *this;
+ }
+
+ Approx& margin( double newMargin ) {
+ m_margin = newMargin;
+ return *this;
+ }
+
+ Approx& scale( double newScale ) {
+ m_scale = newScale;
+ return *this;
+ }
+
+ std::string toString() const {
+ std::ostringstream oss;
+ oss << "Approx( " << Catch::toString( m_value ) << " )";
+ return oss.str();
+ }
+
+ private:
+ double m_epsilon;
+ double m_margin;
+ double m_scale;
+ double m_value;
+ };
+}
+
+template<>
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
+ return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_matchers_string.h
+#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+ namespace StdString {
+
+ struct CasedString
+ {
+ CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
+ std::string adjustString( std::string const& str ) const;
+ std::string caseSensitivitySuffix() const;
+
+ CaseSensitive::Choice m_caseSensitivity;
+ std::string m_str;
+ };
+
+ struct StringMatcherBase : MatcherBase<std::string> {
+ StringMatcherBase( std::string operation, CasedString const& comparator );
+ virtual std::string describe() const CATCH_OVERRIDE;
+
+ CasedString m_comparator;
+ std::string m_operation;
+ };
+
+ struct EqualsMatcher : StringMatcherBase {
+ EqualsMatcher( CasedString const& comparator );
+ virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+ };
+ struct ContainsMatcher : StringMatcherBase {
+ ContainsMatcher( CasedString const& comparator );
+ virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+ };
+ struct StartsWithMatcher : StringMatcherBase {
+ StartsWithMatcher( CasedString const& comparator );
+ virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+ };
+ struct EndsWithMatcher : StringMatcherBase {
+ EndsWithMatcher( CasedString const& comparator );
+ virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+ };
+
+ } // namespace StdString
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+
+ StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+ StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_matchers_vector.h
+#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+ namespace Vector {
+
+ template<typename T>
+ struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
+
+ ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+ bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+ return std::find(v.begin(), v.end(), m_comparator) != v.end();
+ }
+
+ virtual std::string describe() const CATCH_OVERRIDE {
+ return "Contains: " + Catch::toString( m_comparator );
+ }
+
+ T const& m_comparator;
+ };
+
+ template<typename T>
+ struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+ ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+ bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+ // !TBD: see note in EqualsMatcher
+ if (m_comparator.size() > v.size())
+ return false;
+ for (size_t i = 0; i < m_comparator.size(); ++i)
+ if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
+ return false;
+ return true;
+ }
+ virtual std::string describe() const CATCH_OVERRIDE {
+ return "Contains: " + Catch::toString( m_comparator );
+ }
+
+ std::vector<T> const& m_comparator;
+ };
+
+ template<typename T>
+ struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+ EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+ bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+ // !TBD: This currently works if all elements can be compared using !=
+ // - a more general approach would be via a compare template that defaults
+ // to using !=. but could be specialised for, e.g. std::vector<T> etc
+ // - then just call that directly
+ if (m_comparator.size() != v.size())
+ return false;
+ for (size_t i = 0; i < v.size(); ++i)
+ if (m_comparator[i] != v[i])
+ return false;
+ return true;
+ }
+ virtual std::string describe() const CATCH_OVERRIDE {
+ return "Equals: " + Catch::toString( m_comparator );
+ }
+ std::vector<T> const& m_comparator;
+ };
+
+ } // namespace Vector
+
+ // The following functions create the actual matcher objects.
+ // This allows the types to be inferred
+
+ template<typename T>
+ Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
+ return Vector::ContainsMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
+ return Vector::ContainsElementMatcher<T>( comparator );
+ }
+
+ template<typename T>
+ Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
+ return Vector::EqualsMatcher<T>( comparator );
+ }
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+ struct TagAlias {
+ TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+
+ std::string tag;
+ SourceLineInfo lineInfo;
+ };
+
+ struct RegistrarForTagAliases {
+ RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+ };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+ // An optional type
+ template<typename T>
+ class Option {
+ public:
+ Option() : nullableValue( CATCH_NULL ) {}
+ Option( T const& _value )
+ : nullableValue( new( storage ) T( _value ) )
+ {}
+ Option( Option const& _other )
+ : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
+ {}
+
+ ~Option() {
+ reset();
+ }
+
+ Option& operator= ( Option const& _other ) {
+ if( &_other != this ) {
+ reset();
+ if( _other )
+ nullableValue = new( storage ) T( *_other );
+ }
+ return *this;
+ }
+ Option& operator = ( T const& _value ) {
+ reset();
+ nullableValue = new( storage ) T( _value );
+ return *this;
+ }
+
+ void reset() {
+ if( nullableValue )
+ nullableValue->~T();
+ nullableValue = CATCH_NULL;
+ }
+
+ T& operator*() { return *nullableValue; }
+ T const& operator*() const { return *nullableValue; }
+ T* operator->() { return nullableValue; }
+ const T* operator->() const { return nullableValue; }
+
+ T valueOr( T const& defaultValue ) const {
+ return nullableValue ? *nullableValue : defaultValue;
+ }
+
+ bool some() const { return nullableValue != CATCH_NULL; }
+ bool none() const { return nullableValue == CATCH_NULL; }
+
+ bool operator !() const { return nullableValue == CATCH_NULL; }
+ operator SafeBool::type() const {
+ return SafeBool::makeSafe( some() );
+ }
+
+ private:
+ T* nullableValue;
+ char storage[sizeof(T)];
+ };
+
+} // end namespace Catch
+
+namespace Catch {
+
+ struct ITagAliasRegistry {
+ virtual ~ITagAliasRegistry();
+ virtual Option<TagAlias> find( std::string const& alias ) const = 0;
+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+ static ITagAliasRegistry const& get();
+ };
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <string>
+#include <set>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+ struct ITestCase;
+
+ struct TestCaseInfo {
+ enum SpecialProperties{
+ None = 0,
+ IsHidden = 1 << 1,
+ ShouldFail = 1 << 2,
+ MayFail = 1 << 3,
+ Throws = 1 << 4,
+ NonPortable = 1 << 5
+ };
+
+ TestCaseInfo( std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::set<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo );
+
+ TestCaseInfo( TestCaseInfo const& other );
+
+ friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
+
+ bool isHidden() const;
+ bool throws() const;
+ bool okToFail() const;
+ bool expectedToFail() const;
+
+ std::string name;
+ std::string className;
+ std::string description;
+ std::set<std::string> tags;
+ std::set<std::string> lcaseTags;
+ std::string tagsAsString;
+ SourceLineInfo lineInfo;
+ SpecialProperties properties;
+ };
+
+ class TestCase : public TestCaseInfo {
+ public:
+
+ TestCase( ITestCase* testCase, TestCaseInfo const& info );
+ TestCase( TestCase const& other );
+
+ TestCase withName( std::string const& _newName ) const;
+
+ void invoke() const;
+
+ TestCaseInfo const& getTestCaseInfo() const;
+
+ void swap( TestCase& other );
+ bool operator == ( TestCase const& other ) const;
+ bool operator < ( TestCase const& other ) const;
+ TestCase& operator = ( TestCase const& other );
+
+ private:
+ Ptr<ITestCase> test;
+ };
+
+ TestCase makeTestCase( ITestCase* testCase,
+ std::string const& className,
+ std::string const& name,
+ std::string const& description,
+ SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+@protocol OcFixture
+
+@optional
+
+-(void) setUp;
+-(void) tearDown;
+
+@end
+
+namespace Catch {
+
+ class OcMethod : public SharedImpl<ITestCase> {
+
+ public:
+ OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+ virtual void invoke() const {
+ id obj = [[m_cls alloc] init];
+
+ performOptionalSelector( obj, @selector(setUp) );
+ performOptionalSelector( obj, m_sel );
+ performOptionalSelector( obj, @selector(tearDown) );
+
+ arcSafeRelease( obj );
+ }
+ private:
+ virtual ~OcMethod() {}
+
+ Class m_cls;
+ SEL m_sel;
+ };
+
+ namespace Detail{
+
+ inline std::string getAnnotation( Class cls,
+ std::string const& annotationName,
+ std::string const& testCaseName ) {
+ NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+ SEL sel = NSSelectorFromString( selStr );
+ arcSafeRelease( selStr );
+ id value = performOptionalSelector( cls, sel );
+ if( value )
+ return [(NSString*)value UTF8String];
+ return "";
+ }
+ }
+
+ inline size_t registerTestMethods() {
+ size_t noTestMethods = 0;
+ int noClasses = objc_getClassList( CATCH_NULL, 0 );
+
+ Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+ objc_getClassList( classes, noClasses );
+
+ for( int c = 0; c < noClasses; c++ ) {
+ Class cls = classes[c];
+ {
+ u_int count;
+ Method* methods = class_copyMethodList( cls, &count );
+ for( u_int m = 0; m < count ; m++ ) {
+ SEL selector = method_getName(methods[m]);
+ std::string methodName = sel_getName(selector);
+ if( startsWith( methodName, "Catch_TestCase_" ) ) {
+ std::string testCaseName = methodName.substr( 15 );
+ std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+ std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+ const char* className = class_getName( cls );
+
+ getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
+ noTestMethods++;
+ }
+ }
+ free(methods);
+ }
+ }
+ return noTestMethods;
+ }
+
+ namespace Matchers {
+ namespace Impl {
+ namespace NSStringMatchers {
+
+ template<typename MatcherT>
+ struct StringHolder : MatcherImpl<MatcherT, NSString*>{
+ StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+ StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+ StringHolder() {
+ arcSafeRelease( m_substr );
+ }
+
+ NSString* m_substr;
+ };
+
+ struct Equals : StringHolder<Equals> {
+ Equals( NSString* substr ) : StringHolder( substr ){}
+
+ virtual bool match( ExpressionType const& str ) const {
+ return (str != nil || m_substr == nil ) &&
+ [str isEqualToString:m_substr];
+ }
+
+ virtual std::string toString() const {
+ return "equals string: " + Catch::toString( m_substr );
+ }
+ };
+
+ struct Contains : StringHolder<Contains> {
+ Contains( NSString* substr ) : StringHolder( substr ){}
+
+ virtual bool match( ExpressionType const& str ) const {
+ return (str != nil || m_substr == nil ) &&
+ [str rangeOfString:m_substr].location != NSNotFound;
+ }
+
+ virtual std::string toString() const {
+ return "contains string: " + Catch::toString( m_substr );
+ }
+ };
+
+ struct StartsWith : StringHolder<StartsWith> {
+ StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+ virtual bool match( ExpressionType const& str ) const {
+ return (str != nil || m_substr == nil ) &&
+ [str rangeOfString:m_substr].location == 0;
+ }
+
+ virtual std::string toString() const {
+ return "starts with: " + Catch::toString( m_substr );
+ }
+ };
+ struct EndsWith : StringHolder<EndsWith> {
+ EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+ virtual bool match( ExpressionType const& str ) const {
+ return (str != nil || m_substr == nil ) &&
+ [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+ }
+
+ virtual std::string toString() const {
+ return "ends with: " + Catch::toString( m_substr );
+ }
+ };
+
+ } // namespace NSStringMatchers
+ } // namespace Impl
+
+ inline Impl::NSStringMatchers::Equals
+ Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+ inline Impl::NSStringMatchers::Contains
+ Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+ inline Impl::NSStringMatchers::StartsWith
+ StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+ inline Impl::NSStringMatchers::EndsWith
+ EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+ } // namespace Matchers
+
+ using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE( name, desc )\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
+{\
+return @ name; \
+}\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
+{ \
+return @ desc; \
+} \
+-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
+
+#endif
+
+#ifdef CATCH_IMPL
+
+// !TBD: Move the leak detector code into a separate header
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+class LeakDetector {
+public:
+ LeakDetector() {
+ int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ flag |= _CRTDBG_LEAK_CHECK_DF;
+ flag |= _CRTDBG_ALLOC_MEM_DF;
+ _CrtSetDbgFlag(flag);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ // Change this to leaking allocation's number to break there
+ _CrtSetBreakAlloc(-1);
+ }
+};
+#else
+class LeakDetector {};
+#endif
+
+LeakDetector leakDetector;
+
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+#include <stdexcept>
+
+namespace Catch
+{
+ class WildcardPattern {
+ enum WildcardPosition {
+ NoWildcard = 0,
+ WildcardAtStart = 1,
+ WildcardAtEnd = 2,
+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+ };
+
+ public:
+
+ WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
+ : m_caseSensitivity( caseSensitivity ),
+ m_wildcard( NoWildcard ),
+ m_pattern( adjustCase( pattern ) )
+ {
+ if( startsWith( m_pattern, '*' ) ) {
+ m_pattern = m_pattern.substr( 1 );
+ m_wildcard = WildcardAtStart;
+ }
+ if( endsWith( m_pattern, '*' ) ) {
+ m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+ m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+ }
+ }
+ virtual ~WildcardPattern();
+ virtual bool matches( std::string const& str ) const {
+ switch( m_wildcard ) {
+ case NoWildcard:
+ return m_pattern == adjustCase( str );
+ case WildcardAtStart:
+ return endsWith( adjustCase( str ), m_pattern );
+ case WildcardAtEnd:
+ return startsWith( adjustCase( str ), m_pattern );
+ case WildcardAtBothEnds:
+ return contains( adjustCase( str ), m_pattern );
+ }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+ throw std::logic_error( "Unknown enum" );
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ }
+ private:
+ std::string adjustCase( std::string const& str ) const {
+ return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+ }
+ CaseSensitive::Choice m_caseSensitivity;
+ WildcardPosition m_wildcard;
+ std::string m_pattern;
+ };
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ class TestSpec {
+ struct Pattern : SharedImpl<> {
+ virtual ~Pattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+ };
+ class NamePattern : public Pattern {
+ public:
+ NamePattern( std::string const& name )
+ : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+ {}
+ virtual ~NamePattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const {
+ return m_wildcardPattern.matches( toLower( testCase.name ) );
+ }
+ private:
+ WildcardPattern m_wildcardPattern;
+ };
+
+ class TagPattern : public Pattern {
+ public:
+ TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+ virtual ~TagPattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const {
+ return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
+ }
+ private:
+ std::string m_tag;
+ };
+
+ class ExcludedPattern : public Pattern {
+ public:
+ ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+ virtual ~ExcludedPattern();
+ virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+ private:
+ Ptr<Pattern> m_underlyingPattern;
+ };
+
+ struct Filter {
+ std::vector<Ptr<Pattern> > m_patterns;
+
+ bool matches( TestCaseInfo const& testCase ) const {
+ // All patterns in a filter must match for the filter to be a match
+ for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
+ if( !(*it)->matches( testCase ) )
+ return false;
+ }
+ return true;
+ }
+ };
+
+ public:
+ bool hasFilters() const {
+ return !m_filters.empty();
+ }
+ bool matches( TestCaseInfo const& testCase ) const {
+ // A TestSpec matches if any filter matches
+ for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
+ if( it->matches( testCase ) )
+ return true;
+ return false;
+ }
+
+ private:
+ std::vector<Filter> m_filters;
+
+ friend class TestSpecParser;
+ };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+ class TestSpecParser {
+ enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+ Mode m_mode;
+ bool m_exclusion;
+ std::size_t m_start, m_pos;
+ std::string m_arg;
+ std::vector<std::size_t> m_escapeChars;
+ TestSpec::Filter m_currentFilter;
+ TestSpec m_testSpec;
+ ITagAliasRegistry const* m_tagAliases;
+
+ public:
+ TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+ TestSpecParser& parse( std::string const& arg ) {
+ m_mode = None;
+ m_exclusion = false;
+ m_start = std::string::npos;
+ m_arg = m_tagAliases->expandAliases( arg );
+ m_escapeChars.clear();
+ for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+ visitChar( m_arg[m_pos] );
+ if( m_mode == Name )
+ addPattern<TestSpec::NamePattern>();
+ return *this;
+ }
+ TestSpec testSpec() {
+ addFilter();
+ return m_testSpec;
+ }
+ private:
+ void visitChar( char c ) {
+ if( m_mode == None ) {
+ switch( c ) {
+ case ' ': return;
+ case '~': m_exclusion = true; return;
+ case '[': return startNewMode( Tag, ++m_pos );
+ case '"': return startNewMode( QuotedName, ++m_pos );
+ case '\\': return escape();
+ default: startNewMode( Name, m_pos ); break;
+ }
+ }
+ if( m_mode == Name ) {
+ if( c == ',' ) {
+ addPattern<TestSpec::NamePattern>();
+ addFilter();
+ }
+ else if( c == '[' ) {
+ if( subString() == "exclude:" )
+ m_exclusion = true;
+ else
+ addPattern<TestSpec::NamePattern>();
+ startNewMode( Tag, ++m_pos );
+ }
+ else if( c == '\\' )
+ escape();
+ }
+ else if( m_mode == EscapedName )
+ m_mode = Name;
+ else if( m_mode == QuotedName && c == '"' )
+ addPattern<TestSpec::NamePattern>();
+ else if( m_mode == Tag && c == ']' )
+ addPattern<TestSpec::TagPattern>();
+ }
+ void startNewMode( Mode mode, std::size_t start ) {
+ m_mode = mode;
+ m_start = start;
+ }
+ void escape() {
+ if( m_mode == None )
+ m_start = m_pos;
+ m_mode = EscapedName;
+ m_escapeChars.push_back( m_pos );
+ }
+ std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+ template<typename T>
+ void addPattern() {
+ std::string token = subString();
+ for( size_t i = 0; i < m_escapeChars.size(); ++i )
+ token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
+ m_escapeChars.clear();
+ if( startsWith( token, "exclude:" ) ) {
+ m_exclusion = true;
+ token = token.substr( 8 );
+ }
+ if( !token.empty() ) {
+ Ptr<TestSpec::Pattern> pattern = new T( token );
+ if( m_exclusion )
+ pattern = new TestSpec::ExcludedPattern( pattern );
+ m_currentFilter.m_patterns.push_back( pattern );
+ }
+ m_exclusion = false;
+ m_mode = None;
+ }
+ void addFilter() {
+ if( !m_currentFilter.m_patterns.empty() ) {
+ m_testSpec.m_filters.push_back( m_currentFilter );
+ m_currentFilter = TestSpec::Filter();
+ }
+ }
+ };
+ inline TestSpec parseTestSpec( std::string const& arg ) {
+ return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+ }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ struct Verbosity { enum Level {
+ NoOutput = 0,
+ Quiet,
+ Normal
+ }; };
+
+ struct WarnAbout { enum What {
+ Nothing = 0x00,
+ NoAssertions = 0x01
+ }; };
+
+ struct ShowDurations { enum OrNot {
+ DefaultForReporter,
+ Always,
+ Never
+ }; };
+ struct RunTests { enum InWhatOrder {
+ InDeclarationOrder,
+ InLexicographicalOrder,
+ InRandomOrder
+ }; };
+ struct UseColour { enum YesOrNo {
+ Auto,
+ Yes,
+ No
+ }; };
+
+ class TestSpec;
+
+ struct IConfig : IShared {
+
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual std::ostream& stream() const = 0;
+ virtual std::string name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations::OrNot showDurations() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual RunTests::InWhatOrder runOrder() const = 0;
+ virtual unsigned int rngSeed() const = 0;
+ virtual UseColour::YesOrNo useColour() const = 0;
+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
+ };
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+ class StreamBufBase : public std::streambuf {
+ public:
+ virtual ~StreamBufBase() CATCH_NOEXCEPT;
+ };
+}
+
+#include <streambuf>
+#include <ostream>
+#include <fstream>
+#include <memory>
+
+namespace Catch {
+
+ std::ostream& cout();
+ std::ostream& cerr();
+
+ struct IStream {
+ virtual ~IStream() CATCH_NOEXCEPT;
+ virtual std::ostream& stream() const = 0;
+ };
+
+ class FileStream : public IStream {
+ mutable std::ofstream m_ofs;
+ public:
+ FileStream( std::string const& filename );
+ virtual ~FileStream() CATCH_NOEXCEPT;
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+ };
+
+ class CoutStream : public IStream {
+ mutable std::ostream m_os;
+ public:
+ CoutStream();
+ virtual ~CoutStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+ };
+
+ class DebugOutStream : public IStream {
+ CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
+ mutable std::ostream m_os;
+ public:
+ DebugOutStream();
+ virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+ public: // IStream
+ virtual std::ostream& stream() const CATCH_OVERRIDE;
+ };
+}
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <stdexcept>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+ struct ConfigData {
+
+ ConfigData()
+ : listTests( false ),
+ listTags( false ),
+ listReporters( false ),
+ listTestNamesOnly( false ),
+ showSuccessfulTests( false ),
+ shouldDebugBreak( false ),
+ noThrow( false ),
+ showHelp( false ),
+ showInvisibles( false ),
+ filenamesAsTags( false ),
+ abortAfter( -1 ),
+ rngSeed( 0 ),
+ verbosity( Verbosity::Normal ),
+ warnings( WarnAbout::Nothing ),
+ showDurations( ShowDurations::DefaultForReporter ),
+ runOrder( RunTests::InDeclarationOrder ),
+ useColour( UseColour::Auto )
+ {}
+
+ bool listTests;
+ bool listTags;
+ bool listReporters;
+ bool listTestNamesOnly;
+
+ bool showSuccessfulTests;
+ bool shouldDebugBreak;
+ bool noThrow;
+ bool showHelp;
+ bool showInvisibles;
+ bool filenamesAsTags;
+
+ int abortAfter;
+ unsigned int rngSeed;
+
+ Verbosity::Level verbosity;
+ WarnAbout::What warnings;
+ ShowDurations::OrNot showDurations;
+ RunTests::InWhatOrder runOrder;
+ UseColour::YesOrNo useColour;
+
+ std::string outputFilename;
+ std::string name;
+ std::string processName;
+
+ std::vector<std::string> reporterNames;
+ std::vector<std::string> testsOrTags;
+ std::vector<std::string> sectionsToRun;
+ };
+
+ class Config : public SharedImpl<IConfig> {
+ private:
+ Config( Config const& other );
+ Config& operator = ( Config const& other );
+ virtual void dummy();
+ public:
+
+ Config()
+ {}
+
+ Config( ConfigData const& data )
+ : m_data( data ),
+ m_stream( openStream() )
+ {
+ if( !data.testsOrTags.empty() ) {
+ TestSpecParser parser( ITagAliasRegistry::get() );
+ for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
+ parser.parse( data.testsOrTags[i] );
+ m_testSpec = parser.testSpec();
+ }
+ }
+
+ virtual ~Config() {}
+
+ std::string const& getFilename() const {
+ return m_data.outputFilename ;
+ }
+
+ bool listTests() const { return m_data.listTests; }
+ bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+ bool listTags() const { return m_data.listTags; }
+ bool listReporters() const { return m_data.listReporters; }
+
+ std::string getProcessName() const { return m_data.processName; }
+
+ std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+ std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
+
+ virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
+
+ bool showHelp() const { return m_data.showHelp; }
+
+ // IConfig interface
+ virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; }
+ virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); }
+ virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; }
+ virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; }
+ virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; }
+ virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
+ virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; }
+ virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; }
+ virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; }
+ virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
+ virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
+ virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
+
+ private:
+
+ IStream const* openStream() {
+ if( m_data.outputFilename.empty() )
+ return new CoutStream();
+ else if( m_data.outputFilename[0] == '%' ) {
+ if( m_data.outputFilename == "%debug" )
+ return new DebugOutStream();
+ else
+ throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
+ }
+ else
+ return new FileStream( m_data.outputFilename );
+ }
+ ConfigData m_data;
+
+ CATCH_AUTO_PTR( IStream const ) m_stream;
+ TestSpec m_testSpec;
+ };
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Version 0.0.2.4
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <algorithm>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+ const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+ const unsigned int consoleWidth = 80;
+#endif
+
+ struct TextAttributes {
+ TextAttributes()
+ : initialIndent( std::string::npos ),
+ indent( 0 ),
+ width( consoleWidth-1 ),
+ tabChar( '\t' )
+ {}
+
+ TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
+ TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
+ TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
+ TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
+
+ std::size_t initialIndent; // indent of first line, or npos
+ std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
+ std::size_t width; // maximum width of text, including indent. Longer text will wrap
+ char tabChar; // If this char is seen the indent is changed to current pos
+ };
+
+ class Text {
+ public:
+ Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+ : attr( _attr )
+ {
+ std::string wrappableChars = " [({.,/|\\-";
+ std::size_t indent = _attr.initialIndent != std::string::npos
+ ? _attr.initialIndent
+ : _attr.indent;
+ std::string remainder = _str;
+
+ while( !remainder.empty() ) {
+ if( lines.size() >= 1000 ) {
+ lines.push_back( "... message truncated due to excessive size" );
+ return;
+ }
+ std::size_t tabPos = std::string::npos;
+ std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+ std::size_t pos = remainder.find_first_of( '\n' );
+ if( pos <= width ) {
+ width = pos;
+ }
+ pos = remainder.find_last_of( _attr.tabChar, width );
+ if( pos != std::string::npos ) {
+ tabPos = pos;
+ if( remainder[width] == '\n' )
+ width--;
+ remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+ }
+
+ if( width == remainder.size() ) {
+ spliceLine( indent, remainder, width );
+ }
+ else if( remainder[width] == '\n' ) {
+ spliceLine( indent, remainder, width );
+ if( width <= 1 || remainder.size() != 1 )
+ remainder = remainder.substr( 1 );
+ indent = _attr.indent;
+ }
+ else {
+ pos = remainder.find_last_of( wrappableChars, width );
+ if( pos != std::string::npos && pos > 0 ) {
+ spliceLine( indent, remainder, pos );
+ if( remainder[0] == ' ' )
+ remainder = remainder.substr( 1 );
+ }
+ else {
+ spliceLine( indent, remainder, width-1 );
+ lines.back() += "-";
+ }
+ if( lines.size() == 1 )
+ indent = _attr.indent;
+ if( tabPos != std::string::npos )
+ indent += tabPos;
+ }
+ }
+ }
+
+ void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+ lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+ _remainder = _remainder.substr( _pos );
+ }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+
+ const_iterator begin() const { return lines.begin(); }
+ const_iterator end() const { return lines.end(); }
+ std::string const& last() const { return lines.back(); }
+ std::size_t size() const { return lines.size(); }
+ std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+ std::string toString() const {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+
+ inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+ for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+ it != itEnd; ++it ) {
+ if( it != _text.begin() )
+ _stream << "\n";
+ _stream << *it;
+ }
+ return _stream;
+ }
+
+ private:
+ std::string str;
+ TextAttributes attr;
+ std::vector<std::string> lines;
+ };
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+// ----------- #included from clara_compilers.h -----------
+
+#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
+// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+
+// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
+
+#ifdef __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1600)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define CLARA_CPP11_OR_GREATER
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
+#endif
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
+#define CLARA_NOEXCEPT noexcept
+# define CLARA_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CLARA_NOEXCEPT throw()
+# define CLARA_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CLARA_CONFIG_CPP11_NULLPTR
+#define CLARA_NULL nullptr
+#else
+#define CLARA_NULL NULL
+#endif
+
+// override support
+#ifdef CLARA_CONFIG_CPP11_OVERRIDE
+#define CLARA_OVERRIDE override
+#else
+#define CLARA_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
+# define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+# define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// ----------- end of #include from clara_compilers.h -----------
+// ........... back in clara.h
+
+#include <map>
+#include <stdexcept>
+#include <memory>
+
+#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CLARA_PLATFORM_WINDOWS
+#endif
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+ struct UnpositionalTag {};
+
+ extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+ UnpositionalTag _;
+#endif
+
+ namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+ const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+ const unsigned int consoleWidth = 80;
+#endif
+
+ using namespace Tbc;
+
+ inline bool startsWith( std::string const& str, std::string const& prefix ) {
+ return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
+ }
+
+ template<typename T> struct RemoveConstRef{ typedef T type; };
+ template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
+ template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
+ template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
+
+ template<typename T> struct IsBool { static const bool value = false; };
+ template<> struct IsBool<bool> { static const bool value = true; };
+
+ template<typename T>
+ void convertInto( std::string const& _source, T& _dest ) {
+ std::stringstream ss;
+ ss << _source;
+ ss >> _dest;
+ if( ss.fail() )
+ throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
+ }
+ inline void convertInto( std::string const& _source, std::string& _dest ) {
+ _dest = _source;
+ }
+ char toLowerCh(char c) {
+ return static_cast<char>( ::tolower( c ) );
+ }
+ inline void convertInto( std::string const& _source, bool& _dest ) {
+ std::string sourceLC = _source;
+ std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
+ if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
+ _dest = true;
+ else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
+ _dest = false;
+ else
+ throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
+ }
+
+ template<typename ConfigT>
+ struct IArgFunction {
+ virtual ~IArgFunction() {}
+#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
+ IArgFunction() = default;
+ IArgFunction( IArgFunction const& ) = default;
+#endif
+ virtual void set( ConfigT& config, std::string const& value ) const = 0;
+ virtual bool takesArg() const = 0;
+ virtual IArgFunction* clone() const = 0;
+ };
+
+ template<typename ConfigT>
+ class BoundArgFunction {
+ public:
+ BoundArgFunction() : functionObj( CLARA_NULL ) {}
+ BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
+ BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
+ BoundArgFunction& operator = ( BoundArgFunction const& other ) {
+ IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
+ delete functionObj;
+ functionObj = newFunctionObj;
+ return *this;
+ }
+ ~BoundArgFunction() { delete functionObj; }
+
+ void set( ConfigT& config, std::string const& value ) const {
+ functionObj->set( config, value );
+ }
+ bool takesArg() const { return functionObj->takesArg(); }
+
+ bool isSet() const {
+ return functionObj != CLARA_NULL;
+ }
+ private:
+ IArgFunction<ConfigT>* functionObj;
+ };
+
+ template<typename C>
+ struct NullBinder : IArgFunction<C>{
+ virtual void set( C&, std::string const& ) const {}
+ virtual bool takesArg() const { return true; }
+ virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
+ };
+
+ template<typename C, typename M>
+ struct BoundDataMember : IArgFunction<C>{
+ BoundDataMember( M C::* _member ) : member( _member ) {}
+ virtual void set( C& p, std::string const& stringValue ) const {
+ convertInto( stringValue, p.*member );
+ }
+ virtual bool takesArg() const { return !IsBool<M>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
+ M C::* member;
+ };
+ template<typename C, typename M>
+ struct BoundUnaryMethod : IArgFunction<C>{
+ BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
+ virtual void set( C& p, std::string const& stringValue ) const {
+ typename RemoveConstRef<M>::type value;
+ convertInto( stringValue, value );
+ (p.*member)( value );
+ }
+ virtual bool takesArg() const { return !IsBool<M>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
+ void (C::*member)( M );
+ };
+ template<typename C>
+ struct BoundNullaryMethod : IArgFunction<C>{
+ BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
+ virtual void set( C& p, std::string const& stringValue ) const {
+ bool value;
+ convertInto( stringValue, value );
+ if( value )
+ (p.*member)();
+ }
+ virtual bool takesArg() const { return false; }
+ virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
+ void (C::*member)();
+ };
+
+ template<typename C>
+ struct BoundUnaryFunction : IArgFunction<C>{
+ BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
+ virtual void set( C& obj, std::string const& stringValue ) const {
+ bool value;
+ convertInto( stringValue, value );
+ if( value )
+ function( obj );
+ }
+ virtual bool takesArg() const { return false; }
+ virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
+ void (*function)( C& );
+ };
+
+ template<typename C, typename T>
+ struct BoundBinaryFunction : IArgFunction<C>{
+ BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
+ virtual void set( C& obj, std::string const& stringValue ) const {
+ typename RemoveConstRef<T>::type value;
+ convertInto( stringValue, value );
+ function( obj, value );
+ }
+ virtual bool takesArg() const { return !IsBool<T>::value; }
+ virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
+ void (*function)( C&, T );
+ };
+
+ } // namespace Detail
+
+ inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
+ std::vector<std::string> args( static_cast<std::size_t>( argc ) );
+ for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
+ args[i] = argv[i];
+
+ return args;
+ }
+
+ class Parser {
+ enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
+ Mode mode;
+ std::size_t from;
+ bool inQuotes;
+ public:
+
+ struct Token {
+ enum Type { Positional, ShortOpt, LongOpt };
+ Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
+ Type type;
+ std::string data;
+ };
+
+ Parser() : mode( None ), from( 0 ), inQuotes( false ){}
+
+ void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
+ const std::string doubleDash = "--";
+ for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
+ parseIntoTokens( args[i], tokens);
+ }
+
+ void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
+ for( std::size_t i = 0; i <= arg.size(); ++i ) {
+ char c = arg[i];
+ if( c == '"' )
+ inQuotes = !inQuotes;
+ mode = handleMode( i, c, arg, tokens );
+ }
+ }
+ Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+ switch( mode ) {
+ case None: return handleNone( i, c );
+ case MaybeShortOpt: return handleMaybeShortOpt( i, c );
+ case ShortOpt:
+ case LongOpt:
+ case SlashOpt: return handleOpt( i, c, arg, tokens );
+ case Positional: return handlePositional( i, c, arg, tokens );
+ default: throw std::logic_error( "Unknown mode" );
+ }
+ }
+
+ Mode handleNone( std::size_t i, char c ) {
+ if( inQuotes ) {
+ from = i;
+ return Positional;
+ }
+ switch( c ) {
+ case '-': return MaybeShortOpt;
+#ifdef CLARA_PLATFORM_WINDOWS
+ case '/': from = i+1; return SlashOpt;
+#endif
+ default: from = i; return Positional;
+ }
+ }
+ Mode handleMaybeShortOpt( std::size_t i, char c ) {
+ switch( c ) {
+ case '-': from = i+1; return LongOpt;
+ default: from = i; return ShortOpt;
+ }
+ }
+ Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+ if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
+ return mode;
+
+ std::string optName = arg.substr( from, i-from );
+ if( mode == ShortOpt )
+ for( std::size_t j = 0; j < optName.size(); ++j )
+ tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
+ else if( mode == SlashOpt && optName.size() == 1 )
+ tokens.push_back( Token( Token::ShortOpt, optName ) );
+ else
+ tokens.push_back( Token( Token::LongOpt, optName ) );
+ return None;
+ }
+ Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+ if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
+ return mode;
+
+ std::string data = arg.substr( from, i-from );
+ tokens.push_back( Token( Token::Positional, data ) );
+ return None;
+ }
+ };
+
+ template<typename ConfigT>
+ struct CommonArgProperties {
+ CommonArgProperties() {}
+ CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
+
+ Detail::BoundArgFunction<ConfigT> boundField;
+ std::string description;
+ std::string detail;
+ std::string placeholder; // Only value if boundField takes an arg
+
+ bool takesArg() const {
+ return !placeholder.empty();
+ }
+ void validate() const {
+ if( !boundField.isSet() )
+ throw std::logic_error( "option not bound" );
+ }
+ };
+ struct OptionArgProperties {
+ std::vector<std::string> shortNames;
+ std::string longName;
+
+ bool hasShortName( std::string const& shortName ) const {
+ return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
+ }
+ bool hasLongName( std::string const& _longName ) const {
+ return _longName == longName;
+ }
+ };
+ struct PositionalArgProperties {
+ PositionalArgProperties() : position( -1 ) {}
+ int position; // -1 means non-positional (floating)
+
+ bool isFixedPositional() const {
+ return position != -1;
+ }
+ };
+
+ template<typename ConfigT>
+ class CommandLine {
+
+ struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
+ Arg() {}
+ Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
+
+ using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+ std::string dbgName() const {
+ if( !longName.empty() )
+ return "--" + longName;
+ if( !shortNames.empty() )
+ return "-" + shortNames[0];
+ return "positional args";
+ }
+ std::string commands() const {
+ std::ostringstream oss;
+ bool first = true;
+ std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+ for(; it != itEnd; ++it ) {
+ if( first )
+ first = false;
+ else
+ oss << ", ";
+ oss << "-" << *it;
+ }
+ if( !longName.empty() ) {
+ if( !first )
+ oss << ", ";
+ oss << "--" << longName;
+ }
+ if( !placeholder.empty() )
+ oss << " <" << placeholder << ">";
+ return oss.str();
+ }
+ };
+
+ typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
+
+ friend void addOptName( Arg& arg, std::string const& optName )
+ {
+ if( optName.empty() )
+ return;
+ if( Detail::startsWith( optName, "--" ) ) {
+ if( !arg.longName.empty() )
+ throw std::logic_error( "Only one long opt may be specified. '"
+ + arg.longName
+ + "' already specified, now attempting to add '"
+ + optName + "'" );
+ arg.longName = optName.substr( 2 );
+ }
+ else if( Detail::startsWith( optName, "-" ) )
+ arg.shortNames.push_back( optName.substr( 1 ) );
+ else
+ throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
+ }
+ friend void setPositionalArg( Arg& arg, int position )
+ {
+ arg.position = position;
+ }
+
+ class ArgBuilder {
+ public:
+ ArgBuilder( Arg* arg ) : m_arg( arg ) {}
+
+ // Bind a non-boolean data member (requires placeholder string)
+ template<typename C, typename M>
+ void bind( M C::* field, std::string const& placeholder ) {
+ m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
+ m_arg->placeholder = placeholder;
+ }
+ // Bind a boolean data member (no placeholder required)
+ template<typename C>
+ void bind( bool C::* field ) {
+ m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
+ }
+
+ // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+ template<typename C, typename M>
+ void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
+ m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
+ m_arg->placeholder = placeholder;
+ }
+
+ // Bind a method taking a single, boolean argument (no placeholder string required)
+ template<typename C>
+ void bind( void (C::* unaryMethod)( bool ) ) {
+ m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
+ }
+
+ // Bind a method that takes no arguments (will be called if opt is present)
+ template<typename C>
+ void bind( void (C::* nullaryMethod)() ) {
+ m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
+ }
+
+ // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+ template<typename C>
+ void bind( void (* unaryFunction)( C& ) ) {
+ m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
+ }
+
+ // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+ template<typename C, typename T>
+ void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
+ m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
+ m_arg->placeholder = placeholder;
+ }
+
+ ArgBuilder& describe( std::string const& description ) {
+ m_arg->description = description;
+ return *this;
+ }
+ ArgBuilder& detail( std::string const& detail ) {
+ m_arg->detail = detail;
+ return *this;
+ }
+
+ protected:
+ Arg* m_arg;
+ };
+
+ class OptBuilder : public ArgBuilder {
+ public:
+ OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
+ OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
+
+ OptBuilder& operator[]( std::string const& optName ) {
+ addOptName( *ArgBuilder::m_arg, optName );
+ return *this;
+ }
+ };
+
+ public:
+
+ CommandLine()
+ : m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
+ m_highestSpecifiedArgPosition( 0 ),
+ m_throwOnUnrecognisedTokens( false )
+ {}
+ CommandLine( CommandLine const& other )
+ : m_boundProcessName( other.m_boundProcessName ),
+ m_options ( other.m_options ),
+ m_positionalArgs( other.m_positionalArgs ),
+ m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
+ m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
+ {
+ if( other.m_floatingArg.get() )
+ m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
+ }
+
+ CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
+ m_throwOnUnrecognisedTokens = shouldThrow;
+ return *this;
+ }
+
+ OptBuilder operator[]( std::string const& optName ) {
+ m_options.push_back( Arg() );
+ addOptName( m_options.back(), optName );
+ OptBuilder builder( &m_options.back() );
+ return builder;
+ }
+
+ ArgBuilder operator[]( int position ) {
+ m_positionalArgs.insert( std::make_pair( position, Arg() ) );
+ if( position > m_highestSpecifiedArgPosition )
+ m_highestSpecifiedArgPosition = position;
+ setPositionalArg( m_positionalArgs[position], position );
+ ArgBuilder builder( &m_positionalArgs[position] );
+ return builder;
+ }
+
+ // Invoke this with the _ instance
+ ArgBuilder operator[]( UnpositionalTag ) {
+ if( m_floatingArg.get() )
+ throw std::logic_error( "Only one unpositional argument can be added" );
+ m_floatingArg.reset( new Arg() );
+ ArgBuilder builder( m_floatingArg.get() );
+ return builder;
+ }
+
+ template<typename C, typename M>
+ void bindProcessName( M C::* field ) {
+ m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
+ }
+ template<typename C, typename M>
+ void bindProcessName( void (C::*_unaryMethod)( M ) ) {
+ m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
+ }
+
+ void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
+ typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+ std::size_t maxWidth = 0;
+ for( it = itBegin; it != itEnd; ++it )
+ maxWidth = (std::max)( maxWidth, it->commands().size() );
+
+ for( it = itBegin; it != itEnd; ++it ) {
+ Detail::Text usage( it->commands(), Detail::TextAttributes()
+ .setWidth( maxWidth+indent )
+ .setIndent( indent ) );
+ Detail::Text desc( it->description, Detail::TextAttributes()
+ .setWidth( width - maxWidth - 3 ) );
+
+ for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
+ std::string usageCol = i < usage.size() ? usage[i] : "";
+ os << usageCol;
+
+ if( i < desc.size() && !desc[i].empty() )
+ os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
+ << desc[i];
+ os << "\n";
+ }
+ }
+ }
+ std::string optUsage() const {
+ std::ostringstream oss;
+ optUsage( oss );
+ return oss.str();
+ }
+
+ void argSynopsis( std::ostream& os ) const {
+ for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
+ if( i > 1 )
+ os << " ";
+ typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
+ if( it != m_positionalArgs.end() )
+ os << "<" << it->second.placeholder << ">";
+ else if( m_floatingArg.get() )
+ os << "<" << m_floatingArg->placeholder << ">";
+ else
+ throw std::logic_error( "non consecutive positional arguments with no floating args" );
+ }
+ // !TBD No indication of mandatory args
+ if( m_floatingArg.get() ) {
+ if( m_highestSpecifiedArgPosition > 1 )
+ os << " ";
+ os << "[<" << m_floatingArg->placeholder << "> ...]";
+ }
+ }
+ std::string argSynopsis() const {
+ std::ostringstream oss;
+ argSynopsis( oss );
+ return oss.str();
+ }
+
+ void usage( std::ostream& os, std::string const& procName ) const {
+ validate();
+ os << "usage:\n " << procName << " ";
+ argSynopsis( os );
+ if( !m_options.empty() ) {
+ os << " [options]\n\nwhere options are: \n";
+ optUsage( os, 2 );
+ }
+ os << "\n";
+ }
+ std::string usage( std::string const& procName ) const {
+ std::ostringstream oss;
+ usage( oss, procName );
+ return oss.str();
+ }
+
+ ConfigT parse( std::vector<std::string> const& args ) const {
+ ConfigT config;
+ parseInto( args, config );
+ return config;
+ }
+
+ std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
+ std::string processName = args[0];
+ std::size_t lastSlash = processName.find_last_of( "/\\" );
+ if( lastSlash != std::string::npos )
+ processName = processName.substr( lastSlash+1 );
+ m_boundProcessName.set( config, processName );
+ std::vector<Parser::Token> tokens;
+ Parser parser;
+ parser.parseIntoTokens( args, tokens );
+ return populate( tokens, config );
+ }
+
+ std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+ validate();
+ std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
+ unusedTokens = populateFixedArgs( unusedTokens, config );
+ unusedTokens = populateFloatingArgs( unusedTokens, config );
+ return unusedTokens;
+ }
+
+ std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+ std::vector<Parser::Token> unusedTokens;
+ std::vector<std::string> errors;
+ for( std::size_t i = 0; i < tokens.size(); ++i ) {
+ Parser::Token const& token = tokens[i];
+ typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+ for(; it != itEnd; ++it ) {
+ Arg const& arg = *it;
+
+ try {
+ if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
+ ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
+ if( arg.takesArg() ) {
+ if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
+ errors.push_back( "Expected argument to option: " + token.data );
+ else
+ arg.boundField.set( config, tokens[++i].data );
+ }
+ else {
+ arg.boundField.set( config, "true" );
+ }
+ break;
+ }
+ }
+ catch( std::exception& ex ) {
+ errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
+ }
+ }
+ if( it == itEnd ) {
+ if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
+ unusedTokens.push_back( token );
+ else if( errors.empty() && m_throwOnUnrecognisedTokens )
+ errors.push_back( "unrecognised option: " + token.data );
+ }
+ }
+ if( !errors.empty() ) {
+ std::ostringstream oss;
+ for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+ it != itEnd;
+ ++it ) {
+ if( it != errors.begin() )
+ oss << "\n";
+ oss << *it;
+ }
+ throw std::runtime_error( oss.str() );
+ }
+ return unusedTokens;
+ }
+ std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+ std::vector<Parser::Token> unusedTokens;
+ int position = 1;
+ for( std::size_t i = 0; i < tokens.size(); ++i ) {
+ Parser::Token const& token = tokens[i];
+ typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
+ if( it != m_positionalArgs.end() )
+ it->second.boundField.set( config, token.data );
+ else
+ unusedTokens.push_back( token );
+ if( token.type == Parser::Token::Positional )
+ position++;
+ }
+ return unusedTokens;
+ }
+ std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+ if( !m_floatingArg.get() )
+ return tokens;
+ std::vector<Parser::Token> unusedTokens;
+ for( std::size_t i = 0; i < tokens.size(); ++i ) {
+ Parser::Token const& token = tokens[i];
+ if( token.type == Parser::Token::Positional )
+ m_floatingArg->boundField.set( config, token.data );
+ else
+ unusedTokens.push_back( token );
+ }
+ return unusedTokens;
+ }
+
+ void validate() const
+ {
+ if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
+ throw std::logic_error( "No options or arguments specified" );
+
+ for( typename std::vector<Arg>::const_iterator it = m_options.begin(),
+ itEnd = m_options.end();
+ it != itEnd; ++it )
+ it->validate();
+ }
+
+ private:
+ Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+ std::vector<Arg> m_options;
+ std::map<int, Arg> m_positionalArgs;
+ ArgAutoPtr m_floatingArg;
+ int m_highestSpecifiedArgPosition;
+ bool m_throwOnUnrecognisedTokens;
+ };
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+#include <ctime>
+
+namespace Catch {
+
+ inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
+ inline void abortAfterX( ConfigData& config, int x ) {
+ if( x < 1 )
+ throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
+ config.abortAfter = x;
+ }
+ inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+ inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
+ inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
+
+ inline void addWarning( ConfigData& config, std::string const& _warning ) {
+ if( _warning == "NoAssertions" )
+ config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+ else
+ throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
+ }
+ inline void setOrder( ConfigData& config, std::string const& order ) {
+ if( startsWith( "declared", order ) )
+ config.runOrder = RunTests::InDeclarationOrder;
+ else if( startsWith( "lexical", order ) )
+ config.runOrder = RunTests::InLexicographicalOrder;
+ else if( startsWith( "random", order ) )
+ config.runOrder = RunTests::InRandomOrder;
+ else
+ throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
+ }
+ inline void setRngSeed( ConfigData& config, std::string const& seed ) {
+ if( seed == "time" ) {
+ config.rngSeed = static_cast<unsigned int>( std::time(0) );
+ }
+ else {
+ std::stringstream ss;
+ ss << seed;
+ ss >> config.rngSeed;
+ if( ss.fail() )
+ throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
+ }
+ }
+ inline void setVerbosity( ConfigData& config, int level ) {
+ // !TBD: accept strings?
+ config.verbosity = static_cast<Verbosity::Level>( level );
+ }
+ inline void setShowDurations( ConfigData& config, bool _showDurations ) {
+ config.showDurations = _showDurations
+ ? ShowDurations::Always
+ : ShowDurations::Never;
+ }
+ inline void setUseColour( ConfigData& config, std::string const& value ) {
+ std::string mode = toLower( value );
+
+ if( mode == "yes" )
+ config.useColour = UseColour::Yes;
+ else if( mode == "no" )
+ config.useColour = UseColour::No;
+ else if( mode == "auto" )
+ config.useColour = UseColour::Auto;
+ else
+ throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
+ }
+ inline void forceColour( ConfigData& config ) {
+ config.useColour = UseColour::Yes;
+ }
+ inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
+ std::ifstream f( _filename.c_str() );
+ if( !f.is_open() )
+ throw std::domain_error( "Unable to load input file: " + _filename );
+
+ std::string line;
+ while( std::getline( f, line ) ) {
+ line = trim(line);
+ if( !line.empty() && !startsWith( line, '#' ) ) {
+ if( !startsWith( line, '"' ) )
+ line = '"' + line + '"';
+ addTestOrTags( config, line + ',' );
+ }
+ }
+ }
+
+ inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
+
+ using namespace Clara;
+ CommandLine<ConfigData> cli;
+
+ cli.bindProcessName( &ConfigData::processName );
+
+ cli["-?"]["-h"]["--help"]
+ .describe( "display usage information" )
+ .bind( &ConfigData::showHelp );
+
+ cli["-l"]["--list-tests"]
+ .describe( "list all/matching test cases" )
+ .bind( &ConfigData::listTests );
+
+ cli["-t"]["--list-tags"]
+ .describe( "list all/matching tags" )
+ .bind( &ConfigData::listTags );
+
+ cli["-s"]["--success"]
+ .describe( "include successful tests in output" )
+ .bind( &ConfigData::showSuccessfulTests );
+
+ cli["-b"]["--break"]
+ .describe( "break into debugger on failure" )
+ .bind( &ConfigData::shouldDebugBreak );
+
+ cli["-e"]["--nothrow"]
+ .describe( "skip exception tests" )
+ .bind( &ConfigData::noThrow );
+
+ cli["-i"]["--invisibles"]
+ .describe( "show invisibles (tabs, newlines)" )
+ .bind( &ConfigData::showInvisibles );
+
+ cli["-o"]["--out"]
+ .describe( "output filename" )
+ .bind( &ConfigData::outputFilename, "filename" );
+
+ cli["-r"]["--reporter"]
+// .placeholder( "name[:filename]" )
+ .describe( "reporter to use (defaults to console)" )
+ .bind( &addReporterName, "name" );
+
+ cli["-n"]["--name"]
+ .describe( "suite name" )
+ .bind( &ConfigData::name, "name" );
+
+ cli["-a"]["--abort"]
+ .describe( "abort at first failure" )
+ .bind( &abortAfterFirst );
+
+ cli["-x"]["--abortx"]
+ .describe( "abort after x failures" )
+ .bind( &abortAfterX, "no. failures" );
+
+ cli["-w"]["--warn"]
+ .describe( "enable warnings" )
+ .bind( &addWarning, "warning name" );
+
+// - needs updating if reinstated
+// cli.into( &setVerbosity )
+// .describe( "level of verbosity (0=no output)" )
+// .shortOpt( "v")
+// .longOpt( "verbosity" )
+// .placeholder( "level" );
+
+ cli[_]
+ .describe( "which test or tests to use" )
+ .bind( &addTestOrTags, "test name, pattern or tags" );
+
+ cli["-d"]["--durations"]
+ .describe( "show test durations" )
+ .bind( &setShowDurations, "yes|no" );
+
+ cli["-f"]["--input-file"]
+ .describe( "load test names to run from a file" )
+ .bind( &loadTestNamesFromFile, "filename" );
+
+ cli["-#"]["--filenames-as-tags"]
+ .describe( "adds a tag for the filename" )
+ .bind( &ConfigData::filenamesAsTags );
+
+ cli["-c"]["--section"]
+ .describe( "specify section to run" )
+ .bind( &addSectionToRun, "section name" );
+
+ // Less common commands which don't have a short form
+ cli["--list-test-names-only"]
+ .describe( "list all/matching test cases names only" )
+ .bind( &ConfigData::listTestNamesOnly );
+
+ cli["--list-reporters"]
+ .describe( "list all reporters" )
+ .bind( &ConfigData::listReporters );
+
+ cli["--order"]
+ .describe( "test case order (defaults to decl)" )
+ .bind( &setOrder, "decl|lex|rand" );
+
+ cli["--rng-seed"]
+ .describe( "set a specific seed for random numbers" )
+ .bind( &setRngSeed, "'time'|number" );
+
+ cli["--force-colour"]
+ .describe( "force colourised output (deprecated)" )
+ .bind( &forceColour );
+
+ cli["--use-colour"]
+ .describe( "should output be colourised" )
+ .bind( &setUseColour, "yes|no" );
+
+ return cli;
+ }
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+# endif
+# else
+# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+ const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+ const unsigned int consoleWidth = 80;
+#endif
+
+ struct TextAttributes {
+ TextAttributes()
+ : initialIndent( std::string::npos ),
+ indent( 0 ),
+ width( consoleWidth-1 )
+ {}
+
+ TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
+ TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
+ TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
+
+ std::size_t initialIndent; // indent of first line, or npos
+ std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
+ std::size_t width; // maximum width of text, including indent. Longer text will wrap
+ };
+
+ class Text {
+ public:
+ Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+ : attr( _attr )
+ {
+ const std::string wrappableBeforeChars = "[({<\t";
+ const std::string wrappableAfterChars = "])}>-,./|\\";
+ const std::string wrappableInsteadOfChars = " \n\r";
+ std::string indent = _attr.initialIndent != std::string::npos
+ ? std::string( _attr.initialIndent, ' ' )
+ : std::string( _attr.indent, ' ' );
+
+ typedef std::string::const_iterator iterator;
+ iterator it = _str.begin();
+ const iterator strEnd = _str.end();
+
+ while( it != strEnd ) {
+
+ if( lines.size() >= 1000 ) {
+ lines.push_back( "... message truncated due to excessive size" );
+ return;
+ }
+
+ std::string suffix;
+ std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
+ iterator itEnd = it+width;
+ iterator itNext = _str.end();
+
+ iterator itNewLine = std::find( it, itEnd, '\n' );
+ if( itNewLine != itEnd )
+ itEnd = itNewLine;
+
+ if( itEnd != strEnd ) {
+ bool foundWrapPoint = false;
+ iterator findIt = itEnd;
+ do {
+ if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
+ itEnd = findIt+1;
+ itNext = findIt+1;
+ foundWrapPoint = true;
+ }
+ else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
+ itEnd = findIt;
+ itNext = findIt;
+ foundWrapPoint = true;
+ }
+ else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
+ itNext = findIt+1;
+ itEnd = findIt;
+ foundWrapPoint = true;
+ }
+ if( findIt == it )
+ break;
+ else
+ --findIt;
+ }
+ while( !foundWrapPoint );
+
+ if( !foundWrapPoint ) {
+ // No good wrap char, so we'll break mid word and add a hyphen
+ --itEnd;
+ itNext = itEnd;
+ suffix = "-";
+ }
+ else {
+ while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
+ --itEnd;
+ }
+ }
+ lines.push_back( indent + std::string( it, itEnd ) + suffix );
+
+ if( indent.size() != _attr.indent )
+ indent = std::string( _attr.indent, ' ' );
+ it = itNext;
+ }
+ }
+
+ typedef std::vector<std::string>::const_iterator const_iterator;
+
+ const_iterator begin() const { return lines.begin(); }
+ const_iterator end() const { return lines.end(); }
+ std::string const& last() const { return lines.back(); }
+ std::size_t size() const { return lines.size(); }
+ std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+ std::string toString() const {
+ std::ostringstream oss;
+ oss << *this;
+ return oss.str();
+ }
+
+ inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+ for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+ it != itEnd; ++it ) {
+ if( it != _text.begin() )
+ _stream << "\n";
+ _stream << *it;
+ }
+ return _stream;
+ }
+
+ private:
+ std::string str;
+ TextAttributes attr;
+ std::vector<std::string> lines;
+ };
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+ using Tbc::Text;
+ using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+ struct Colour {
+ enum Code {
+ None = 0,
+
+ White,
+ Red,
+ Green,
+ Blue,
+ Cyan,
+ Yellow,
+ Grey,
+
+ Bright = 0x10,
+
+ BrightRed = Bright | Red,
+ BrightGreen = Bright | Green,
+ LightGrey = Bright | Grey,
+ BrightWhite = Bright | White,
+
+ // By intention
+ FileName = LightGrey,
+ Warning = Yellow,
+ ResultError = BrightRed,
+ ResultSuccess = BrightGreen,
+ ResultExpectedFailure = Warning,
+
+ Error = BrightRed,
+ Success = Green,
+
+ OriginalExpression = Cyan,
+ ReconstructedExpression = Yellow,
+
+ SecondaryText = LightGrey,
+ Headers = White
+ };
+
+ // Use constructed object for RAII guard
+ Colour( Code _colourCode );
+ Colour( Colour const& other );
+ ~Colour();
+
+ // Use static method for one-shot changes
+ static void use( Code _colourCode );
+
+ private:
+ bool m_moved;
+ };
+
+ inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <string>
+#include <ostream>
+#include <map>
+
+namespace Catch
+{
+ struct ReporterConfig {
+ explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
+ : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+ ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
+ : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+ std::ostream& stream() const { return *m_stream; }
+ Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+ private:
+ std::ostream* m_stream;
+ Ptr<IConfig const> m_fullConfig;
+ };
+
+ struct ReporterPreferences {
+ ReporterPreferences()
+ : shouldRedirectStdOut( false )
+ {}
+
+ bool shouldRedirectStdOut;
+ };
+
+ template<typename T>
+ struct LazyStat : Option<T> {
+ LazyStat() : used( false ) {}
+ LazyStat& operator=( T const& _value ) {
+ Option<T>::operator=( _value );
+ used = false;
+ return *this;
+ }
+ void reset() {
+ Option<T>::reset();
+ used = false;
+ }
+ bool used;
+ };
+
+ struct TestRunInfo {
+ TestRunInfo( std::string const& _name ) : name( _name ) {}
+ std::string name;
+ };
+ struct GroupInfo {
+ GroupInfo( std::string const& _name,
+ std::size_t _groupIndex,
+ std::size_t _groupsCount )
+ : name( _name ),
+ groupIndex( _groupIndex ),
+ groupsCounts( _groupsCount )
+ {}
+
+ std::string name;
+ std::size_t groupIndex;
+ std::size_t groupsCounts;
+ };
+
+ struct AssertionStats {
+ AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals )
+ : assertionResult( _assertionResult ),
+ infoMessages( _infoMessages ),
+ totals( _totals )
+ {
+ if( assertionResult.hasMessage() ) {
+ // Copy message into messages list.
+ // !TBD This should have been done earlier, somewhere
+ MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+ builder << assertionResult.getMessage();
+ builder.m_info.message = builder.m_stream.str();
+
+ infoMessages.push_back( builder.m_info );
+ }
+ }
+ virtual ~AssertionStats();
+
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ AssertionStats( AssertionStats const& ) = default;
+ AssertionStats( AssertionStats && ) = default;
+ AssertionStats& operator = ( AssertionStats const& ) = default;
+ AssertionStats& operator = ( AssertionStats && ) = default;
+# endif
+
+ AssertionResult assertionResult;
+ std::vector<MessageInfo> infoMessages;
+ Totals totals;
+ };
+
+ struct SectionStats {
+ SectionStats( SectionInfo const& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions )
+ : sectionInfo( _sectionInfo ),
+ assertions( _assertions ),
+ durationInSeconds( _durationInSeconds ),
+ missingAssertions( _missingAssertions )
+ {}
+ virtual ~SectionStats();
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ SectionStats( SectionStats const& ) = default;
+ SectionStats( SectionStats && ) = default;
+ SectionStats& operator = ( SectionStats const& ) = default;
+ SectionStats& operator = ( SectionStats && ) = default;
+# endif
+
+ SectionInfo sectionInfo;
+ Counts assertions;
+ double durationInSeconds;
+ bool missingAssertions;
+ };
+
+ struct TestCaseStats {
+ TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string const& _stdOut,
+ std::string const& _stdErr,
+ bool _aborting )
+ : testInfo( _testInfo ),
+ totals( _totals ),
+ stdOut( _stdOut ),
+ stdErr( _stdErr ),
+ aborting( _aborting )
+ {}
+ virtual ~TestCaseStats();
+
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestCaseStats( TestCaseStats const& ) = default;
+ TestCaseStats( TestCaseStats && ) = default;
+ TestCaseStats& operator = ( TestCaseStats const& ) = default;
+ TestCaseStats& operator = ( TestCaseStats && ) = default;
+# endif
+
+ TestCaseInfo testInfo;
+ Totals totals;
+ std::string stdOut;
+ std::string stdErr;
+ bool aborting;
+ };
+
+ struct TestGroupStats {
+ TestGroupStats( GroupInfo const& _groupInfo,
+ Totals const& _totals,
+ bool _aborting )
+ : groupInfo( _groupInfo ),
+ totals( _totals ),
+ aborting( _aborting )
+ {}
+ TestGroupStats( GroupInfo const& _groupInfo )
+ : groupInfo( _groupInfo ),
+ aborting( false )
+ {}
+ virtual ~TestGroupStats();
+
+# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestGroupStats( TestGroupStats const& ) = default;
+ TestGroupStats( TestGroupStats && ) = default;
+ TestGroupStats& operator = ( TestGroupStats const& ) = default;
+ TestGroupStats& operator = ( TestGroupStats && ) = default;
+# endif
+
+ GroupInfo groupInfo;
+ Totals totals;
+ bool aborting;
+ };
+
+ struct TestRunStats {
+ TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting )
+ : runInfo( _runInfo ),
+ totals( _totals ),
+ aborting( _aborting )
+ {}
+ virtual ~TestRunStats();
+
+# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+ TestRunStats( TestRunStats const& _other )
+ : runInfo( _other.runInfo ),
+ totals( _other.totals ),
+ aborting( _other.aborting )
+ {}
+# else
+ TestRunStats( TestRunStats const& ) = default;
+ TestRunStats( TestRunStats && ) = default;
+ TestRunStats& operator = ( TestRunStats const& ) = default;
+ TestRunStats& operator = ( TestRunStats && ) = default;
+# endif
+
+ TestRunInfo runInfo;
+ Totals totals;
+ bool aborting;
+ };
+
+ class MultipleReporters;
+
+ struct IStreamingReporter : IShared {
+ virtual ~IStreamingReporter();
+
+ // Implementing class must also provide the following static method:
+ // static std::string getDescription();
+
+ virtual ReporterPreferences getPreferences() const = 0;
+
+ virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+ virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+ virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+ virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+ virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+ virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
+ };
+
+ struct IReporterFactory : IShared {
+ virtual ~IReporterFactory();
+ virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
+ virtual std::string getDescription() const = 0;
+ };
+
+ struct IReporterRegistry {
+ typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
+ typedef std::vector<Ptr<IReporterFactory> > Listeners;
+
+ virtual ~IReporterRegistry();
+ virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
+ virtual FactoryMap const& getFactories() const = 0;
+ virtual Listeners const& getListeners() const = 0;
+ };
+
+ Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
+
+}
+
+#include <limits>
+#include <algorithm>
+
+namespace Catch {
+
+ inline std::size_t listTests( Config const& config ) {
+
+ TestSpec testSpec = config.testSpec();
+ if( config.testSpec().hasFilters() )
+ Catch::cout() << "Matching test cases:\n";
+ else {
+ Catch::cout() << "All available test cases:\n";
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+ }
+
+ std::size_t matchedTests = 0;
+ TextAttributes nameAttr, tagsAttr;
+ nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+ tagsAttr.setIndent( 6 );
+
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+ for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it ) {
+ matchedTests++;
+ TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+ Colour::Code colour = testCaseInfo.isHidden()
+ ? Colour::SecondaryText
+ : Colour::None;
+ Colour colourGuard( colour );
+
+ Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
+ if( !testCaseInfo.tags.empty() )
+ Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
+ }
+
+ if( !config.testSpec().hasFilters() )
+ Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
+ else
+ Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
+ return matchedTests;
+ }
+
+ inline std::size_t listTestsNamesOnly( Config const& config ) {
+ TestSpec testSpec = config.testSpec();
+ if( !config.testSpec().hasFilters() )
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+ std::size_t matchedTests = 0;
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+ for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it ) {
+ matchedTests++;
+ TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+ if( startsWith( testCaseInfo.name, '#' ) )
+ Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
+ else
+ Catch::cout() << testCaseInfo.name << std::endl;
+ }
+ return matchedTests;
+ }
+
+ struct TagInfo {
+ TagInfo() : count ( 0 ) {}
+ void add( std::string const& spelling ) {
+ ++count;
+ spellings.insert( spelling );
+ }
+ std::string all() const {
+ std::string out;
+ for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+ it != itEnd;
+ ++it )
+ out += "[" + *it + "]";
+ return out;
+ }
+ std::set<std::string> spellings;
+ std::size_t count;
+ };
+
+ inline std::size_t listTags( Config const& config ) {
+ TestSpec testSpec = config.testSpec();
+ if( config.testSpec().hasFilters() )
+ Catch::cout() << "Tags for matching test cases:\n";
+ else {
+ Catch::cout() << "All available tags:\n";
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+ }
+
+ std::map<std::string, TagInfo> tagCounts;
+
+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+ for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+ it != itEnd;
+ ++it ) {
+ for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
+ tagItEnd = it->getTestCaseInfo().tags.end();
+ tagIt != tagItEnd;
+ ++tagIt ) {
+ std::string tagName = *tagIt;
+ std::string lcaseTagName = toLower( tagName );
+ std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
+ if( countIt == tagCounts.end() )
+ countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+ countIt->second.add( tagName );
+ }
+ }
+
+ for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+ countItEnd = tagCounts.end();
+ countIt != countItEnd;
+ ++countIt ) {
+ std::ostringstream oss;
+ oss << " " << std::setw(2) << countIt->second.count << " ";
+ Text wrapper( countIt->second.all(), TextAttributes()
+ .setInitialIndent( 0 )
+ .setIndent( oss.str().size() )
+ .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
+ Catch::cout() << oss.str() << wrapper << '\n';
+ }
+ Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
+ return tagCounts.size();
+ }
+
+ inline std::size_t listReporters( Config const& /*config*/ ) {
+ Catch::cout() << "Available reporters:\n";
+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+ IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+ std::size_t maxNameLen = 0;
+ for(it = itBegin; it != itEnd; ++it )
+ maxNameLen = (std::max)( maxNameLen, it->first.size() );
+
+ for(it = itBegin; it != itEnd; ++it ) {
+ Text wrapper( it->second->getDescription(), TextAttributes()
+ .setInitialIndent( 0 )
+ .setIndent( 7+maxNameLen )
+ .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
+ Catch::cout() << " "
+ << it->first
+ << ':'
+ << std::string( maxNameLen - it->first.size() + 2, ' ' )
+ << wrapper << '\n';
+ }
+ Catch::cout() << std::endl;
+ return factories.size();
+ }
+
+ inline Option<std::size_t> list( Config const& config ) {
+ Option<std::size_t> listedCount;
+ if( config.listTests() )
+ listedCount = listedCount.valueOr(0) + listTests( config );
+ if( config.listTestNamesOnly() )
+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+ if( config.listTags() )
+ listedCount = listedCount.valueOr(0) + listTags( config );
+ if( config.listReporters() )
+ listedCount = listedCount.valueOr(0) + listReporters( config );
+ return listedCount;
+ }
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <assert.h>
+#include <vector>
+#include <iterator>
+#include <stdexcept>
+
+namespace Catch {
+namespace TestCaseTracking {
+
+ struct NameAndLocation {
+ std::string name;
+ SourceLineInfo location;
+
+ NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+ : name( _name ),
+ location( _location )
+ {}
+ };
+
+ struct ITracker : SharedImpl<> {
+ virtual ~ITracker();
+
+ // static queries
+ virtual NameAndLocation const& nameAndLocation() const = 0;
+
+ // dynamic queries
+ virtual bool isComplete() const = 0; // Successfully completed or failed
+ virtual bool isSuccessfullyCompleted() const = 0;
+ virtual bool isOpen() const = 0; // Started but not complete
+ virtual bool hasChildren() const = 0;
+
+ virtual ITracker& parent() = 0;
+
+ // actions
+ virtual void close() = 0; // Successfully complete
+ virtual void fail() = 0;
+ virtual void markAsNeedingAnotherRun() = 0;
+
+ virtual void addChild( Ptr<ITracker> const& child ) = 0;
+ virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
+ virtual void openChild() = 0;
+
+ // Debug/ checking
+ virtual bool isSectionTracker() const = 0;
+ virtual bool isIndexTracker() const = 0;
+ };
+
+ class TrackerContext {
+
+ enum RunState {
+ NotStarted,
+ Executing,
+ CompletedCycle
+ };
+
+ Ptr<ITracker> m_rootTracker;
+ ITracker* m_currentTracker;
+ RunState m_runState;
+
+ public:
+
+ static TrackerContext& instance() {
+ static TrackerContext s_instance;
+ return s_instance;
+ }
+
+ TrackerContext()
+ : m_currentTracker( CATCH_NULL ),
+ m_runState( NotStarted )
+ {}
+
+ ITracker& startRun();
+
+ void endRun() {
+ m_rootTracker.reset();
+ m_currentTracker = CATCH_NULL;
+ m_runState = NotStarted;
+ }
+
+ void startCycle() {
+ m_currentTracker = m_rootTracker.get();
+ m_runState = Executing;
+ }
+ void completeCycle() {
+ m_runState = CompletedCycle;
+ }
+
+ bool completedCycle() const {
+ return m_runState == CompletedCycle;
+ }
+ ITracker& currentTracker() {
+ return *m_currentTracker;
+ }
+ void setCurrentTracker( ITracker* tracker ) {
+ m_currentTracker = tracker;
+ }
+ };
+
+ class TrackerBase : public ITracker {
+ protected:
+ enum CycleState {
+ NotStarted,
+ Executing,
+ ExecutingChildren,
+ NeedsAnotherRun,
+ CompletedSuccessfully,
+ Failed
+ };
+ class TrackerHasName {
+ NameAndLocation m_nameAndLocation;
+ public:
+ TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
+ bool operator ()( Ptr<ITracker> const& tracker ) {
+ return
+ tracker->nameAndLocation().name == m_nameAndLocation.name &&
+ tracker->nameAndLocation().location == m_nameAndLocation.location;
+ }
+ };
+ typedef std::vector<Ptr<ITracker> > Children;
+ NameAndLocation m_nameAndLocation;
+ TrackerContext& m_ctx;
+ ITracker* m_parent;
+ Children m_children;
+ CycleState m_runState;
+ public:
+ TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : m_nameAndLocation( nameAndLocation ),
+ m_ctx( ctx ),
+ m_parent( parent ),
+ m_runState( NotStarted )
+ {}
+ virtual ~TrackerBase();
+
+ virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
+ return m_nameAndLocation;
+ }
+ virtual bool isComplete() const CATCH_OVERRIDE {
+ return m_runState == CompletedSuccessfully || m_runState == Failed;
+ }
+ virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
+ return m_runState == CompletedSuccessfully;
+ }
+ virtual bool isOpen() const CATCH_OVERRIDE {
+ return m_runState != NotStarted && !isComplete();
+ }
+ virtual bool hasChildren() const CATCH_OVERRIDE {
+ return !m_children.empty();
+ }
+
+ virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
+ m_children.push_back( child );
+ }
+
+ virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
+ Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
+ return( it != m_children.end() )
+ ? it->get()
+ : CATCH_NULL;
+ }
+ virtual ITracker& parent() CATCH_OVERRIDE {
+ assert( m_parent ); // Should always be non-null except for root
+ return *m_parent;
+ }
+
+ virtual void openChild() CATCH_OVERRIDE {
+ if( m_runState != ExecutingChildren ) {
+ m_runState = ExecutingChildren;
+ if( m_parent )
+ m_parent->openChild();
+ }
+ }
+
+ virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
+ virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
+
+ void open() {
+ m_runState = Executing;
+ moveToThis();
+ if( m_parent )
+ m_parent->openChild();
+ }
+
+ virtual void close() CATCH_OVERRIDE {
+
+ // Close any still open children (e.g. generators)
+ while( &m_ctx.currentTracker() != this )
+ m_ctx.currentTracker().close();
+
+ switch( m_runState ) {
+ case NotStarted:
+ case CompletedSuccessfully:
+ case Failed:
+ throw std::logic_error( "Illogical state" );
+
+ case NeedsAnotherRun:
+ break;;
+
+ case Executing:
+ m_runState = CompletedSuccessfully;
+ break;
+ case ExecutingChildren:
+ if( m_children.empty() || m_children.back()->isComplete() )
+ m_runState = CompletedSuccessfully;
+ break;
+
+ default:
+ throw std::logic_error( "Unexpected state" );
+ }
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ virtual void fail() CATCH_OVERRIDE {
+ m_runState = Failed;
+ if( m_parent )
+ m_parent->markAsNeedingAnotherRun();
+ moveToParent();
+ m_ctx.completeCycle();
+ }
+ virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
+ m_runState = NeedsAnotherRun;
+ }
+ private:
+ void moveToParent() {
+ assert( m_parent );
+ m_ctx.setCurrentTracker( m_parent );
+ }
+ void moveToThis() {
+ m_ctx.setCurrentTracker( this );
+ }
+ };
+
+ class SectionTracker : public TrackerBase {
+ std::vector<std::string> m_filters;
+ public:
+ SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+ : TrackerBase( nameAndLocation, ctx, parent )
+ {
+ if( parent ) {
+ while( !parent->isSectionTracker() )
+ parent = &parent->parent();
+
+ SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+ addNextFilters( parentSection.m_filters );
+ }
+ }
+ virtual ~SectionTracker();
+
+ virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
+
+ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+ SectionTracker* section = CATCH_NULL;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isSectionTracker() );
+ section = static_cast<SectionTracker*>( childTracker );
+ }
+ else {
+ section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
+ currentTracker.addChild( section );
+ }
+ if( !ctx.completedCycle() )
+ section->tryOpen();
+ return *section;
+ }
+
+ void tryOpen() {
+ if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
+ open();
+ }
+
+ void addInitialFilters( std::vector<std::string> const& filters ) {
+ if( !filters.empty() ) {
+ m_filters.push_back(""); // Root - should never be consulted
+ m_filters.push_back(""); // Test Case - not a section filter
+ std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) );
+ }
+ }
+ void addNextFilters( std::vector<std::string> const& filters ) {
+ if( filters.size() > 1 )
+ std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) );
+ }
+ };
+
+ class IndexTracker : public TrackerBase {
+ int m_size;
+ int m_index;
+ public:
+ IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
+ : TrackerBase( nameAndLocation, ctx, parent ),
+ m_size( size ),
+ m_index( -1 )
+ {}
+ virtual ~IndexTracker();
+
+ virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
+
+ static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
+ IndexTracker* tracker = CATCH_NULL;
+
+ ITracker& currentTracker = ctx.currentTracker();
+ if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+ assert( childTracker );
+ assert( childTracker->isIndexTracker() );
+ tracker = static_cast<IndexTracker*>( childTracker );
+ }
+ else {
+ tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
+ currentTracker.addChild( tracker );
+ }
+
+ if( !ctx.completedCycle() && !tracker->isComplete() ) {
+ if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
+ tracker->moveNext();
+ tracker->open();
+ }
+
+ return *tracker;
+ }
+
+ int index() const { return m_index; }
+
+ void moveNext() {
+ m_index++;
+ m_children.clear();
+ }
+
+ virtual void close() CATCH_OVERRIDE {
+ TrackerBase::close();
+ if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
+ m_runState = Executing;
+ }
+ };
+
+ inline ITracker& TrackerContext::startRun() {
+ m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
+ m_currentTracker = CATCH_NULL;
+ m_runState = Executing;
+ return *m_rootTracker;
+ }
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+ // Report the error condition
+ inline void reportFatal( std::string const& message ) {
+ IContext& context = Catch::getCurrentContext();
+ IResultCapture* resultCapture = context.getResultCapture();
+ resultCapture->handleFatalErrorCondition( message );
+ }
+
+} // namespace Catch
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+// #included from: catch_windows_h_proxy.h
+
+#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED
+
+#ifdef CATCH_DEFINES_NOMINMAX
+# define NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINES_NOMINMAX
+# undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+
+# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+ struct FatalConditionHandler {
+ void reset() {}
+ };
+}
+
+# else // CATCH_CONFIG_WINDOWS_SEH is defined
+
+namespace Catch {
+
+ struct SignalDefs { DWORD id; const char* name; };
+ extern SignalDefs signalDefs[];
+ // There is no 1-1 mapping between signals and windows exceptions.
+ // Windows can easily distinguish between SO and SigSegV,
+ // but SigInt, SigTerm, etc are handled differently.
+ SignalDefs signalDefs[] = {
+ { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
+ { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+ { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+ { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+ };
+
+ struct FatalConditionHandler {
+
+ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+ for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+ reset();
+ reportFatal(signalDefs[i].name);
+ }
+ }
+ // If its not an exception we care about, pass it along.
+ // This stops us from eating debugger breaks etc.
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ FatalConditionHandler() {
+ isSet = true;
+ // 32k seems enough for Catch to handle stack overflow,
+ // but the value was found experimentally, so there is no strong guarantee
+ guaranteeSize = 32 * 1024;
+ exceptionHandlerHandle = CATCH_NULL;
+ // Register as first handler in current chain
+ exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+ // Pass in guarantee size to be filled
+ SetThreadStackGuarantee(&guaranteeSize);
+ }
+
+ static void reset() {
+ if (isSet) {
+ // Unregister handler and restore the old guarantee
+ RemoveVectoredExceptionHandler(exceptionHandlerHandle);
+ SetThreadStackGuarantee(&guaranteeSize);
+ exceptionHandlerHandle = CATCH_NULL;
+ isSet = false;
+ }
+ }
+
+ ~FatalConditionHandler() {
+ reset();
+ }
+ private:
+ static bool isSet;
+ static ULONG guaranteeSize;
+ static PVOID exceptionHandlerHandle;
+ };
+
+ bool FatalConditionHandler::isSet = false;
+ ULONG FatalConditionHandler::guaranteeSize = 0;
+ PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
+
+} // namespace Catch
+
+# endif // CATCH_CONFIG_WINDOWS_SEH
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+
+namespace Catch {
+ struct FatalConditionHandler {
+ void reset() {}
+ };
+}
+
+# else // CATCH_CONFIG_POSIX_SIGNALS is defined
+
+#include <signal.h>
+
+namespace Catch {
+
+ struct SignalDefs {
+ int id;
+ const char* name;
+ };
+ extern SignalDefs signalDefs[];
+ SignalDefs signalDefs[] = {
+ { SIGINT, "SIGINT - Terminal interrupt signal" },
+ { SIGILL, "SIGILL - Illegal instruction signal" },
+ { SIGFPE, "SIGFPE - Floating point error signal" },
+ { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+ { SIGTERM, "SIGTERM - Termination request signal" },
+ { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+ };
+
+ struct FatalConditionHandler {
+
+ static bool isSet;
+ static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
+ static stack_t oldSigStack;
+ static char altStackMem[SIGSTKSZ];
+
+ static void handleSignal( int sig ) {
+ std::string name = "<unknown signal>";
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ SignalDefs &def = signalDefs[i];
+ if (sig == def.id) {
+ name = def.name;
+ break;
+ }
+ }
+ reset();
+ reportFatal(name);
+ raise( sig );
+ }
+
+ FatalConditionHandler() {
+ isSet = true;
+ stack_t sigStack;
+ sigStack.ss_sp = altStackMem;
+ sigStack.ss_size = SIGSTKSZ;
+ sigStack.ss_flags = 0;
+ sigaltstack(&sigStack, &oldSigStack);
+ struct sigaction sa = { 0 };
+
+ sa.sa_handler = handleSignal;
+ sa.sa_flags = SA_ONSTACK;
+ for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+ sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+ }
+ }
+
+ ~FatalConditionHandler() {
+ reset();
+ }
+ static void reset() {
+ if( isSet ) {
+ // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
+ for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
+ sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
+ }
+ // Return the old stack
+ sigaltstack(&oldSigStack, CATCH_NULL);
+ isSet = false;
+ }
+ }
+ };
+
+ bool FatalConditionHandler::isSet = false;
+ struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+ stack_t FatalConditionHandler::oldSigStack = {};
+ char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+
+} // namespace Catch
+
+# endif // CATCH_CONFIG_POSIX_SIGNALS
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+ class StreamRedirect {
+
+ public:
+ StreamRedirect( std::ostream& stream, std::string& targetString )
+ : m_stream( stream ),
+ m_prevBuf( stream.rdbuf() ),
+ m_targetString( targetString )
+ {
+ stream.rdbuf( m_oss.rdbuf() );
+ }
+
+ ~StreamRedirect() {
+ m_targetString += m_oss.str();
+ m_stream.rdbuf( m_prevBuf );
+ }
+
+ private:
+ std::ostream& m_stream;
+ std::streambuf* m_prevBuf;
+ std::ostringstream m_oss;
+ std::string& m_targetString;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class RunContext : public IResultCapture, public IRunner {
+
+ RunContext( RunContext const& );
+ void operator =( RunContext const& );
+
+ public:
+
+ explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
+ : m_runInfo( _config->name() ),
+ m_context( getCurrentMutableContext() ),
+ m_activeTestCase( CATCH_NULL ),
+ m_config( _config ),
+ m_reporter( reporter )
+ {
+ m_context.setRunner( this );
+ m_context.setConfig( m_config );
+ m_context.setResultCapture( this );
+ m_reporter->testRunStarting( m_runInfo );
+ }
+
+ virtual ~RunContext() {
+ m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
+ }
+
+ void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
+ m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
+ }
+ void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
+ m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
+ }
+
+ Totals runTest( TestCase const& testCase ) {
+ Totals prevTotals = m_totals;
+
+ std::string redirectedCout;
+ std::string redirectedCerr;
+
+ TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+ m_reporter->testCaseStarting( testInfo );
+
+ m_activeTestCase = &testCase;
+
+ do {
+ ITracker& rootTracker = m_trackerContext.startRun();
+ assert( rootTracker.isSectionTracker() );
+ static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
+ do {
+ m_trackerContext.startCycle();
+ m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
+ runCurrentTest( redirectedCout, redirectedCerr );
+ }
+ while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
+ }
+ // !TBD: deprecated - this will be replaced by indexed trackers
+ while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
+
+ Totals deltaTotals = m_totals.delta( prevTotals );
+ if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
+ deltaTotals.assertions.failed++;
+ deltaTotals.testCases.passed--;
+ deltaTotals.testCases.failed++;
+ }
+ m_totals.testCases += deltaTotals.testCases;
+ m_reporter->testCaseEnded( TestCaseStats( testInfo,
+ deltaTotals,
+ redirectedCout,
+ redirectedCerr,
+ aborting() ) );
+
+ m_activeTestCase = CATCH_NULL;
+ m_testCaseTracker = CATCH_NULL;
+
+ return deltaTotals;
+ }
+
+ Ptr<IConfig const> config() const {
+ return m_config;
+ }
+
+ private: // IResultCapture
+
+ virtual void assertionEnded( AssertionResult const& result ) {
+ if( result.getResultType() == ResultWas::Ok ) {
+ m_totals.assertions.passed++;
+ }
+ else if( !result.isOk() ) {
+ m_totals.assertions.failed++;
+ }
+
+ if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
+ m_messages.clear();
+
+ // Reset working state
+ m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+ m_lastResult = result;
+ }
+
+ virtual bool sectionStarted (
+ SectionInfo const& sectionInfo,
+ Counts& assertions
+ )
+ {
+ ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
+ if( !sectionTracker.isOpen() )
+ return false;
+ m_activeSections.push_back( &sectionTracker );
+
+ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+ m_reporter->sectionStarting( sectionInfo );
+
+ assertions = m_totals.assertions;
+
+ return true;
+ }
+ bool testForMissingAssertions( Counts& assertions ) {
+ if( assertions.total() != 0 )
+ return false;
+ if( !m_config->warnAboutMissingAssertions() )
+ return false;
+ if( m_trackerContext.currentTracker().hasChildren() )
+ return false;
+ m_totals.assertions.failed++;
+ assertions.failed++;
+ return true;
+ }
+
+ virtual void sectionEnded( SectionEndInfo const& endInfo ) {
+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+ bool missingAssertions = testForMissingAssertions( assertions );
+
+ if( !m_activeSections.empty() ) {
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+ }
+
+ m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
+ m_messages.clear();
+ }
+
+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
+ if( m_unfinishedSections.empty() )
+ m_activeSections.back()->fail();
+ else
+ m_activeSections.back()->close();
+ m_activeSections.pop_back();
+
+ m_unfinishedSections.push_back( endInfo );
+ }
+
+ virtual void pushScopedMessage( MessageInfo const& message ) {
+ m_messages.push_back( message );
+ }
+
+ virtual void popScopedMessage( MessageInfo const& message ) {
+ m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
+ }
+
+ virtual std::string getCurrentTestName() const {
+ return m_activeTestCase
+ ? m_activeTestCase->getTestCaseInfo().name
+ : std::string();
+ }
+
+ virtual const AssertionResult* getLastResult() const {
+ return &m_lastResult;
+ }
+
+ virtual void handleFatalErrorCondition( std::string const& message ) {
+ ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
+ resultBuilder.setResultType( ResultWas::FatalErrorCondition );
+ resultBuilder << message;
+ resultBuilder.captureExpression();
+
+ handleUnfinishedSections();
+
+ // Recreate section for test case (as we will lose the one that was in scope)
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+
+ Counts assertions;
+ assertions.failed = 1;
+ SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
+ m_reporter->sectionEnded( testCaseSectionStats );
+
+ TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+ Totals deltaTotals;
+ deltaTotals.testCases.failed = 1;
+ m_reporter->testCaseEnded( TestCaseStats( testInfo,
+ deltaTotals,
+ std::string(),
+ std::string(),
+ false ) );
+ m_totals.testCases.failed++;
+ testGroupEnded( std::string(), m_totals, 1, 1 );
+ m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
+ }
+
+ public:
+ // !TBD We need to do this another way!
+ bool aborting() const {
+ return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
+ }
+
+ private:
+
+ void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
+ TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+ SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+ m_reporter->sectionStarting( testCaseSection );
+ Counts prevAssertions = m_totals.assertions;
+ double duration = 0;
+ try {
+ m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
+
+ seedRng( *m_config );
+
+ Timer timer;
+ timer.start();
+ if( m_reporter->getPreferences().shouldRedirectStdOut ) {
+ StreamRedirect coutRedir( Catch::cout(), redirectedCout );
+ StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
+ invokeActiveTestCase();
+ }
+ else {
+ invokeActiveTestCase();
+ }
+ duration = timer.getElapsedSeconds();
+ }
+ catch( TestFailureException& ) {
+ // This just means the test was aborted due to failure
+ }
+ catch(...) {
+ makeUnexpectedResultBuilder().useActiveException();
+ }
+ m_testCaseTracker->close();
+ handleUnfinishedSections();
+ m_messages.clear();
+
+ Counts assertions = m_totals.assertions - prevAssertions;
+ bool missingAssertions = testForMissingAssertions( assertions );
+
+ if( testCaseInfo.okToFail() ) {
+ std::swap( assertions.failedButOk, assertions.failed );
+ m_totals.assertions.failed -= assertions.failedButOk;
+ m_totals.assertions.failedButOk += assertions.failedButOk;
+ }
+
+ SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
+ m_reporter->sectionEnded( testCaseSectionStats );
+ }
+
+ void invokeActiveTestCase() {
+ FatalConditionHandler fatalConditionHandler; // Handle signals
+ m_activeTestCase->invoke();
+ fatalConditionHandler.reset();
+ }
+
+ private:
+
+ ResultBuilder makeUnexpectedResultBuilder() const {
+ return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
+ m_lastAssertionInfo.lineInfo,
+ m_lastAssertionInfo.capturedExpression.c_str(),
+ m_lastAssertionInfo.resultDisposition );
+ }
+
+ void handleUnfinishedSections() {
+ // If sections ended prematurely due to an exception we stored their
+ // infos here so we can tear them down outside the unwind process.
+ for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+ itEnd = m_unfinishedSections.rend();
+ it != itEnd;
+ ++it )
+ sectionEnded( *it );
+ m_unfinishedSections.clear();
+ }
+
+ TestRunInfo m_runInfo;
+ IMutableContext& m_context;
+ TestCase const* m_activeTestCase;
+ ITracker* m_testCaseTracker;
+ ITracker* m_currentSectionTracker;
+ AssertionResult m_lastResult;
+
+ Ptr<IConfig const> m_config;
+ Totals m_totals;
+ Ptr<IStreamingReporter> m_reporter;
+ std::vector<MessageInfo> m_messages;
+ AssertionInfo m_lastAssertionInfo;
+ std::vector<SectionEndInfo> m_unfinishedSections;
+ std::vector<ITracker*> m_activeSections;
+ TrackerContext m_trackerContext;
+ };
+
+ IResultCapture& getResultCapture() {
+ if( IResultCapture* capture = getCurrentContext().getResultCapture() )
+ return *capture;
+ else
+ throw std::logic_error( "No result capture instance" );
+ }
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+ // Versioning information
+ struct Version {
+ Version( unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ std::string const& _branchName,
+ unsigned int _buildNumber );
+
+ unsigned int const majorVersion;
+ unsigned int const minorVersion;
+ unsigned int const patchNumber;
+
+ // buildNumber is only used if branchName is not null
+ std::string const branchName;
+ unsigned int const buildNumber;
+
+ friend std::ostream& operator << ( std::ostream& os, Version const& version );
+
+ private:
+ void operator=( Version const& );
+ };
+
+ extern Version libraryVersion;
+}
+
+#include <fstream>
+#include <stdlib.h>
+#include <limits>
+
+namespace Catch {
+
+ Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
+ Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
+ if( !reporter ) {
+ std::ostringstream oss;
+ oss << "No reporter registered with name: '" << reporterName << "'";
+ throw std::domain_error( oss.str() );
+ }
+ return reporter;
+ }
+
+ Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
+ std::vector<std::string> reporters = config->getReporterNames();
+ if( reporters.empty() )
+ reporters.push_back( "console" );
+
+ Ptr<IStreamingReporter> reporter;
+ for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+ it != itEnd;
+ ++it )
+ reporter = addReporter( reporter, createReporter( *it, config ) );
+ return reporter;
+ }
+ Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
+ IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+ for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+ it != itEnd;
+ ++it )
+ reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
+ return reporters;
+ }
+
+ Totals runTests( Ptr<Config> const& config ) {
+
+ Ptr<IConfig const> iconfig = config.get();
+
+ Ptr<IStreamingReporter> reporter = makeReporter( config );
+ reporter = addListeners( iconfig, reporter );
+
+ RunContext context( iconfig, reporter );
+
+ Totals totals;
+
+ context.testGroupStarting( config->name(), 1, 1 );
+
+ TestSpec testSpec = config->testSpec();
+ if( !testSpec.hasFilters() )
+ testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
+
+ std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
+ for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+ it != itEnd;
+ ++it ) {
+ if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
+ totals += context.runTest( *it );
+ else
+ reporter->skipTest( *it );
+ }
+
+ context.testGroupEnded( iconfig->name(), totals, 1, 1 );
+ return totals;
+ }
+
+ void applyFilenamesAsTags( IConfig const& config ) {
+ std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
+ for(std::size_t i = 0; i < tests.size(); ++i ) {
+ TestCase& test = const_cast<TestCase&>( tests[i] );
+ std::set<std::string> tags = test.tags;
+
+ std::string filename = test.lineInfo.file;
+ std::string::size_type lastSlash = filename.find_last_of( "\\/" );
+ if( lastSlash != std::string::npos )
+ filename = filename.substr( lastSlash+1 );
+
+ std::string::size_type lastDot = filename.find_last_of( "." );
+ if( lastDot != std::string::npos )
+ filename = filename.substr( 0, lastDot );
+
+ tags.insert( "#" + filename );
+ setTags( test, tags );
+ }
+ }
+
+ class Session : NonCopyable {
+ static bool alreadyInstantiated;
+
+ public:
+
+ struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
+
+ Session()
+ : m_cli( makeCommandLineParser() ) {
+ if( alreadyInstantiated ) {
+ std::string msg = "Only one instance of Catch::Session can ever be used";
+ Catch::cerr() << msg << std::endl;
+ throw std::logic_error( msg );
+ }
+ alreadyInstantiated = true;
+ }
+ ~Session() {
+ Catch::cleanUp();
+ }
+
+ void showHelp( std::string const& processName ) {
+ Catch::cout() << "\nCatch v" << libraryVersion << "\n";
+
+ m_cli.usage( Catch::cout(), processName );
+ Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
+ }
+
+ int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
+ try {
+ m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
+ m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
+ if( m_configData.showHelp )
+ showHelp( m_configData.processName );
+ m_config.reset();
+ }
+ catch( std::exception& ex ) {
+ {
+ Colour colourGuard( Colour::Red );
+ Catch::cerr()
+ << "\nError(s) in input:\n"
+ << Text( ex.what(), TextAttributes().setIndent(2) )
+ << "\n\n";
+ }
+ m_cli.usage( Catch::cout(), m_configData.processName );
+ return (std::numeric_limits<int>::max)();
+ }
+ return 0;
+ }
+
+ void useConfigData( ConfigData const& _configData ) {
+ m_configData = _configData;
+ m_config.reset();
+ }
+
+ int run( int argc, char const* const* const argv ) {
+
+ int returnCode = applyCommandLine( argc, argv );
+ if( returnCode == 0 )
+ returnCode = run();
+ return returnCode;
+ }
+
+ int run() {
+ if( m_configData.showHelp )
+ return 0;
+
+ try
+ {
+ config(); // Force config to be constructed
+
+ seedRng( *m_config );
+
+ if( m_configData.filenamesAsTags )
+ applyFilenamesAsTags( *m_config );
+
+ // Handle list request
+ if( Option<std::size_t> listed = list( config() ) )
+ return static_cast<int>( *listed );
+
+ return static_cast<int>( runTests( m_config ).assertions.failed );
+ }
+ catch( std::exception& ex ) {
+ Catch::cerr() << ex.what() << std::endl;
+ return (std::numeric_limits<int>::max)();
+ }
+ }
+
+ Clara::CommandLine<ConfigData> const& cli() const {
+ return m_cli;
+ }
+ std::vector<Clara::Parser::Token> const& unusedTokens() const {
+ return m_unusedTokens;
+ }
+ ConfigData& configData() {
+ return m_configData;
+ }
+ Config& config() {
+ if( !m_config )
+ m_config = new Config( m_configData );
+ return *m_config;
+ }
+ private:
+ Clara::CommandLine<ConfigData> m_cli;
+ std::vector<Clara::Parser::Token> m_unusedTokens;
+ ConfigData m_configData;
+ Ptr<Config> m_config;
+ };
+
+ bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+ struct RandomNumberGenerator {
+ typedef std::ptrdiff_t result_type;
+
+ result_type operator()( result_type n ) const { return std::rand() % n; }
+
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+ static constexpr result_type min() { return 0; }
+ static constexpr result_type max() { return 1000000; }
+ result_type operator()() const { return std::rand() % max(); }
+#endif
+ template<typename V>
+ static void shuffle( V& vector ) {
+ RandomNumberGenerator rng;
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+ std::shuffle( vector.begin(), vector.end(), rng );
+#else
+ std::random_shuffle( vector.begin(), vector.end(), rng );
+#endif
+ }
+ };
+
+ inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+
+ std::vector<TestCase> sorted = unsortedTestCases;
+
+ switch( config.runOrder() ) {
+ case RunTests::InLexicographicalOrder:
+ std::sort( sorted.begin(), sorted.end() );
+ break;
+ case RunTests::InRandomOrder:
+ {
+ seedRng( config );
+ RandomNumberGenerator::shuffle( sorted );
+ }
+ break;
+ case RunTests::InDeclarationOrder:
+ // already in declaration order
+ break;
+ }
+ return sorted;
+ }
+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+ return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+ }
+
+ void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+ std::set<TestCase> seenFunctions;
+ for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+ it != itEnd;
+ ++it ) {
+ std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
+ if( !prev.second ) {
+ std::ostringstream ss;
+
+ ss << Colour( Colour::Red )
+ << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
+ << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+
+ throw std::runtime_error(ss.str());
+ }
+ }
+ }
+
+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+ std::vector<TestCase> filtered;
+ filtered.reserve( testCases.size() );
+ for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+ it != itEnd;
+ ++it )
+ if( matchTest( *it, testSpec, config ) )
+ filtered.push_back( *it );
+ return filtered;
+ }
+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+ }
+
+ class TestRegistry : public ITestCaseRegistry {
+ public:
+ TestRegistry()
+ : m_currentSortOrder( RunTests::InDeclarationOrder ),
+ m_unnamedCount( 0 )
+ {}
+ virtual ~TestRegistry();
+
+ virtual void registerTest( TestCase const& testCase ) {
+ std::string name = testCase.getTestCaseInfo().name;
+ if( name.empty() ) {
+ std::ostringstream oss;
+ oss << "Anonymous test case " << ++m_unnamedCount;
+ return registerTest( testCase.withName( oss.str() ) );
+ }
+ m_functions.push_back( testCase );
+ }
+
+ virtual std::vector<TestCase> const& getAllTests() const {
+ return m_functions;
+ }
+ virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
+ if( m_sortedFunctions.empty() )
+ enforceNoDuplicateTestCases( m_functions );
+
+ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+ m_sortedFunctions = sortTests( config, m_functions );
+ m_currentSortOrder = config.runOrder();
+ }
+ return m_sortedFunctions;
+ }
+
+ private:
+ std::vector<TestCase> m_functions;
+ mutable RunTests::InWhatOrder m_currentSortOrder;
+ mutable std::vector<TestCase> m_sortedFunctions;
+ size_t m_unnamedCount;
+ std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class FreeFunctionTestCase : public SharedImpl<ITestCase> {
+ public:
+
+ FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
+
+ virtual void invoke() const {
+ m_fun();
+ }
+
+ private:
+ virtual ~FreeFunctionTestCase();
+
+ TestFunction m_fun;
+ };
+
+ inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+ std::string className = classOrQualifiedMethodName;
+ if( startsWith( className, '&' ) )
+ {
+ std::size_t lastColons = className.rfind( "::" );
+ std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+ if( penultimateColons == std::string::npos )
+ penultimateColons = 1;
+ className = className.substr( penultimateColons, lastColons-penultimateColons );
+ }
+ return className;
+ }
+
+ void registerTestCase
+ ( ITestCase* testCase,
+ char const* classOrQualifiedMethodName,
+ NameAndDesc const& nameAndDesc,
+ SourceLineInfo const& lineInfo ) {
+
+ getMutableRegistryHub().registerTest
+ ( makeTestCase
+ ( testCase,
+ extractClassName( classOrQualifiedMethodName ),
+ nameAndDesc.name,
+ nameAndDesc.description,
+ lineInfo ) );
+ }
+ void registerTestCaseFunction
+ ( TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc ) {
+ registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ AutoReg::AutoReg
+ ( TestFunction function,
+ SourceLineInfo const& lineInfo,
+ NameAndDesc const& nameAndDesc ) {
+ registerTestCaseFunction( function, lineInfo, nameAndDesc );
+ }
+
+ AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+ class ReporterRegistry : public IReporterRegistry {
+
+ public:
+
+ virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+ virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
+ FactoryMap::const_iterator it = m_factories.find( name );
+ if( it == m_factories.end() )
+ return CATCH_NULL;
+ return it->second->create( ReporterConfig( config ) );
+ }
+
+ void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
+ m_factories.insert( std::make_pair( name, factory ) );
+ }
+ void registerListener( Ptr<IReporterFactory> const& factory ) {
+ m_listeners.push_back( factory );
+ }
+
+ virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
+ return m_factories;
+ }
+ virtual Listeners const& getListeners() const CATCH_OVERRIDE {
+ return m_listeners;
+ }
+
+ private:
+ FactoryMap m_factories;
+ Listeners m_listeners;
+ };
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+ class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+ public:
+ ~ExceptionTranslatorRegistry() {
+ deleteAll( m_translators );
+ }
+
+ virtual void registerTranslator( const IExceptionTranslator* translator ) {
+ m_translators.push_back( translator );
+ }
+
+ virtual std::string translateActiveException() const {
+ try {
+#ifdef __OBJC__
+ // In Objective-C try objective-c exceptions first
+ @try {
+ return tryTranslators();
+ }
+ @catch (NSException *exception) {
+ return Catch::toString( [exception description] );
+ }
+#else
+ return tryTranslators();
+#endif
+ }
+ catch( TestFailureException& ) {
+ throw;
+ }
+ catch( std::exception& ex ) {
+ return ex.what();
+ }
+ catch( std::string& msg ) {
+ return msg;
+ }
+ catch( const char* msg ) {
+ return msg;
+ }
+ catch(...) {
+ return "Unknown exception";
+ }
+ }
+
+ std::string tryTranslators() const {
+ if( m_translators.empty() )
+ throw;
+ else
+ return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+ }
+
+ private:
+ std::vector<const IExceptionTranslator*> m_translators;
+ };
+}
+
+namespace Catch {
+
+ namespace {
+
+ class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
+
+ RegistryHub( RegistryHub const& );
+ void operator=( RegistryHub const& );
+
+ public: // IRegistryHub
+ RegistryHub() {
+ }
+ virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
+ return m_reporterRegistry;
+ }
+ virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
+ return m_testCaseRegistry;
+ }
+ virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
+ return m_exceptionTranslatorRegistry;
+ }
+
+ public: // IMutableRegistryHub
+ virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+ m_reporterRegistry.registerReporter( name, factory );
+ }
+ virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+ m_reporterRegistry.registerListener( factory );
+ }
+ virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
+ m_testCaseRegistry.registerTest( testInfo );
+ }
+ virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
+ m_exceptionTranslatorRegistry.registerTranslator( translator );
+ }
+
+ private:
+ TestRegistry m_testCaseRegistry;
+ ReporterRegistry m_reporterRegistry;
+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+ };
+
+ // Single, global, instance
+ inline RegistryHub*& getTheRegistryHub() {
+ static RegistryHub* theRegistryHub = CATCH_NULL;
+ if( !theRegistryHub )
+ theRegistryHub = new RegistryHub();
+ return theRegistryHub;
+ }
+ }
+
+ IRegistryHub& getRegistryHub() {
+ return *getTheRegistryHub();
+ }
+ IMutableRegistryHub& getMutableRegistryHub() {
+ return *getTheRegistryHub();
+ }
+ void cleanUp() {
+ delete getTheRegistryHub();
+ getTheRegistryHub() = CATCH_NULL;
+ cleanUpContext();
+ }
+ std::string translateActiveException() {
+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+ }
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <sstream>
+
+namespace Catch {
+
+ NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
+ : m_lineInfo( lineInfo ) {
+ std::ostringstream oss;
+ oss << lineInfo << ": function ";
+ oss << "not implemented";
+ m_what = oss.str();
+ }
+
+ const char* NotImplementedException::what() const CATCH_NOEXCEPT {
+ return m_what.c_str();
+ }
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <stdexcept>
+#include <cstdio>
+#include <iostream>
+
+namespace Catch {
+
+ template<typename WriterF, size_t bufferSize=256>
+ class StreamBufImpl : public StreamBufBase {
+ char data[bufferSize];
+ WriterF m_writer;
+
+ public:
+ StreamBufImpl() {
+ setp( data, data + sizeof(data) );
+ }
+
+ ~StreamBufImpl() CATCH_NOEXCEPT {
+ sync();
+ }
+
+ private:
+ int overflow( int c ) {
+ sync();
+
+ if( c != EOF ) {
+ if( pbase() == epptr() )
+ m_writer( std::string( 1, static_cast<char>( c ) ) );
+ else
+ sputc( static_cast<char>( c ) );
+ }
+ return 0;
+ }
+
+ int sync() {
+ if( pbase() != pptr() ) {
+ m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+ setp( pbase(), epptr() );
+ }
+ return 0;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ FileStream::FileStream( std::string const& filename ) {
+ m_ofs.open( filename.c_str() );
+ if( m_ofs.fail() ) {
+ std::ostringstream oss;
+ oss << "Unable to open file: '" << filename << '\'';
+ throw std::domain_error( oss.str() );
+ }
+ }
+
+ std::ostream& FileStream::stream() const {
+ return m_ofs;
+ }
+
+ struct OutputDebugWriter {
+
+ void operator()( std::string const&str ) {
+ writeToDebugConsole( str );
+ }
+ };
+
+ DebugOutStream::DebugOutStream()
+ : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+ m_os( m_streamBuf.get() )
+ {}
+
+ std::ostream& DebugOutStream::stream() const {
+ return m_os;
+ }
+
+ // Store the streambuf from cout up-front because
+ // cout may get redirected when running tests
+ CoutStream::CoutStream()
+ : m_os( Catch::cout().rdbuf() )
+ {}
+
+ std::ostream& CoutStream::stream() const {
+ return m_os;
+ }
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+ std::ostream& cout() {
+ return std::cout;
+ }
+ std::ostream& cerr() {
+ return std::cerr;
+ }
+#endif
+}
+
+namespace Catch {
+
+ class Context : public IMutableContext {
+
+ Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
+ Context( Context const& );
+ void operator=( Context const& );
+
+ public:
+ virtual ~Context() {
+ deleteAllValues( m_generatorsByTestName );
+ }
+
+ public: // IContext
+ virtual IResultCapture* getResultCapture() {
+ return m_resultCapture;
+ }
+ virtual IRunner* getRunner() {
+ return m_runner;
+ }
+ virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
+ return getGeneratorsForCurrentTest()
+ .getGeneratorInfo( fileInfo, totalSize )
+ .getCurrentIndex();
+ }
+ virtual bool advanceGeneratorsForCurrentTest() {
+ IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+ return generators && generators->moveNext();
+ }
+
+ virtual Ptr<IConfig const> getConfig() const {
+ return m_config;
+ }
+
+ public: // IMutableContext
+ virtual void setResultCapture( IResultCapture* resultCapture ) {
+ m_resultCapture = resultCapture;
+ }
+ virtual void setRunner( IRunner* runner ) {
+ m_runner = runner;
+ }
+ virtual void setConfig( Ptr<IConfig const> const& config ) {
+ m_config = config;
+ }
+
+ friend IMutableContext& getCurrentMutableContext();
+
+ private:
+ IGeneratorsForTest* findGeneratorsForCurrentTest() {
+ std::string testName = getResultCapture()->getCurrentTestName();
+
+ std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+ m_generatorsByTestName.find( testName );
+ return it != m_generatorsByTestName.end()
+ ? it->second
+ : CATCH_NULL;
+ }
+
+ IGeneratorsForTest& getGeneratorsForCurrentTest() {
+ IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+ if( !generators ) {
+ std::string testName = getResultCapture()->getCurrentTestName();
+ generators = createGeneratorsForTest();
+ m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
+ }
+ return *generators;
+ }
+
+ private:
+ Ptr<IConfig const> m_config;
+ IRunner* m_runner;
+ IResultCapture* m_resultCapture;
+ std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+ };
+
+ namespace {
+ Context* currentContext = CATCH_NULL;
+ }
+ IMutableContext& getCurrentMutableContext() {
+ if( !currentContext )
+ currentContext = new Context();
+ return *currentContext;
+ }
+ IContext& getCurrentContext() {
+ return getCurrentMutableContext();
+ }
+
+ void cleanUpContext() {
+ delete currentContext;
+ currentContext = CATCH_NULL;
+ }
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+namespace Catch {
+ namespace {
+
+ struct IColourImpl {
+ virtual ~IColourImpl() {}
+ virtual void use( Colour::Code _colourCode ) = 0;
+ };
+
+ struct NoColourImpl : IColourImpl {
+ void use( Colour::Code ) {}
+
+ static IColourImpl* instance() {
+ static NoColourImpl s_instance;
+ return &s_instance;
+ }
+ };
+
+ } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+# ifdef CATCH_PLATFORM_WINDOWS
+# define CATCH_CONFIG_COLOUR_WINDOWS
+# else
+# define CATCH_CONFIG_COLOUR_ANSI
+# endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+ class Win32ColourImpl : public IColourImpl {
+ public:
+ Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+ {
+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+ GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+ originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+ originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+ }
+
+ virtual void use( Colour::Code _colourCode ) {
+ switch( _colourCode ) {
+ case Colour::None: return setTextAttribute( originalForegroundAttributes );
+ case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+ case Colour::Red: return setTextAttribute( FOREGROUND_RED );
+ case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
+ case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
+ case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+ case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+ case Colour::Grey: return setTextAttribute( 0 );
+
+ case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
+ case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+ case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+ case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+
+ case Colour::Bright: throw std::logic_error( "not a colour" );
+ }
+ }
+
+ private:
+ void setTextAttribute( WORD _textAttribute ) {
+ SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
+ }
+ HANDLE stdoutHandle;
+ WORD originalForegroundAttributes;
+ WORD originalBackgroundAttributes;
+ };
+
+ IColourImpl* platformColourInstance() {
+ static Win32ColourImpl s_instance;
+
+ Ptr<IConfig const> config = getCurrentContext().getConfig();
+ UseColour::YesOrNo colourMode = config
+ ? config->useColour()
+ : UseColour::Auto;
+ if( colourMode == UseColour::Auto )
+ colourMode = !isDebuggerActive()
+ ? UseColour::Yes
+ : UseColour::No;
+ return colourMode == UseColour::Yes
+ ? &s_instance
+ : NoColourImpl::instance();
+ }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+ // use POSIX/ ANSI console terminal codes
+ // Thanks to Adam Strzelecki for original contribution
+ // (http://github.com/nanoant)
+ // https://github.com/philsquared/Catch/pull/131
+ class PosixColourImpl : public IColourImpl {
+ public:
+ virtual void use( Colour::Code _colourCode ) {
+ switch( _colourCode ) {
+ case Colour::None:
+ case Colour::White: return setColour( "[0m" );
+ case Colour::Red: return setColour( "[0;31m" );
+ case Colour::Green: return setColour( "[0;32m" );
+ case Colour::Blue: return setColour( "[0;34m" );
+ case Colour::Cyan: return setColour( "[0;36m" );
+ case Colour::Yellow: return setColour( "[0;33m" );
+ case Colour::Grey: return setColour( "[1;30m" );
+
+ case Colour::LightGrey: return setColour( "[0;37m" );
+ case Colour::BrightRed: return setColour( "[1;31m" );
+ case Colour::BrightGreen: return setColour( "[1;32m" );
+ case Colour::BrightWhite: return setColour( "[1;37m" );
+
+ case Colour::Bright: throw std::logic_error( "not a colour" );
+ }
+ }
+ static IColourImpl* instance() {
+ static PosixColourImpl s_instance;
+ return &s_instance;
+ }
+
+ private:
+ void setColour( const char* _escapeCode ) {
+ Catch::cout() << '\033' << _escapeCode;
+ }
+ };
+
+ IColourImpl* platformColourInstance() {
+ Ptr<IConfig const> config = getCurrentContext().getConfig();
+ UseColour::YesOrNo colourMode = config
+ ? config->useColour()
+ : UseColour::Auto;
+ if( colourMode == UseColour::Auto )
+ colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
+ ? UseColour::Yes
+ : UseColour::No;
+ return colourMode == UseColour::Yes
+ ? PosixColourImpl::instance()
+ : NoColourImpl::instance();
+ }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+ static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+ Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
+ Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
+ Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+ void Colour::use( Code _colourCode ) {
+ static IColourImpl* impl = platformColourInstance();
+ impl->use( _colourCode );
+ }
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Catch {
+
+ struct GeneratorInfo : IGeneratorInfo {
+
+ GeneratorInfo( std::size_t size )
+ : m_size( size ),
+ m_currentIndex( 0 )
+ {}
+
+ bool moveNext() {
+ if( ++m_currentIndex == m_size ) {
+ m_currentIndex = 0;
+ return false;
+ }
+ return true;
+ }
+
+ std::size_t getCurrentIndex() const {
+ return m_currentIndex;
+ }
+
+ std::size_t m_size;
+ std::size_t m_currentIndex;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ class GeneratorsForTest : public IGeneratorsForTest {
+
+ public:
+ ~GeneratorsForTest() {
+ deleteAll( m_generatorsInOrder );
+ }
+
+ IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
+ std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
+ if( it == m_generatorsByName.end() ) {
+ IGeneratorInfo* info = new GeneratorInfo( size );
+ m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
+ m_generatorsInOrder.push_back( info );
+ return *info;
+ }
+ return *it->second;
+ }
+
+ bool moveNext() {
+ std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+ std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+ for(; it != itEnd; ++it ) {
+ if( (*it)->moveNext() )
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+ std::vector<IGeneratorInfo*> m_generatorsInOrder;
+ };
+
+ IGeneratorsForTest* createGeneratorsForTest()
+ {
+ return new GeneratorsForTest();
+ }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+ AssertionInfo::AssertionInfo( std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ std::string const& _capturedExpression,
+ ResultDisposition::Flags _resultDisposition )
+ : macroName( _macroName ),
+ lineInfo( _lineInfo ),
+ capturedExpression( _capturedExpression ),
+ resultDisposition( _resultDisposition )
+ {}
+
+ AssertionResult::AssertionResult() {}
+
+ AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+ : m_info( info ),
+ m_resultData( data )
+ {}
+
+ AssertionResult::~AssertionResult() {}
+
+ // Result was a success
+ bool AssertionResult::succeeded() const {
+ return Catch::isOk( m_resultData.resultType );
+ }
+
+ // Result was a success, or failure is suppressed
+ bool AssertionResult::isOk() const {
+ return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+ }
+
+ ResultWas::OfType AssertionResult::getResultType() const {
+ return m_resultData.resultType;
+ }
+
+ bool AssertionResult::hasExpression() const {
+ return !m_info.capturedExpression.empty();
+ }
+
+ bool AssertionResult::hasMessage() const {
+ return !m_resultData.message.empty();
+ }
+
+ std::string AssertionResult::getExpression() const {
+ if( isFalseTest( m_info.resultDisposition ) )
+ return '!' + m_info.capturedExpression;
+ else
+ return m_info.capturedExpression;
+ }
+ std::string AssertionResult::getExpressionInMacro() const {
+ if( m_info.macroName.empty() )
+ return m_info.capturedExpression;
+ else
+ return m_info.macroName + "( " + m_info.capturedExpression + " )";
+ }
+
+ bool AssertionResult::hasExpandedExpression() const {
+ return hasExpression() && getExpandedExpression() != getExpression();
+ }
+
+ std::string AssertionResult::getExpandedExpression() const {
+ return m_resultData.reconstructExpression();
+ }
+
+ std::string AssertionResult::getMessage() const {
+ return m_resultData.message;
+ }
+ SourceLineInfo AssertionResult::getSourceInfo() const {
+ return m_info.lineInfo;
+ }
+
+ std::string AssertionResult::getTestMacroName() const {
+ return m_info.macroName;
+ }
+
+ void AssertionResult::discardDecomposedExpression() const {
+ m_resultData.decomposedExpression = CATCH_NULL;
+ }
+
+ void AssertionResult::expandDecomposedExpression() const {
+ m_resultData.reconstructExpression();
+ }
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+#include <cctype>
+
+namespace Catch {
+
+ inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+ if( startsWith( tag, '.' ) ||
+ tag == "hide" ||
+ tag == "!hide" )
+ return TestCaseInfo::IsHidden;
+ else if( tag == "!throws" )
+ return TestCaseInfo::Throws;
+ else if( tag == "!shouldfail" )
+ return TestCaseInfo::ShouldFail;
+ else if( tag == "!mayfail" )
+ return TestCaseInfo::MayFail;
+ else if( tag == "!nonportable" )
+ return TestCaseInfo::NonPortable;
+ else
+ return TestCaseInfo::None;
+ }
+ inline bool isReservedTag( std::string const& tag ) {
+ return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
+ }
+ inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+ if( isReservedTag( tag ) ) {
+ {
+ Colour colourGuard( Colour::Red );
+ Catch::cerr()
+ << "Tag name [" << tag << "] not allowed.\n"
+ << "Tag names starting with non alpha-numeric characters are reserved\n";
+ }
+ {
+ Colour colourGuard( Colour::FileName );
+ Catch::cerr() << _lineInfo << std::endl;
+ }
+ exit(1);
+ }
+ }
+
+ TestCase makeTestCase( ITestCase* _testCase,
+ std::string const& _className,
+ std::string const& _name,
+ std::string const& _descOrTags,
+ SourceLineInfo const& _lineInfo )
+ {
+ bool isHidden( startsWith( _name, "./" ) ); // Legacy support
+
+ // Parse out tags
+ std::set<std::string> tags;
+ std::string desc, tag;
+ bool inTag = false;
+ for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
+ char c = _descOrTags[i];
+ if( !inTag ) {
+ if( c == '[' )
+ inTag = true;
+ else
+ desc += c;
+ }
+ else {
+ if( c == ']' ) {
+ TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+ if( prop == TestCaseInfo::IsHidden )
+ isHidden = true;
+ else if( prop == TestCaseInfo::None )
+ enforceNotReservedTag( tag, _lineInfo );
+
+ tags.insert( tag );
+ tag.clear();
+ inTag = false;
+ }
+ else
+ tag += c;
+ }
+ }
+ if( isHidden ) {
+ tags.insert( "hide" );
+ tags.insert( "." );
+ }
+
+ TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
+ return TestCase( _testCase, info );
+ }
+
+ void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
+ {
+ testCaseInfo.tags = tags;
+ testCaseInfo.lcaseTags.clear();
+
+ std::ostringstream oss;
+ for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
+ oss << '[' << *it << ']';
+ std::string lcaseTag = toLower( *it );
+ testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
+ testCaseInfo.lcaseTags.insert( lcaseTag );
+ }
+ testCaseInfo.tagsAsString = oss.str();
+ }
+
+ TestCaseInfo::TestCaseInfo( std::string const& _name,
+ std::string const& _className,
+ std::string const& _description,
+ std::set<std::string> const& _tags,
+ SourceLineInfo const& _lineInfo )
+ : name( _name ),
+ className( _className ),
+ description( _description ),
+ lineInfo( _lineInfo ),
+ properties( None )
+ {
+ setTags( *this, _tags );
+ }
+
+ TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
+ : name( other.name ),
+ className( other.className ),
+ description( other.description ),
+ tags( other.tags ),
+ lcaseTags( other.lcaseTags ),
+ tagsAsString( other.tagsAsString ),
+ lineInfo( other.lineInfo ),
+ properties( other.properties )
+ {}
+
+ bool TestCaseInfo::isHidden() const {
+ return ( properties & IsHidden ) != 0;
+ }
+ bool TestCaseInfo::throws() const {
+ return ( properties & Throws ) != 0;
+ }
+ bool TestCaseInfo::okToFail() const {
+ return ( properties & (ShouldFail | MayFail ) ) != 0;
+ }
+ bool TestCaseInfo::expectedToFail() const {
+ return ( properties & (ShouldFail ) ) != 0;
+ }
+
+ TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+
+ TestCase::TestCase( TestCase const& other )
+ : TestCaseInfo( other ),
+ test( other.test )
+ {}
+
+ TestCase TestCase::withName( std::string const& _newName ) const {
+ TestCase other( *this );
+ other.name = _newName;
+ return other;
+ }
+
+ void TestCase::swap( TestCase& other ) {
+ test.swap( other.test );
+ name.swap( other.name );
+ className.swap( other.className );
+ description.swap( other.description );
+ tags.swap( other.tags );
+ lcaseTags.swap( other.lcaseTags );
+ tagsAsString.swap( other.tagsAsString );
+ std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
+ std::swap( lineInfo, other.lineInfo );
+ }
+
+ void TestCase::invoke() const {
+ test->invoke();
+ }
+
+ bool TestCase::operator == ( TestCase const& other ) const {
+ return test.get() == other.test.get() &&
+ name == other.name &&
+ className == other.className;
+ }
+
+ bool TestCase::operator < ( TestCase const& other ) const {
+ return name < other.name;
+ }
+ TestCase& TestCase::operator = ( TestCase const& other ) {
+ TestCase temp( other );
+ swap( temp );
+ return *this;
+ }
+
+ TestCaseInfo const& TestCase::getTestCaseInfo() const
+ {
+ return *this;
+ }
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+ Version::Version
+ ( unsigned int _majorVersion,
+ unsigned int _minorVersion,
+ unsigned int _patchNumber,
+ std::string const& _branchName,
+ unsigned int _buildNumber )
+ : majorVersion( _majorVersion ),
+ minorVersion( _minorVersion ),
+ patchNumber( _patchNumber ),
+ branchName( _branchName ),
+ buildNumber( _buildNumber )
+ {}
+
+ std::ostream& operator << ( std::ostream& os, Version const& version ) {
+ os << version.majorVersion << '.'
+ << version.minorVersion << '.'
+ << version.patchNumber;
+
+ if( !version.branchName.empty() ) {
+ os << '-' << version.branchName
+ << '.' << version.buildNumber;
+ }
+ return os;
+ }
+
+ Version libraryVersion( 1, 8, 1, "", 0 );
+
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+ MessageInfo::MessageInfo( std::string const& _macroName,
+ SourceLineInfo const& _lineInfo,
+ ResultWas::OfType _type )
+ : macroName( _macroName ),
+ lineInfo( _lineInfo ),
+ type( _type ),
+ sequence( ++globalCount )
+ {}
+
+ // This may need protecting if threading support is added
+ unsigned int MessageInfo::globalCount = 0;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+ : m_info( builder.m_info )
+ {
+ m_info.message = builder.m_stream.str();
+ getResultCapture().pushScopedMessage( m_info );
+ }
+ ScopedMessage::ScopedMessage( ScopedMessage const& other )
+ : m_info( other.m_info )
+ {}
+
+ ScopedMessage::~ScopedMessage() {
+ getResultCapture().popScopedMessage( m_info );
+ }
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch
+{
+ // Deprecated
+ struct IReporter : IShared {
+ virtual ~IReporter();
+
+ virtual bool shouldRedirectStdout() const = 0;
+
+ virtual void StartTesting() = 0;
+ virtual void EndTesting( Totals const& totals ) = 0;
+ virtual void StartGroup( std::string const& groupName ) = 0;
+ virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+ virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+ virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+ virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+ virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+ virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+ virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+ virtual void Aborted() = 0;
+ virtual void Result( AssertionResult const& result ) = 0;
+ };
+
+ class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+ {
+ public:
+ LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
+ virtual ~LegacyReporterAdapter();
+
+ virtual ReporterPreferences getPreferences() const;
+ virtual void noMatchingTestCases( std::string const& );
+ virtual void testRunStarting( TestRunInfo const& );
+ virtual void testGroupStarting( GroupInfo const& groupInfo );
+ virtual void testCaseStarting( TestCaseInfo const& testInfo );
+ virtual void sectionStarting( SectionInfo const& sectionInfo );
+ virtual void assertionStarting( AssertionInfo const& );
+ virtual bool assertionEnded( AssertionStats const& assertionStats );
+ virtual void sectionEnded( SectionStats const& sectionStats );
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats );
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats );
+ virtual void testRunEnded( TestRunStats const& testRunStats );
+ virtual void skipTest( TestCaseInfo const& );
+
+ private:
+ Ptr<IReporter> m_legacyReporter;
+ };
+}
+
+namespace Catch
+{
+ LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
+ : m_legacyReporter( legacyReporter )
+ {}
+ LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+ ReporterPreferences LegacyReporterAdapter::getPreferences() const {
+ ReporterPreferences prefs;
+ prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+ return prefs;
+ }
+
+ void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
+ void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
+ m_legacyReporter->StartTesting();
+ }
+ void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
+ m_legacyReporter->StartGroup( groupInfo.name );
+ }
+ void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
+ m_legacyReporter->StartTestCase( testInfo );
+ }
+ void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
+ m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
+ }
+ void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
+ // Not on legacy interface
+ }
+
+ bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
+ if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+ for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+ it != itEnd;
+ ++it ) {
+ if( it->type == ResultWas::Info ) {
+ ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
+ rb << it->message;
+ rb.setResultType( ResultWas::Info );
+ AssertionResult result = rb.build();
+ m_legacyReporter->Result( result );
+ }
+ }
+ }
+ m_legacyReporter->Result( assertionStats.assertionResult );
+ return true;
+ }
+ void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
+ if( sectionStats.missingAssertions )
+ m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
+ m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
+ }
+ void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+ m_legacyReporter->EndTestCase
+ ( testCaseStats.testInfo,
+ testCaseStats.totals,
+ testCaseStats.stdOut,
+ testCaseStats.stdErr );
+ }
+ void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+ if( testGroupStats.aborting )
+ m_legacyReporter->Aborted();
+ m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
+ }
+ void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
+ m_legacyReporter->EndTesting( testRunStats.totals );
+ }
+ void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
+ }
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+#else
+
+#include <sys/time.h>
+
+#endif
+
+namespace Catch {
+
+ namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+ uint64_t getCurrentTicks() {
+ static uint64_t hz=0, hzo=0;
+ if (!hz) {
+ QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
+ QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
+ }
+ uint64_t t;
+ QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
+ return ((t-hzo)*1000000)/hz;
+ }
+#else
+ uint64_t getCurrentTicks() {
+ timeval t;
+ gettimeofday(&t,CATCH_NULL);
+ return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
+ }
+#endif
+ }
+
+ void Timer::start() {
+ m_ticks = getCurrentTicks();
+ }
+ unsigned int Timer::getElapsedMicroseconds() const {
+ return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+ }
+ unsigned int Timer::getElapsedMilliseconds() const {
+ return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+ }
+ double Timer::getElapsedSeconds() const {
+ return getElapsedMicroseconds()/1000000.0;
+ }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+#include <cstring>
+#include <cctype>
+
+namespace Catch {
+
+ bool startsWith( std::string const& s, std::string const& prefix ) {
+ return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+ }
+ bool startsWith( std::string const& s, char prefix ) {
+ return !s.empty() && s[0] == prefix;
+ }
+ bool endsWith( std::string const& s, std::string const& suffix ) {
+ return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+ }
+ bool endsWith( std::string const& s, char suffix ) {
+ return !s.empty() && s[s.size()-1] == suffix;
+ }
+ bool contains( std::string const& s, std::string const& infix ) {
+ return s.find( infix ) != std::string::npos;
+ }
+ char toLowerCh(char c) {
+ return static_cast<char>( std::tolower( c ) );
+ }
+ void toLowerInPlace( std::string& s ) {
+ std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
+ }
+ std::string toLower( std::string const& s ) {
+ std::string lc = s;
+ toLowerInPlace( lc );
+ return lc;
+ }
+ std::string trim( std::string const& str ) {
+ static char const* whitespaceChars = "\n\r\t ";
+ std::string::size_type start = str.find_first_not_of( whitespaceChars );
+ std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+ return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+ }
+
+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+ bool replaced = false;
+ std::size_t i = str.find( replaceThis );
+ while( i != std::string::npos ) {
+ replaced = true;
+ str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+ if( i < str.size()-withThis.size() )
+ i = str.find( replaceThis, i+withThis.size() );
+ else
+ i = std::string::npos;
+ }
+ return replaced;
+ }
+
+ pluralise::pluralise( std::size_t count, std::string const& label )
+ : m_count( count ),
+ m_label( label )
+ {}
+
+ std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+ os << pluraliser.m_count << ' ' << pluraliser.m_label;
+ if( pluraliser.m_count != 1 )
+ os << 's';
+ return os;
+ }
+
+ SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
+ SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
+ : file( _file ),
+ line( _line )
+ {}
+ bool SourceLineInfo::empty() const {
+ return file[0] == '\0';
+ }
+ bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+ return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+ }
+ bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
+ return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
+ }
+
+ void seedRng( IConfig const& config ) {
+ if( config.rngSeed() != 0 )
+ std::srand( config.rngSeed() );
+ }
+ unsigned int rngSeed() {
+ return getCurrentContext().getConfig()->rngSeed();
+ }
+
+ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+ os << info.file << '(' << info.line << ')';
+#else
+ os << info.file << ':' << info.line;
+#endif
+ return os;
+ }
+
+ void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+ std::ostringstream oss;
+ oss << locationInfo << ": Internal Catch error: '" << message << '\'';
+ if( alwaysTrue() )
+ throw std::logic_error( oss.str() );
+ }
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+ SectionInfo::SectionInfo
+ ( SourceLineInfo const& _lineInfo,
+ std::string const& _name,
+ std::string const& _description )
+ : name( _name ),
+ description( _description ),
+ lineInfo( _lineInfo )
+ {}
+
+ Section::Section( SectionInfo const& info )
+ : m_info( info ),
+ m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+ {
+ m_timer.start();
+ }
+
+ Section::~Section() {
+ if( m_sectionIncluded ) {
+ SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
+ if( std::uncaught_exception() )
+ getResultCapture().sectionEndedEarly( endInfo );
+ else
+ getResultCapture().sectionEnded( endInfo );
+ }
+ }
+
+ // This indicates whether the section should be executed or not
+ Section::operator bool() const {
+ return m_sectionIncluded;
+ }
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#ifdef CATCH_PLATFORM_MAC
+
+ #include <assert.h>
+ #include <stdbool.h>
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <sys/sysctl.h>
+
+ namespace Catch{
+
+ // The following function is taken directly from the following technical note:
+ // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+ // Returns true if the current process is being debugged (either
+ // running under the debugger or has a debugger attached post facto).
+ bool isDebuggerActive(){
+
+ int mib[4];
+ struct kinfo_proc info;
+ size_t size;
+
+ // Initialize the flags so that, if sysctl fails for some bizarre
+ // reason, we get a predictable result.
+
+ info.kp_proc.p_flag = 0;
+
+ // Initialize mib, which tells sysctl the info we want, in this case
+ // we're looking for information about a specific process ID.
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+
+ // Call sysctl.
+
+ size = sizeof(info);
+ if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+ return false;
+ }
+
+ // We're being debugged if the P_TRACED flag is set.
+
+ return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+ }
+ } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+ #include <fstream>
+ #include <string>
+
+ namespace Catch{
+ // The standard POSIX way of detecting a debugger is to attempt to
+ // ptrace() the process, but this needs to be done from a child and not
+ // this process itself to still allow attaching to this process later
+ // if wanted, so is rather heavy. Under Linux we have the PID of the
+ // "debugger" (which doesn't need to be gdb, of course, it could also
+ // be strace, for example) in /proc/$PID/status, so just get it from
+ // there instead.
+ bool isDebuggerActive(){
+ std::ifstream in("/proc/self/status");
+ for( std::string line; std::getline(in, line); ) {
+ static const int PREFIX_LEN = 11;
+ if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+ // We're traced if the PID is not 0 and no other PID starts
+ // with 0 digit, so it's enough to check for just a single
+ // character.
+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+ }
+ }
+
+ return false;
+ }
+ } // namespace Catch
+#elif defined(_MSC_VER)
+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+ namespace Catch {
+ bool isDebuggerActive() {
+ return IsDebuggerPresent() != 0;
+ }
+ }
+#elif defined(__MINGW32__)
+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+ namespace Catch {
+ bool isDebuggerActive() {
+ return IsDebuggerPresent() != 0;
+ }
+ }
+#else
+ namespace Catch {
+ inline bool isDebuggerActive() { return false; }
+ }
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ ::OutputDebugStringA( text.c_str() );
+ }
+ }
+#else
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ // !TBD: Need a version for Mac/ XCode and other IDEs
+ Catch::cout() << text;
+ }
+ }
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+ const std::string unprintableString = "{?}";
+
+ namespace {
+ const int hexThreshold = 255;
+
+ struct Endianness {
+ enum Arch { Big, Little };
+
+ static Arch which() {
+ union _{
+ int asInt;
+ char asChar[sizeof (int)];
+ } u;
+
+ u.asInt = 1;
+ return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+ }
+ };
+ }
+
+ std::string rawMemoryToString( const void *object, std::size_t size )
+ {
+ // Reverse order for little endian architectures
+ int i = 0, end = static_cast<int>( size ), inc = 1;
+ if( Endianness::which() == Endianness::Little ) {
+ i = end-1;
+ end = inc = -1;
+ }
+
+ unsigned char const *bytes = static_cast<unsigned char const *>(object);
+ std::ostringstream os;
+ os << "0x" << std::setfill('0') << std::hex;
+ for( ; i != end; i += inc )
+ os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+ return os.str();
+ }
+}
+
+std::string toString( std::string const& value ) {
+ std::string s = value;
+ if( getCurrentContext().getConfig()->showInvisibles() ) {
+ for(size_t i = 0; i < s.size(); ++i ) {
+ std::string subs;
+ switch( s[i] ) {
+ case '\n': subs = "\\n"; break;
+ case '\t': subs = "\\t"; break;
+ default: break;
+ }
+ if( !subs.empty() ) {
+ s = s.substr( 0, i ) + subs + s.substr( i+1 );
+ ++i;
+ }
+ }
+ }
+ return '"' + s + '"';
+}
+std::string toString( std::wstring const& value ) {
+
+ std::string s;
+ s.reserve( value.size() );
+ for(size_t i = 0; i < value.size(); ++i )
+ s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
+ return Catch::toString( s );
+}
+
+std::string toString( const char* const value ) {
+ return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
+}
+
+std::string toString( char* const value ) {
+ return Catch::toString( static_cast<const char*>( value ) );
+}
+
+std::string toString( const wchar_t* const value )
+{
+ return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+}
+
+std::string toString( wchar_t* const value )
+{
+ return Catch::toString( static_cast<const wchar_t*>( value ) );
+}
+
+std::string toString( int value ) {
+ std::ostringstream oss;
+ oss << value;
+ if( value > Detail::hexThreshold )
+ oss << " (0x" << std::hex << value << ')';
+ return oss.str();
+}
+
+std::string toString( unsigned long value ) {
+ std::ostringstream oss;
+ oss << value;
+ if( value > Detail::hexThreshold )
+ oss << " (0x" << std::hex << value << ')';
+ return oss.str();
+}
+
+std::string toString( unsigned int value ) {
+ return Catch::toString( static_cast<unsigned long>( value ) );
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+ std::ostringstream oss;
+ oss << std::setprecision( precision )
+ << std::fixed
+ << value;
+ std::string d = oss.str();
+ std::size_t i = d.find_last_not_of( '0' );
+ if( i != std::string::npos && i != d.size()-1 ) {
+ if( d[i] == '.' )
+ i++;
+ d = d.substr( 0, i+1 );
+ }
+ return d;
+}
+
+std::string toString( const double value ) {
+ return fpToString( value, 10 );
+}
+std::string toString( const float value ) {
+ return fpToString( value, 5 ) + 'f';
+}
+
+std::string toString( bool value ) {
+ return value ? "true" : "false";
+}
+
+std::string toString( char value ) {
+ if ( value == '\r' )
+ return "'\\r'";
+ if ( value == '\f' )
+ return "'\\f'";
+ if ( value == '\n' )
+ return "'\\n'";
+ if ( value == '\t' )
+ return "'\\t'";
+ if ( '\0' <= value && value < ' ' )
+ return toString( static_cast<unsigned int>( value ) );
+ char chstr[] = "' '";
+ chstr[1] = value;
+ return chstr;
+}
+
+std::string toString( signed char value ) {
+ return toString( static_cast<char>( value ) );
+}
+
+std::string toString( unsigned char value ) {
+ return toString( static_cast<char>( value ) );
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value ) {
+ std::ostringstream oss;
+ oss << value;
+ if( value > Detail::hexThreshold )
+ oss << " (0x" << std::hex << value << ')';
+ return oss.str();
+}
+std::string toString( unsigned long long value ) {
+ std::ostringstream oss;
+ oss << value;
+ if( value > Detail::hexThreshold )
+ oss << " (0x" << std::hex << value << ')';
+ return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t ) {
+ return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+ std::string toString( NSString const * const& nsstring ) {
+ if( !nsstring )
+ return "nil";
+ return "@" + toString([nsstring UTF8String]);
+ }
+ std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
+ if( !nsstring )
+ return "nil";
+ return "@" + toString([nsstring UTF8String]);
+ }
+ std::string toString( NSObject* const& nsObject ) {
+ return toString( [nsObject description] );
+ }
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+ std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
+ return secondArg.empty() || secondArg == "\"\""
+ ? capturedExpression
+ : capturedExpression + ", " + secondArg;
+ }
+ ResultBuilder::ResultBuilder( char const* macroName,
+ SourceLineInfo const& lineInfo,
+ char const* capturedExpression,
+ ResultDisposition::Flags resultDisposition,
+ char const* secondArg )
+ : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
+ m_shouldDebugBreak( false ),
+ m_shouldThrow( false )
+ {}
+
+ ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
+ m_data.resultType = result;
+ return *this;
+ }
+ ResultBuilder& ResultBuilder::setResultType( bool result ) {
+ m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+ return *this;
+ }
+
+ void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
+ AssertionResult result = build( expr );
+ handleResult( result );
+ }
+
+ void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
+ m_assertionInfo.resultDisposition = resultDisposition;
+ m_stream.oss << Catch::translateActiveException();
+ captureResult( ResultWas::ThrewException );
+ }
+
+ void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
+ setResultType( resultType );
+ captureExpression();
+ }
+
+ void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
+ if( expectedMessage.empty() )
+ captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
+ else
+ captureExpectedException( Matchers::Equals( expectedMessage ) );
+ }
+
+ void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
+
+ assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
+ AssertionResultData data = m_data;
+ data.resultType = ResultWas::Ok;
+ data.reconstructedExpression = m_assertionInfo.capturedExpression;
+
+ std::string actualMessage = Catch::translateActiveException();
+ if( !matcher.match( actualMessage ) ) {
+ data.resultType = ResultWas::ExpressionFailed;
+ data.reconstructedExpression = actualMessage;
+ }
+ AssertionResult result( m_assertionInfo, data );
+ handleResult( result );
+ }
+
+ void ResultBuilder::captureExpression() {
+ AssertionResult result = build();
+ handleResult( result );
+ }
+
+ void ResultBuilder::handleResult( AssertionResult const& result )
+ {
+ getResultCapture().assertionEnded( result );
+
+ if( !result.isOk() ) {
+ if( getCurrentContext().getConfig()->shouldDebugBreak() )
+ m_shouldDebugBreak = true;
+ if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
+ m_shouldThrow = true;
+ }
+ }
+
+ void ResultBuilder::react() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+ if (m_shouldDebugBreak) {
+ ///////////////////////////////////////////////////////////////////
+ // To inspect the state during test, you need to go one level up the callstack
+ // To go back to the test and change execution, jump over the throw statement
+ ///////////////////////////////////////////////////////////////////
+ CATCH_BREAK_INTO_DEBUGGER();
+ }
+#endif
+ if( m_shouldThrow )
+ throw Catch::TestFailureException();
+ }
+
+ bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+ bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+ AssertionResult ResultBuilder::build() const
+ {
+ return build( *this );
+ }
+
+ // CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
+ // a temporary DecomposedExpression, which in turn holds references to
+ // operands, possibly temporary as well.
+ // It should immediately be passed to handleResult; if the expression
+ // needs to be reported, its string expansion must be composed before
+ // the temporaries are destroyed.
+ AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
+ {
+ assert( m_data.resultType != ResultWas::Unknown );
+ AssertionResultData data = m_data;
+
+ // Flip bool results if FalseTest flag is set
+ if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+ data.negate( expr.isBinaryExpression() );
+ }
+
+ data.message = m_stream.oss.str();
+ data.decomposedExpression = &expr; // for lazy reconstruction
+ return AssertionResult( m_assertionInfo, data );
+ }
+
+ void ResultBuilder::reconstructExpression( std::string& dest ) const {
+ dest = m_assertionInfo.capturedExpression;
+ }
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+ class TagAliasRegistry : public ITagAliasRegistry {
+ public:
+ virtual ~TagAliasRegistry();
+ virtual Option<TagAlias> find( std::string const& alias ) const;
+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+ void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+ static TagAliasRegistry& get();
+
+ private:
+ std::map<std::string, TagAlias> m_registry;
+ };
+
+} // end namespace Catch
+
+namespace Catch {
+
+ TagAliasRegistry::~TagAliasRegistry() {}
+
+ Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
+ std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
+ if( it != m_registry.end() )
+ return it->second;
+ else
+ return Option<TagAlias>();
+ }
+
+ std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+ std::string expandedTestSpec = unexpandedTestSpec;
+ for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+ it != itEnd;
+ ++it ) {
+ std::size_t pos = expandedTestSpec.find( it->first );
+ if( pos != std::string::npos ) {
+ expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
+ it->second.tag +
+ expandedTestSpec.substr( pos + it->first.size() );
+ }
+ }
+ return expandedTestSpec;
+ }
+
+ void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+
+ if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
+ std::ostringstream oss;
+ oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
+ throw std::domain_error( oss.str().c_str() );
+ }
+ if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
+ std::ostringstream oss;
+ oss << "error: tag alias, \"" << alias << "\" already registered.\n"
+ << "\tFirst seen at " << find(alias)->lineInfo << '\n'
+ << "\tRedefined at " << lineInfo;
+ throw std::domain_error( oss.str().c_str() );
+ }
+ }
+
+ TagAliasRegistry& TagAliasRegistry::get() {
+ static TagAliasRegistry instance;
+ return instance;
+
+ }
+
+ ITagAliasRegistry::~ITagAliasRegistry() {}
+ ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
+
+ RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+ try {
+ TagAliasRegistry::get().add( alias, tag, lineInfo );
+ }
+ catch( std::exception& ex ) {
+ Colour colourGuard( Colour::Red );
+ Catch::cerr() << ex.what() << std::endl;
+ exit(1);
+ }
+ }
+
+} // end namespace Catch
+
+// #included from: catch_matchers_string.hpp
+
+namespace Catch {
+namespace Matchers {
+
+ namespace StdString {
+
+ CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
+ : m_caseSensitivity( caseSensitivity ),
+ m_str( adjustString( str ) )
+ {}
+ std::string CasedString::adjustString( std::string const& str ) const {
+ return m_caseSensitivity == CaseSensitive::No
+ ? toLower( str )
+ : str;
+ }
+ std::string CasedString::caseSensitivitySuffix() const {
+ return m_caseSensitivity == CaseSensitive::No
+ ? " (case insensitive)"
+ : std::string();
+ }
+
+ StringMatcherBase::StringMatcherBase( std::string operation, CasedString const& comparator )
+ : m_comparator( comparator ),
+ m_operation( operation ) {
+ }
+
+ std::string StringMatcherBase::describe() const {
+ std::string description;
+ description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+ m_comparator.caseSensitivitySuffix().size());
+ description += m_operation;
+ description += ": \"";
+ description += m_comparator.m_str;
+ description += "\"";
+ description += m_comparator.caseSensitivitySuffix();
+ return description;
+ }
+
+ EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
+
+ bool EqualsMatcher::match( std::string const& source ) const {
+ return m_comparator.adjustString( source ) == m_comparator.m_str;
+ }
+
+ ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
+
+ bool ContainsMatcher::match( std::string const& source ) const {
+ return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+ StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
+
+ bool StartsWithMatcher::match( std::string const& source ) const {
+ return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+ EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
+
+ bool EndsWithMatcher::match( std::string const& source ) const {
+ return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+ }
+
+ } // namespace StdString
+
+ StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+ StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+ StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+ StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+ return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+ }
+
+} // namespace Matchers
+} // namespace Catch
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter> {
+ typedef std::vector<Ptr<IStreamingReporter> > Reporters;
+ Reporters m_reporters;
+
+public:
+ void add( Ptr<IStreamingReporter> const& reporter ) {
+ m_reporters.push_back( reporter );
+ }
+
+public: // IStreamingReporter
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+ return m_reporters[0]->getPreferences();
+ }
+
+ virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->noMatchingTestCases( spec );
+ }
+
+ virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->testRunStarting( testRunInfo );
+ }
+
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->testGroupStarting( groupInfo );
+ }
+
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->testCaseStarting( testInfo );
+ }
+
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->sectionStarting( sectionInfo );
+ }
+
+ virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->assertionStarting( assertionInfo );
+ }
+
+ // The return value indicates if the messages buffer should be cleared:
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+ bool clearBuffer = false;
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ clearBuffer |= (*it)->assertionEnded( assertionStats );
+ return clearBuffer;
+ }
+
+ virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->sectionEnded( sectionStats );
+ }
+
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->testCaseEnded( testCaseStats );
+ }
+
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->testGroupEnded( testGroupStats );
+ }
+
+ virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->testRunEnded( testRunStats );
+ }
+
+ virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+ for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+ it != itEnd;
+ ++it )
+ (*it)->skipTest( testInfo );
+ }
+
+ virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
+ return this;
+ }
+
+};
+
+Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
+ Ptr<IStreamingReporter> resultingReporter;
+
+ if( existingReporter ) {
+ MultipleReporters* multi = existingReporter->tryAsMulti();
+ if( !multi ) {
+ multi = new MultipleReporters;
+ resultingReporter = Ptr<IStreamingReporter>( multi );
+ if( existingReporter )
+ multi->add( existingReporter );
+ }
+ else
+ resultingReporter = existingReporter;
+ multi->add( additionalReporter );
+ }
+ else
+ resultingReporter = additionalReporter;
+
+ return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+#include <assert.h>
+
+namespace Catch {
+
+ struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+ StreamingReporterBase( ReporterConfig const& _config )
+ : m_config( _config.fullConfig() ),
+ stream( _config.stream() )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ }
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+ return m_reporterPrefs;
+ }
+
+ virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+ virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {}
+
+ virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE {
+ currentTestRunInfo = _testRunInfo;
+ }
+ virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
+ currentGroupInfo = _groupInfo;
+ }
+
+ virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
+ currentTestCaseInfo = _testInfo;
+ }
+ virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+ m_sectionStack.push_back( _sectionInfo );
+ }
+
+ virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
+ m_sectionStack.pop_back();
+ }
+ virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
+ currentTestCaseInfo.reset();
+ }
+ virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
+ currentGroupInfo.reset();
+ }
+ virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
+ currentTestCaseInfo.reset();
+ currentGroupInfo.reset();
+ currentTestRunInfo.reset();
+ }
+
+ virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
+ // Don't do anything with this by default.
+ // It can optionally be overridden in the derived class.
+ }
+
+ Ptr<IConfig const> m_config;
+ std::ostream& stream;
+
+ LazyStat<TestRunInfo> currentTestRunInfo;
+ LazyStat<GroupInfo> currentGroupInfo;
+ LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+ std::vector<SectionInfo> m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+ };
+
+ struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+ template<typename T, typename ChildNodeT>
+ struct Node : SharedImpl<> {
+ explicit Node( T const& _value ) : value( _value ) {}
+ virtual ~Node() {}
+
+ typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+ T value;
+ ChildNodes children;
+ };
+ struct SectionNode : SharedImpl<> {
+ explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+ virtual ~SectionNode();
+
+ bool operator == ( SectionNode const& other ) const {
+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+ }
+ bool operator == ( Ptr<SectionNode> const& other ) const {
+ return operator==( *other );
+ }
+
+ SectionStats stats;
+ typedef std::vector<Ptr<SectionNode> > ChildSections;
+ typedef std::vector<AssertionStats> Assertions;
+ ChildSections childSections;
+ Assertions assertions;
+ std::string stdOut;
+ std::string stdErr;
+ };
+
+ struct BySectionInfo {
+ BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+ BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+ bool operator() ( Ptr<SectionNode> const& node ) const {
+ return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+ }
+ private:
+ void operator=( BySectionInfo const& );
+ SectionInfo const& m_other;
+ };
+
+ typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+ typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+ typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+ CumulativeReporterBase( ReporterConfig const& _config )
+ : m_config( _config.fullConfig() ),
+ stream( _config.stream() )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = false;
+ }
+ ~CumulativeReporterBase();
+
+ virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+ return m_reporterPrefs;
+ }
+
+ virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {}
+ virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {}
+
+ virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+ SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+ Ptr<SectionNode> node;
+ if( m_sectionStack.empty() ) {
+ if( !m_rootSection )
+ m_rootSection = new SectionNode( incompleteStats );
+ node = m_rootSection;
+ }
+ else {
+ SectionNode& parentNode = *m_sectionStack.back();
+ SectionNode::ChildSections::const_iterator it =
+ std::find_if( parentNode.childSections.begin(),
+ parentNode.childSections.end(),
+ BySectionInfo( sectionInfo ) );
+ if( it == parentNode.childSections.end() ) {
+ node = new SectionNode( incompleteStats );
+ parentNode.childSections.push_back( node );
+ }
+ else
+ node = *it;
+ }
+ m_sectionStack.push_back( node );
+ m_deepestSection = node;
+ }
+
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+ assert( !m_sectionStack.empty() );
+ SectionNode& sectionNode = *m_sectionStack.back();
+ sectionNode.assertions.push_back( assertionStats );
+ // AssertionResult holds a pointer to a temporary DecomposedExpression,
+ // which getExpandedExpression() calls to build the expression string.
+ // Our section stack copy of the assertionResult will likely outlive the
+ // temporary, so it must be expanded or discarded now to avoid calling
+ // a destroyed object later.
+ prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
+ return true;
+ }
+ virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+ assert( !m_sectionStack.empty() );
+ SectionNode& node = *m_sectionStack.back();
+ node.stats = sectionStats;
+ m_sectionStack.pop_back();
+ }
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+ Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+ assert( m_sectionStack.size() == 0 );
+ node->children.push_back( m_rootSection );
+ m_testCases.push_back( node );
+ m_rootSection.reset();
+
+ assert( m_deepestSection );
+ m_deepestSection->stdOut = testCaseStats.stdOut;
+ m_deepestSection->stdErr = testCaseStats.stdErr;
+ }
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+ Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+ node->children.swap( m_testCases );
+ m_testGroups.push_back( node );
+ }
+ virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+ Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+ node->children.swap( m_testGroups );
+ m_testRuns.push_back( node );
+ testRunEndedCumulative();
+ }
+ virtual void testRunEndedCumulative() = 0;
+
+ virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+ virtual void prepareExpandedExpression( AssertionResult& result ) const {
+ if( result.isOk() )
+ result.discardDecomposedExpression();
+ else
+ result.expandDecomposedExpression();
+ }
+
+ Ptr<IConfig const> m_config;
+ std::ostream& stream;
+ std::vector<AssertionStats> m_assertions;
+ std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+ std::vector<Ptr<TestCaseNode> > m_testCases;
+ std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+ std::vector<Ptr<TestRunNode> > m_testRuns;
+
+ Ptr<SectionNode> m_rootSection;
+ Ptr<SectionNode> m_deepestSection;
+ std::vector<Ptr<SectionNode> > m_sectionStack;
+ ReporterPreferences m_reporterPrefs;
+
+ };
+
+ template<char C>
+ char const* getLineOfChars() {
+ static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+ if( !*line ) {
+ std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+ line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+ }
+ return line;
+ }
+
+ struct TestEventListenerBase : StreamingReporterBase {
+ TestEventListenerBase( ReporterConfig const& _config )
+ : StreamingReporterBase( _config )
+ {}
+
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+ virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE {
+ return false;
+ }
+ };
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+ template<typename T>
+ class LegacyReporterRegistrar {
+
+ class ReporterFactory : public IReporterFactory {
+ virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+ return new LegacyReporterAdapter( new T( config ) );
+ }
+
+ virtual std::string getDescription() const {
+ return T::getDescription();
+ }
+ };
+
+ public:
+
+ LegacyReporterRegistrar( std::string const& name ) {
+ getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+ }
+ };
+
+ template<typename T>
+ class ReporterRegistrar {
+
+ class ReporterFactory : public SharedImpl<IReporterFactory> {
+
+ // *** Please Note ***:
+ // - If you end up here looking at a compiler error because it's trying to register
+ // your custom reporter class be aware that the native reporter interface has changed
+ // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+ // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+ // However please consider updating to the new interface as the old one is now
+ // deprecated and will probably be removed quite soon!
+ // Please contact me via github if you have any questions at all about this.
+ // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+ // no idea who is actually using custom reporters at all (possibly no-one!).
+ // The new interface is designed to minimise exposure to interface changes in the future.
+ virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+ return new T( config );
+ }
+
+ virtual std::string getDescription() const {
+ return T::getDescription();
+ }
+ };
+
+ public:
+
+ ReporterRegistrar( std::string const& name ) {
+ getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+ }
+ };
+
+ template<typename T>
+ class ListenerRegistrar {
+
+ class ListenerFactory : public SharedImpl<IReporterFactory> {
+
+ virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+ return new T( config );
+ }
+ virtual std::string getDescription() const {
+ return std::string();
+ }
+ };
+
+ public:
+
+ ListenerRegistrar() {
+ getMutableRegistryHub().registerListener( new ListenerFactory() );
+ }
+ };
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
+ namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
+ namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iomanip>
+
+namespace Catch {
+
+ class XmlEncode {
+ public:
+ enum ForWhat { ForTextNodes, ForAttributes };
+
+ XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
+ : m_str( str ),
+ m_forWhat( forWhat )
+ {}
+
+ void encodeTo( std::ostream& os ) const {
+
+ // Apostrophe escaping not necessary if we always use " to write attributes
+ // (see: http://www.w3.org/TR/xml/#syntax)
+
+ for( std::size_t i = 0; i < m_str.size(); ++ i ) {
+ char c = m_str[i];
+ switch( c ) {
+ case '<': os << "&lt;"; break;
+ case '&': os << "&amp;"; break;
+
+ case '>':
+ // See: http://www.w3.org/TR/xml/#syntax
+ if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
+ os << "&gt;";
+ else
+ os << c;
+ break;
+
+ case '\"':
+ if( m_forWhat == ForAttributes )
+ os << "&quot;";
+ else
+ os << c;
+ break;
+
+ default:
+ // Escape control chars - based on contribution by @espenalb in PR #465 and
+ // by @mrpi PR #588
+ if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+ os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+ << static_cast<int>( c );
+ }
+ else
+ os << c;
+ }
+ }
+ }
+
+ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+ xmlEncode.encodeTo( os );
+ return os;
+ }
+
+ private:
+ std::string m_str;
+ ForWhat m_forWhat;
+ };
+
+ class XmlWriter {
+ public:
+
+ class ScopedElement {
+ public:
+ ScopedElement( XmlWriter* writer )
+ : m_writer( writer )
+ {}
+
+ ScopedElement( ScopedElement const& other )
+ : m_writer( other.m_writer ){
+ other.m_writer = CATCH_NULL;
+ }
+
+ ~ScopedElement() {
+ if( m_writer )
+ m_writer->endElement();
+ }
+
+ ScopedElement& writeText( std::string const& text, bool indent = true ) {
+ m_writer->writeText( text, indent );
+ return *this;
+ }
+
+ template<typename T>
+ ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+ m_writer->writeAttribute( name, attribute );
+ return *this;
+ }
+
+ private:
+ mutable XmlWriter* m_writer;
+ };
+
+ XmlWriter()
+ : m_tagIsOpen( false ),
+ m_needsNewline( false ),
+ m_os( Catch::cout() )
+ {
+ writeDeclaration();
+ }
+
+ XmlWriter( std::ostream& os )
+ : m_tagIsOpen( false ),
+ m_needsNewline( false ),
+ m_os( os )
+ {
+ writeDeclaration();
+ }
+
+ ~XmlWriter() {
+ while( !m_tags.empty() )
+ endElement();
+ }
+
+ XmlWriter& startElement( std::string const& name ) {
+ ensureTagClosed();
+ newlineIfNecessary();
+ m_os << m_indent << '<' << name;
+ m_tags.push_back( name );
+ m_indent += " ";
+ m_tagIsOpen = true;
+ return *this;
+ }
+
+ ScopedElement scopedElement( std::string const& name ) {
+ ScopedElement scoped( this );
+ startElement( name );
+ return scoped;
+ }
+
+ XmlWriter& endElement() {
+ newlineIfNecessary();
+ m_indent = m_indent.substr( 0, m_indent.size()-2 );
+ if( m_tagIsOpen ) {
+ m_os << "/>";
+ m_tagIsOpen = false;
+ }
+ else {
+ m_os << m_indent << "</" << m_tags.back() << ">";
+ }
+ m_os << std::endl;
+ m_tags.pop_back();
+ return *this;
+ }
+
+ XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
+ if( !name.empty() && !attribute.empty() )
+ m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+ return *this;
+ }
+
+ XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
+ m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
+ return *this;
+ }
+
+ template<typename T>
+ XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+ std::ostringstream oss;
+ oss << attribute;
+ return writeAttribute( name, oss.str() );
+ }
+
+ XmlWriter& writeText( std::string const& text, bool indent = true ) {
+ if( !text.empty() ){
+ bool tagWasOpen = m_tagIsOpen;
+ ensureTagClosed();
+ if( tagWasOpen && indent )
+ m_os << m_indent;
+ m_os << XmlEncode( text );
+ m_needsNewline = true;
+ }
+ return *this;
+ }
+
+ XmlWriter& writeComment( std::string const& text ) {
+ ensureTagClosed();
+ m_os << m_indent << "<!--" << text << "-->";
+ m_needsNewline = true;
+ return *this;
+ }
+
+ void writeStylesheetRef( std::string const& url ) {
+ m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+ }
+
+ XmlWriter& writeBlankLine() {
+ ensureTagClosed();
+ m_os << '\n';
+ return *this;
+ }
+
+ void ensureTagClosed() {
+ if( m_tagIsOpen ) {
+ m_os << ">" << std::endl;
+ m_tagIsOpen = false;
+ }
+ }
+
+ private:
+ XmlWriter( XmlWriter const& );
+ void operator=( XmlWriter const& );
+
+ void writeDeclaration() {
+ m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ }
+
+ void newlineIfNecessary() {
+ if( m_needsNewline ) {
+ m_os << std::endl;
+ m_needsNewline = false;
+ }
+ }
+
+ bool m_tagIsOpen;
+ bool m_needsNewline;
+ std::vector<std::string> m_tags;
+ std::string m_indent;
+ std::ostream& m_os;
+ };
+
+}
+// #included from: catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+# ifdef __ICC // icpc defines the __clang__ macro
+# pragma warning(pop)
+# else
+# pragma clang diagnostic pop
+# endif
+#elif defined __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+
+namespace Catch {
+ class XmlReporter : public StreamingReporterBase {
+ public:
+ XmlReporter( ReporterConfig const& _config )
+ : StreamingReporterBase( _config ),
+ m_xml(_config.stream()),
+ m_sectionDepth( 0 )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ }
+
+ virtual ~XmlReporter() CATCH_OVERRIDE;
+
+ static std::string getDescription() {
+ return "Reports test results as an XML document";
+ }
+
+ virtual std::string getStylesheetRef() const {
+ return std::string();
+ }
+
+ void writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+ m_xml
+ .writeAttribute( "filename", sourceInfo.file )
+ .writeAttribute( "line", sourceInfo.line );
+ }
+
+ public: // StreamingReporterBase
+
+ virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
+ StreamingReporterBase::noMatchingTestCases( s );
+ }
+
+ virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
+ StreamingReporterBase::testRunStarting( testInfo );
+ std::string stylesheetRef = getStylesheetRef();
+ if( !stylesheetRef.empty() )
+ m_xml.writeStylesheetRef( stylesheetRef );
+ m_xml.startElement( "Catch" );
+ if( !m_config->name().empty() )
+ m_xml.writeAttribute( "name", m_config->name() );
+ }
+
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+ StreamingReporterBase::testGroupStarting( groupInfo );
+ m_xml.startElement( "Group" )
+ .writeAttribute( "name", groupInfo.name );
+ }
+
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+ StreamingReporterBase::testCaseStarting(testInfo);
+ m_xml.startElement( "TestCase" )
+ .writeAttribute( "name", trim( testInfo.name ) )
+ .writeAttribute( "description", testInfo.description )
+ .writeAttribute( "tags", testInfo.tagsAsString );
+
+ writeSourceInfo( testInfo.lineInfo );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ m_testCaseTimer.start();
+ m_xml.ensureTagClosed();
+ }
+
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+ StreamingReporterBase::sectionStarting( sectionInfo );
+ if( m_sectionDepth++ > 0 ) {
+ m_xml.startElement( "Section" )
+ .writeAttribute( "name", trim( sectionInfo.name ) )
+ .writeAttribute( "description", sectionInfo.description );
+ writeSourceInfo( sectionInfo.lineInfo );
+ m_xml.ensureTagClosed();
+ }
+ }
+
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
+
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+ const AssertionResult& assertionResult = assertionStats.assertionResult;
+
+ // Print any info messages in <Info> tags.
+ if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+ for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+ it != itEnd;
+ ++it ) {
+ if( it->type == ResultWas::Info ) {
+ m_xml.scopedElement( "Info" )
+ .writeText( it->message );
+ } else if ( it->type == ResultWas::Warning ) {
+ m_xml.scopedElement( "Warning" )
+ .writeText( it->message );
+ }
+ }
+ }
+
+ // Drop out if result was successful but we're not printing them.
+ if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
+ return true;
+
+ // Print the expression if there is one.
+ if( assertionResult.hasExpression() ) {
+ m_xml.startElement( "Expression" )
+ .writeAttribute( "success", assertionResult.succeeded() )
+ .writeAttribute( "type", assertionResult.getTestMacroName() );
+
+ writeSourceInfo( assertionResult.getSourceInfo() );
+
+ m_xml.scopedElement( "Original" )
+ .writeText( assertionResult.getExpression() );
+ m_xml.scopedElement( "Expanded" )
+ .writeText( assertionResult.getExpandedExpression() );
+ }
+
+ // And... Print a result applicable to each result type.
+ switch( assertionResult.getResultType() ) {
+ case ResultWas::ThrewException:
+ m_xml.startElement( "Exception" );
+ writeSourceInfo( assertionResult.getSourceInfo() );
+ m_xml.writeText( assertionResult.getMessage() );
+ m_xml.endElement();
+ break;
+ case ResultWas::FatalErrorCondition:
+ m_xml.startElement( "FatalErrorCondition" );
+ writeSourceInfo( assertionResult.getSourceInfo() );
+ m_xml.writeText( assertionResult.getMessage() );
+ m_xml.endElement();
+ break;
+ case ResultWas::Info:
+ m_xml.scopedElement( "Info" )
+ .writeText( assertionResult.getMessage() );
+ break;
+ case ResultWas::Warning:
+ // Warning will already have been written
+ break;
+ case ResultWas::ExplicitFailure:
+ m_xml.startElement( "Failure" );
+ writeSourceInfo( assertionResult.getSourceInfo() );
+ m_xml.writeText( assertionResult.getMessage() );
+ m_xml.endElement();
+ break;
+ default:
+ break;
+ }
+
+ if( assertionResult.hasExpression() )
+ m_xml.endElement();
+
+ return true;
+ }
+
+ virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+ StreamingReporterBase::sectionEnded( sectionStats );
+ if( --m_sectionDepth > 0 ) {
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+ e.writeAttribute( "successes", sectionStats.assertions.passed );
+ e.writeAttribute( "failures", sectionStats.assertions.failed );
+ e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+ m_xml.endElement();
+ }
+ }
+
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+ StreamingReporterBase::testCaseEnded( testCaseStats );
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+ e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+ if( !testCaseStats.stdOut.empty() )
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+ if( !testCaseStats.stdErr.empty() )
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+
+ m_xml.endElement();
+ }
+
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+ StreamingReporterBase::testGroupEnded( testGroupStats );
+ // TODO: Check testGroupStats.aborting and act accordingly.
+ m_xml.scopedElement( "OverallResults" )
+ .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+ .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+ .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+ m_xml.endElement();
+ }
+
+ virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+ StreamingReporterBase::testRunEnded( testRunStats );
+ m_xml.scopedElement( "OverallResults" )
+ .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+ .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+ .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+ m_xml.endElement();
+ }
+
+ private:
+ Timer m_testCaseTimer;
+ XmlWriter m_xml;
+ int m_sectionDepth;
+ };
+
+ INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+ namespace {
+ std::string getCurrentTimestamp() {
+ // Beware, this is not reentrant because of backward compatibility issues
+ // Also, UTC only, again because of backward compatibility (%z is C++11)
+ time_t rawtime;
+ std::time(&rawtime);
+ const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+ std::tm timeInfo = {};
+ gmtime_s(&timeInfo, &rawtime);
+#else
+ std::tm* timeInfo;
+ timeInfo = std::gmtime(&rawtime);
+#endif
+
+ char timeStamp[timeStampSize];
+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+ return std::string(timeStamp);
+ }
+
+ }
+
+ class JunitReporter : public CumulativeReporterBase {
+ public:
+ JunitReporter( ReporterConfig const& _config )
+ : CumulativeReporterBase( _config ),
+ xml( _config.stream() )
+ {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ }
+
+ virtual ~JunitReporter() CATCH_OVERRIDE;
+
+ static std::string getDescription() {
+ return "Reports test results in an XML format that looks like Ant's junitreport target";
+ }
+
+ virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {}
+
+ virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
+ CumulativeReporterBase::testRunStarting( runInfo );
+ xml.startElement( "testsuites" );
+ }
+
+ virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+ suiteTimer.start();
+ stdOutForSuite.str("");
+ stdErrForSuite.str("");
+ unexpectedExceptions = 0;
+ CumulativeReporterBase::testGroupStarting( groupInfo );
+ }
+
+ virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+ if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
+ unexpectedExceptions++;
+ return CumulativeReporterBase::assertionEnded( assertionStats );
+ }
+
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+ stdOutForSuite << testCaseStats.stdOut;
+ stdErrForSuite << testCaseStats.stdErr;
+ CumulativeReporterBase::testCaseEnded( testCaseStats );
+ }
+
+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+ double suiteTime = suiteTimer.getElapsedSeconds();
+ CumulativeReporterBase::testGroupEnded( testGroupStats );
+ writeGroup( *m_testGroups.back(), suiteTime );
+ }
+
+ virtual void testRunEndedCumulative() CATCH_OVERRIDE {
+ xml.endElement();
+ }
+
+ void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+ XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+ TestGroupStats const& stats = groupNode.value;
+ xml.writeAttribute( "name", stats.groupInfo.name );
+ xml.writeAttribute( "errors", unexpectedExceptions );
+ xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+ xml.writeAttribute( "tests", stats.totals.assertions.total() );
+ xml.writeAttribute( "hostname", "tbd" ); // !TBD
+ if( m_config->showDurations() == ShowDurations::Never )
+ xml.writeAttribute( "time", "" );
+ else
+ xml.writeAttribute( "time", suiteTime );
+ xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+
+ // Write test cases
+ for( TestGroupNode::ChildNodes::const_iterator
+ it = groupNode.children.begin(), itEnd = groupNode.children.end();
+ it != itEnd;
+ ++it )
+ writeTestCase( **it );
+
+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
+ }
+
+ void writeTestCase( TestCaseNode const& testCaseNode ) {
+ TestCaseStats const& stats = testCaseNode.value;
+
+ // All test cases have exactly one section - which represents the
+ // test case itself. That section may have 0-n nested sections
+ assert( testCaseNode.children.size() == 1 );
+ SectionNode const& rootSection = *testCaseNode.children.front();
+
+ std::string className = stats.testInfo.className;
+
+ if( className.empty() ) {
+ if( rootSection.childSections.empty() )
+ className = "global";
+ }
+ writeSection( className, "", rootSection );
+ }
+
+ void writeSection( std::string const& className,
+ std::string const& rootName,
+ SectionNode const& sectionNode ) {
+ std::string name = trim( sectionNode.stats.sectionInfo.name );
+ if( !rootName.empty() )
+ name = rootName + '/' + name;
+
+ if( !sectionNode.assertions.empty() ||
+ !sectionNode.stdOut.empty() ||
+ !sectionNode.stdErr.empty() ) {
+ XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+ if( className.empty() ) {
+ xml.writeAttribute( "classname", name );
+ xml.writeAttribute( "name", "root" );
+ }
+ else {
+ xml.writeAttribute( "classname", className );
+ xml.writeAttribute( "name", name );
+ }
+ xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
+
+ writeAssertions( sectionNode );
+
+ if( !sectionNode.stdOut.empty() )
+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+ if( !sectionNode.stdErr.empty() )
+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+ }
+ for( SectionNode::ChildSections::const_iterator
+ it = sectionNode.childSections.begin(),
+ itEnd = sectionNode.childSections.end();
+ it != itEnd;
+ ++it )
+ if( className.empty() )
+ writeSection( name, "", **it );
+ else
+ writeSection( className, name, **it );
+ }
+
+ void writeAssertions( SectionNode const& sectionNode ) {
+ for( SectionNode::Assertions::const_iterator
+ it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
+ it != itEnd;
+ ++it )
+ writeAssertion( *it );
+ }
+ void writeAssertion( AssertionStats const& stats ) {
+ AssertionResult const& result = stats.assertionResult;
+ if( !result.isOk() ) {
+ std::string elementName;
+ switch( result.getResultType() ) {
+ case ResultWas::ThrewException:
+ case ResultWas::FatalErrorCondition:
+ elementName = "error";
+ break;
+ case ResultWas::ExplicitFailure:
+ elementName = "failure";
+ break;
+ case ResultWas::ExpressionFailed:
+ elementName = "failure";
+ break;
+ case ResultWas::DidntThrowException:
+ elementName = "failure";
+ break;
+
+ // We should never see these here:
+ case ResultWas::Info:
+ case ResultWas::Warning:
+ case ResultWas::Ok:
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ elementName = "internalError";
+ break;
+ }
+
+ XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+ xml.writeAttribute( "message", result.getExpandedExpression() );
+ xml.writeAttribute( "type", result.getTestMacroName() );
+
+ std::ostringstream oss;
+ if( !result.getMessage().empty() )
+ oss << result.getMessage() << '\n';
+ for( std::vector<MessageInfo>::const_iterator
+ it = stats.infoMessages.begin(),
+ itEnd = stats.infoMessages.end();
+ it != itEnd;
+ ++it )
+ if( it->type == ResultWas::Info )
+ oss << it->message << '\n';
+
+ oss << "at " << result.getSourceInfo();
+ xml.writeText( oss.str(), false );
+ }
+ }
+
+ XmlWriter xml;
+ Timer suiteTimer;
+ std::ostringstream stdOutForSuite;
+ std::ostringstream stdErrForSuite;
+ unsigned int unexpectedExceptions;
+ };
+
+ INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+#include <cfloat>
+#include <cstdio>
+
+namespace Catch {
+
+ namespace {
+ // Because formatting using c++ streams is stateful, drop down to C is required
+ // Alternatively we could use stringstream, but its performance is... not good.
+ std::string getFormattedDuration( double duration ) {
+ // Max exponent + 1 is required to represent the whole part
+ // + 1 for decimal point
+ // + 3 for the 3 decimal places
+ // + 1 for null terminator
+ const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+ char buffer[maxDoubleSize];
+#ifdef _MSC_VER
+ sprintf_s(buffer, "%.3f", duration);
+#else
+ sprintf(buffer, "%.3f", duration);
+#endif
+ return std::string(buffer);
+ }
+ }
+
+ struct ConsoleReporter : StreamingReporterBase {
+ ConsoleReporter( ReporterConfig const& _config )
+ : StreamingReporterBase( _config ),
+ m_headerPrinted( false )
+ {}
+
+ virtual ~ConsoleReporter() CATCH_OVERRIDE;
+ static std::string getDescription() {
+ return "Reports test results as plain lines of text";
+ }
+
+ virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+ stream << "No test cases matched '" << spec << '\'' << std::endl;
+ }
+
+ virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
+ }
+
+ virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+ if( result.getResultType() != ResultWas::Warning )
+ return false;
+ printInfoMessages = false;
+ }
+
+ lazyPrint();
+
+ AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+ printer.print();
+ stream << std::endl;
+ return true;
+ }
+
+ virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+ m_headerPrinted = false;
+ StreamingReporterBase::sectionStarting( _sectionInfo );
+ }
+ virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
+ if( _sectionStats.missingAssertions ) {
+ lazyPrint();
+ Colour colour( Colour::ResultError );
+ if( m_sectionStack.size() > 1 )
+ stream << "\nNo assertions in section";
+ else
+ stream << "\nNo assertions in test case";
+ stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+ }
+ if( m_config->showDurations() == ShowDurations::Always ) {
+ stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ }
+ if( m_headerPrinted ) {
+ m_headerPrinted = false;
+ }
+ StreamingReporterBase::sectionEnded( _sectionStats );
+ }
+
+ virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
+ StreamingReporterBase::testCaseEnded( _testCaseStats );
+ m_headerPrinted = false;
+ }
+ virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
+ if( currentGroupInfo.used ) {
+ printSummaryDivider();
+ stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+ printTotals( _testGroupStats.totals );
+ stream << '\n' << std::endl;
+ }
+ StreamingReporterBase::testGroupEnded( _testGroupStats );
+ }
+ virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
+ printTotalsDivider( _testRunStats.totals );
+ printTotals( _testRunStats.totals );
+ stream << std::endl;
+ StreamingReporterBase::testRunEnded( _testRunStats );
+ }
+
+ private:
+
+ class AssertionPrinter {
+ void operator= ( AssertionPrinter const& );
+ public:
+ AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+ : stream( _stream ),
+ stats( _stats ),
+ result( _stats.assertionResult ),
+ colour( Colour::None ),
+ message( result.getMessage() ),
+ messages( _stats.infoMessages ),
+ printInfoMessages( _printInfoMessages )
+ {
+ switch( result.getResultType() ) {
+ case ResultWas::Ok:
+ colour = Colour::Success;
+ passOrFail = "PASSED";
+ //if( result.hasMessage() )
+ if( _stats.infoMessages.size() == 1 )
+ messageLabel = "with message";
+ if( _stats.infoMessages.size() > 1 )
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ExpressionFailed:
+ if( result.isOk() ) {
+ colour = Colour::Success;
+ passOrFail = "FAILED - but was ok";
+ }
+ else {
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ }
+ if( _stats.infoMessages.size() == 1 )
+ messageLabel = "with message";
+ if( _stats.infoMessages.size() > 1 )
+ messageLabel = "with messages";
+ break;
+ case ResultWas::ThrewException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to unexpected exception with message";
+ break;
+ case ResultWas::FatalErrorCondition:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "due to a fatal error condition";
+ break;
+ case ResultWas::DidntThrowException:
+ colour = Colour::Error;
+ passOrFail = "FAILED";
+ messageLabel = "because no exception was thrown where one was expected";
+ break;
+ case ResultWas::Info:
+ messageLabel = "info";
+ break;
+ case ResultWas::Warning:
+ messageLabel = "warning";
+ break;
+ case ResultWas::ExplicitFailure:
+ passOrFail = "FAILED";
+ colour = Colour::Error;
+ if( _stats.infoMessages.size() == 1 )
+ messageLabel = "explicitly with message";
+ if( _stats.infoMessages.size() > 1 )
+ messageLabel = "explicitly with messages";
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ passOrFail = "** internal error **";
+ colour = Colour::Error;
+ break;
+ }
+ }
+
+ void print() const {
+ printSourceInfo();
+ if( stats.totals.assertions.total() > 0 ) {
+ if( result.isOk() )
+ stream << '\n';
+ printResultType();
+ printOriginalExpression();
+ printReconstructedExpression();
+ }
+ else {
+ stream << '\n';
+ }
+ printMessage();
+ }
+
+ private:
+ void printResultType() const {
+ if( !passOrFail.empty() ) {
+ Colour colourGuard( colour );
+ stream << passOrFail << ":\n";
+ }
+ }
+ void printOriginalExpression() const {
+ if( result.hasExpression() ) {
+ Colour colourGuard( Colour::OriginalExpression );
+ stream << " ";
+ stream << result.getExpressionInMacro();
+ stream << '\n';
+ }
+ }
+ void printReconstructedExpression() const {
+ if( result.hasExpandedExpression() ) {
+ stream << "with expansion:\n";
+ Colour colourGuard( Colour::ReconstructedExpression );
+ stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
+ }
+ }
+ void printMessage() const {
+ if( !messageLabel.empty() )
+ stream << messageLabel << ':' << '\n';
+ for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+ it != itEnd;
+ ++it ) {
+ // If this assertion is a warning ignore any INFO messages
+ if( printInfoMessages || it->type != ResultWas::Info )
+ stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
+ }
+ }
+ void printSourceInfo() const {
+ Colour colourGuard( Colour::FileName );
+ stream << result.getSourceInfo() << ": ";
+ }
+
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ Colour::Code colour;
+ std::string passOrFail;
+ std::string messageLabel;
+ std::string message;
+ std::vector<MessageInfo> messages;
+ bool printInfoMessages;
+ };
+
+ void lazyPrint() {
+
+ if( !currentTestRunInfo.used )
+ lazyPrintRunInfo();
+ if( !currentGroupInfo.used )
+ lazyPrintGroupInfo();
+
+ if( !m_headerPrinted ) {
+ printTestCaseAndSectionHeader();
+ m_headerPrinted = true;
+ }
+ }
+ void lazyPrintRunInfo() {
+ stream << '\n' << getLineOfChars<'~'>() << '\n';
+ Colour colour( Colour::SecondaryText );
+ stream << currentTestRunInfo->name
+ << " is a Catch v" << libraryVersion << " host application.\n"
+ << "Run with -? for options\n\n";
+
+ if( m_config->rngSeed() != 0 )
+ stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+ currentTestRunInfo.used = true;
+ }
+ void lazyPrintGroupInfo() {
+ if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
+ printClosedHeader( "Group: " + currentGroupInfo->name );
+ currentGroupInfo.used = true;
+ }
+ }
+ void printTestCaseAndSectionHeader() {
+ assert( !m_sectionStack.empty() );
+ printOpenHeader( currentTestCaseInfo->name );
+
+ if( m_sectionStack.size() > 1 ) {
+ Colour colourGuard( Colour::Headers );
+
+ std::vector<SectionInfo>::const_iterator
+ it = m_sectionStack.begin()+1, // Skip first section (test case)
+ itEnd = m_sectionStack.end();
+ for( ; it != itEnd; ++it )
+ printHeaderString( it->name, 2 );
+ }
+
+ SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+ if( !lineInfo.empty() ){
+ stream << getLineOfChars<'-'>() << '\n';
+ Colour colourGuard( Colour::FileName );
+ stream << lineInfo << '\n';
+ }
+ stream << getLineOfChars<'.'>() << '\n' << std::endl;
+ }
+
+ void printClosedHeader( std::string const& _name ) {
+ printOpenHeader( _name );
+ stream << getLineOfChars<'.'>() << '\n';
+ }
+ void printOpenHeader( std::string const& _name ) {
+ stream << getLineOfChars<'-'>() << '\n';
+ {
+ Colour colourGuard( Colour::Headers );
+ printHeaderString( _name );
+ }
+ }
+
+ // if string has a : in first line will set indent to follow it on
+ // subsequent lines
+ void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
+ std::size_t i = _string.find( ": " );
+ if( i != std::string::npos )
+ i+=2;
+ else
+ i = 0;
+ stream << Text( _string, TextAttributes()
+ .setIndent( indent+i)
+ .setInitialIndent( indent ) ) << '\n';
+ }
+
+ struct SummaryColumn {
+
+ SummaryColumn( std::string const& _label, Colour::Code _colour )
+ : label( _label ),
+ colour( _colour )
+ {}
+ SummaryColumn addRow( std::size_t count ) {
+ std::ostringstream oss;
+ oss << count;
+ std::string row = oss.str();
+ for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
+ while( it->size() < row.size() )
+ *it = ' ' + *it;
+ while( it->size() > row.size() )
+ row = ' ' + row;
+ }
+ rows.push_back( row );
+ return *this;
+ }
+
+ std::string label;
+ Colour::Code colour;
+ std::vector<std::string> rows;
+
+ };
+
+ void printTotals( Totals const& totals ) {
+ if( totals.testCases.total() == 0 ) {
+ stream << Colour( Colour::Warning ) << "No tests ran\n";
+ }
+ else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
+ stream << Colour( Colour::ResultSuccess ) << "All tests passed";
+ stream << " ("
+ << pluralise( totals.assertions.passed, "assertion" ) << " in "
+ << pluralise( totals.testCases.passed, "test case" ) << ')'
+ << '\n';
+ }
+ else {
+
+ std::vector<SummaryColumn> columns;
+ columns.push_back( SummaryColumn( "", Colour::None )
+ .addRow( totals.testCases.total() )
+ .addRow( totals.assertions.total() ) );
+ columns.push_back( SummaryColumn( "passed", Colour::Success )
+ .addRow( totals.testCases.passed )
+ .addRow( totals.assertions.passed ) );
+ columns.push_back( SummaryColumn( "failed", Colour::ResultError )
+ .addRow( totals.testCases.failed )
+ .addRow( totals.assertions.failed ) );
+ columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
+ .addRow( totals.testCases.failedButOk )
+ .addRow( totals.assertions.failedButOk ) );
+
+ printSummaryRow( "test cases", columns, 0 );
+ printSummaryRow( "assertions", columns, 1 );
+ }
+ }
+ void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
+ for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
+ std::string value = it->rows[row];
+ if( it->label.empty() ) {
+ stream << label << ": ";
+ if( value != "0" )
+ stream << value;
+ else
+ stream << Colour( Colour::Warning ) << "- none -";
+ }
+ else if( value != "0" ) {
+ stream << Colour( Colour::LightGrey ) << " | ";
+ stream << Colour( it->colour )
+ << value << ' ' << it->label;
+ }
+ }
+ stream << '\n';
+ }
+
+ static std::size_t makeRatio( std::size_t number, std::size_t total ) {
+ std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
+ return ( ratio == 0 && number > 0 ) ? 1 : ratio;
+ }
+ static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+ if( i > j && i > k )
+ return i;
+ else if( j > k )
+ return j;
+ else
+ return k;
+ }
+
+ void printTotalsDivider( Totals const& totals ) {
+ if( totals.testCases.total() > 0 ) {
+ std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
+ std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
+ std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
+ while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
+ findMax( failedRatio, failedButOkRatio, passedRatio )++;
+ while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
+ findMax( failedRatio, failedButOkRatio, passedRatio )--;
+
+ stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
+ stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
+ if( totals.testCases.allPassed() )
+ stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
+ else
+ stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
+ }
+ else {
+ stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
+ }
+ stream << '\n';
+ }
+ void printSummaryDivider() {
+ stream << getLineOfChars<'-'>() << '\n';
+ }
+
+ private:
+ bool m_headerPrinted;
+ };
+
+ INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+ struct CompactReporter : StreamingReporterBase {
+
+ CompactReporter( ReporterConfig const& _config )
+ : StreamingReporterBase( _config )
+ {}
+
+ virtual ~CompactReporter();
+
+ static std::string getDescription() {
+ return "Reports test results on a single line, suitable for IDEs";
+ }
+
+ virtual ReporterPreferences getPreferences() const {
+ ReporterPreferences prefs;
+ prefs.shouldRedirectStdOut = false;
+ return prefs;
+ }
+
+ virtual void noMatchingTestCases( std::string const& spec ) {
+ stream << "No test cases matched '" << spec << '\'' << std::endl;
+ }
+
+ virtual void assertionStarting( AssertionInfo const& ) {
+ }
+
+ virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+ AssertionResult const& result = _assertionStats.assertionResult;
+
+ bool printInfoMessages = true;
+
+ // Drop out if result was successful and we're not printing those
+ if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+ if( result.getResultType() != ResultWas::Warning )
+ return false;
+ printInfoMessages = false;
+ }
+
+ AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+ printer.print();
+
+ stream << std::endl;
+ return true;
+ }
+
+ virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+ printTotals( _testRunStats.totals );
+ stream << '\n' << std::endl;
+ StreamingReporterBase::testRunEnded( _testRunStats );
+ }
+
+ private:
+ class AssertionPrinter {
+ void operator= ( AssertionPrinter const& );
+ public:
+ AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+ : stream( _stream )
+ , stats( _stats )
+ , result( _stats.assertionResult )
+ , messages( _stats.infoMessages )
+ , itMessage( _stats.infoMessages.begin() )
+ , printInfoMessages( _printInfoMessages )
+ {}
+
+ void print() {
+ printSourceInfo();
+
+ itMessage = messages.begin();
+
+ switch( result.getResultType() ) {
+ case ResultWas::Ok:
+ printResultType( Colour::ResultSuccess, passedString() );
+ printOriginalExpression();
+ printReconstructedExpression();
+ if ( ! result.hasExpression() )
+ printRemainingMessages( Colour::None );
+ else
+ printRemainingMessages();
+ break;
+ case ResultWas::ExpressionFailed:
+ if( result.isOk() )
+ printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
+ else
+ printResultType( Colour::Error, failedString() );
+ printOriginalExpression();
+ printReconstructedExpression();
+ printRemainingMessages();
+ break;
+ case ResultWas::ThrewException:
+ printResultType( Colour::Error, failedString() );
+ printIssue( "unexpected exception with message:" );
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::FatalErrorCondition:
+ printResultType( Colour::Error, failedString() );
+ printIssue( "fatal error condition with message:" );
+ printMessage();
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::DidntThrowException:
+ printResultType( Colour::Error, failedString() );
+ printIssue( "expected exception, got none" );
+ printExpressionWas();
+ printRemainingMessages();
+ break;
+ case ResultWas::Info:
+ printResultType( Colour::None, "info" );
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::Warning:
+ printResultType( Colour::None, "warning" );
+ printMessage();
+ printRemainingMessages();
+ break;
+ case ResultWas::ExplicitFailure:
+ printResultType( Colour::Error, failedString() );
+ printIssue( "explicitly" );
+ printRemainingMessages( Colour::None );
+ break;
+ // These cases are here to prevent compiler warnings
+ case ResultWas::Unknown:
+ case ResultWas::FailureBit:
+ case ResultWas::Exception:
+ printResultType( Colour::Error, "** internal error **" );
+ break;
+ }
+ }
+
+ private:
+ // Colour::LightGrey
+
+ static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+ static const char* failedString() { return "FAILED"; }
+ static const char* passedString() { return "PASSED"; }
+#else
+ static const char* failedString() { return "failed"; }
+ static const char* passedString() { return "passed"; }
+#endif
+
+ void printSourceInfo() const {
+ Colour colourGuard( Colour::FileName );
+ stream << result.getSourceInfo() << ':';
+ }
+
+ void printResultType( Colour::Code colour, std::string passOrFail ) const {
+ if( !passOrFail.empty() ) {
+ {
+ Colour colourGuard( colour );
+ stream << ' ' << passOrFail;
+ }
+ stream << ':';
+ }
+ }
+
+ void printIssue( std::string issue ) const {
+ stream << ' ' << issue;
+ }
+
+ void printExpressionWas() {
+ if( result.hasExpression() ) {
+ stream << ';';
+ {
+ Colour colour( dimColour() );
+ stream << " expression was:";
+ }
+ printOriginalExpression();
+ }
+ }
+
+ void printOriginalExpression() const {
+ if( result.hasExpression() ) {
+ stream << ' ' << result.getExpression();
+ }
+ }
+
+ void printReconstructedExpression() const {
+ if( result.hasExpandedExpression() ) {
+ {
+ Colour colour( dimColour() );
+ stream << " for: ";
+ }
+ stream << result.getExpandedExpression();
+ }
+ }
+
+ void printMessage() {
+ if ( itMessage != messages.end() ) {
+ stream << " '" << itMessage->message << '\'';
+ ++itMessage;
+ }
+ }
+
+ void printRemainingMessages( Colour::Code colour = dimColour() ) {
+ if ( itMessage == messages.end() )
+ return;
+
+ // using messages.end() directly yields compilation error:
+ std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+ const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+
+ {
+ Colour colourGuard( colour );
+ stream << " with " << pluralise( N, "message" ) << ':';
+ }
+
+ for(; itMessage != itEnd; ) {
+ // If this assertion is a warning ignore any INFO messages
+ if( printInfoMessages || itMessage->type != ResultWas::Info ) {
+ stream << " '" << itMessage->message << '\'';
+ if ( ++itMessage != itEnd ) {
+ Colour colourGuard( dimColour() );
+ stream << " and";
+ }
+ }
+ }
+ }
+
+ private:
+ std::ostream& stream;
+ AssertionStats const& stats;
+ AssertionResult const& result;
+ std::vector<MessageInfo> messages;
+ std::vector<MessageInfo>::const_iterator itMessage;
+ bool printInfoMessages;
+ };
+
+ // Colour, message variants:
+ // - white: No tests ran.
+ // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
+ // - white: Passed [both/all] N test cases (no assertions).
+ // - red: Failed N tests cases, failed M assertions.
+ // - green: Passed [both/all] N tests cases with M assertions.
+
+ std::string bothOrAll( std::size_t count ) const {
+ return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
+ }
+
+ void printTotals( const Totals& totals ) const {
+ if( totals.testCases.total() == 0 ) {
+ stream << "No tests ran.";
+ }
+ else if( totals.testCases.failed == totals.testCases.total() ) {
+ Colour colour( Colour::ResultError );
+ const std::string qualify_assertions_failed =
+ totals.assertions.failed == totals.assertions.total() ?
+ bothOrAll( totals.assertions.failed ) : std::string();
+ stream <<
+ "Failed " << bothOrAll( totals.testCases.failed )
+ << pluralise( totals.testCases.failed, "test case" ) << ", "
+ "failed " << qualify_assertions_failed <<
+ pluralise( totals.assertions.failed, "assertion" ) << '.';
+ }
+ else if( totals.assertions.total() == 0 ) {
+ stream <<
+ "Passed " << bothOrAll( totals.testCases.total() )
+ << pluralise( totals.testCases.total(), "test case" )
+ << " (no assertions).";
+ }
+ else if( totals.assertions.failed ) {
+ Colour colour( Colour::ResultError );
+ stream <<
+ "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", "
+ "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
+ }
+ else {
+ Colour colour( Colour::ResultSuccess );
+ stream <<
+ "Passed " << bothOrAll( totals.testCases.passed )
+ << pluralise( totals.testCases.passed, "test case" ) <<
+ " with " << pluralise( totals.assertions.passed, "assertion" ) << '.';
+ }
+ }
+ };
+
+ INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+
+namespace Catch {
+ // These are all here to avoid warnings about not having any out of line
+ // virtual methods
+ NonCopyable::~NonCopyable() {}
+ IShared::~IShared() {}
+ IStream::~IStream() CATCH_NOEXCEPT {}
+ FileStream::~FileStream() CATCH_NOEXCEPT {}
+ CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+ DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+ StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+ IContext::~IContext() {}
+ IResultCapture::~IResultCapture() {}
+ ITestCase::~ITestCase() {}
+ ITestCaseRegistry::~ITestCaseRegistry() {}
+ IRegistryHub::~IRegistryHub() {}
+ IMutableRegistryHub::~IMutableRegistryHub() {}
+ IExceptionTranslator::~IExceptionTranslator() {}
+ IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+ IReporter::~IReporter() {}
+ IReporterFactory::~IReporterFactory() {}
+ IReporterRegistry::~IReporterRegistry() {}
+ IStreamingReporter::~IStreamingReporter() {}
+ AssertionStats::~AssertionStats() {}
+ SectionStats::~SectionStats() {}
+ TestCaseStats::~TestCaseStats() {}
+ TestGroupStats::~TestGroupStats() {}
+ TestRunStats::~TestRunStats() {}
+ CumulativeReporterBase::SectionNode::~SectionNode() {}
+ CumulativeReporterBase::~CumulativeReporterBase() {}
+
+ StreamingReporterBase::~StreamingReporterBase() {}
+ ConsoleReporter::~ConsoleReporter() {}
+ CompactReporter::~CompactReporter() {}
+ IRunner::~IRunner() {}
+ IMutableContext::~IMutableContext() {}
+ IConfig::~IConfig() {}
+ XmlReporter::~XmlReporter() {}
+ JunitReporter::~JunitReporter() {}
+ TestRegistry::~TestRegistry() {}
+ FreeFunctionTestCase::~FreeFunctionTestCase() {}
+ IGeneratorInfo::~IGeneratorInfo() {}
+ IGeneratorsForTest::~IGeneratorsForTest() {}
+ WildcardPattern::~WildcardPattern() {}
+ TestSpec::Pattern::~Pattern() {}
+ TestSpec::NamePattern::~NamePattern() {}
+ TestSpec::TagPattern::~TagPattern() {}
+ TestSpec::ExcludedPattern::~ExcludedPattern() {}
+
+ void Config::dummy() {}
+
+ namespace TestCaseTracking {
+ ITracker::~ITracker() {}
+ TrackerBase::~TrackerBase() {}
+ SectionTracker::~SectionTracker() {}
+ IndexTracker::~IndexTracker() {}
+ }
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+ int result = Catch::Session().run( argc, argv );
+ return ( result < 0xff ? result : 0xff );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+ Catch::registerTestMethods();
+ int result = Catch::Session().run( argc, (char* const*)argv );
+
+#if !CATCH_ARC_ENABLED
+ [pool drain];
+#endif
+
+ return ( result < 0xff ? result : 0xff );
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+# undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
+
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
+
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
+
+#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CATCH_CHECK_THROWS" )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
+
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+ #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+ #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+ #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+ #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
+ #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
+#else
+ #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+ #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+ #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+ #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
+ #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+ #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
+ #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
+#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" )
+#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" )
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
+#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" )
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
+
+#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
+
+#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
+#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+ #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+ #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+ #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+ #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+ #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
+ #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
+#else
+ #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+ #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+ #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+ #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
+ #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+ #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
+ #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
+#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" )
+#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" )
+#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
+#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" )
+#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" )
+
+using Catch::Detail::Approx;
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/fuzzylite/test/hedge/HedgeFunctionTest.cpp b/fuzzylite/test/hedge/HedgeFunctionTest.cpp
new file mode 100644
index 0000000..dab70f5
--- /dev/null
+++ b/fuzzylite/test/hedge/HedgeFunctionTest.cpp
@@ -0,0 +1,141 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: hedge/HedgeFunction
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ static std::string hedgeEngine() {
+#ifdef FL_CPP98
+ return "";
+#else
+ return R""(
+Engine: Sugeno-Tip-Calculator
+InputVariable: FoodQuality
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+InputVariable: Service
+ enabled: true
+ range: 1.000 10.000
+ lock-range: false
+ term: Bad Trapezoid 0.000 1.000 3.000 7.000
+ term: Good Trapezoid 3.000 7.000 10.000 11.000
+OutputVariable: CheapTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: AverageTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+OutputVariable: GenerousTip
+ enabled: true
+ range: 5.000 25.000
+ lock-range: false
+ aggregation: none
+ defuzzifier: WeightedAverage TakagiSugeno
+ default: nan
+ lock-previous: false
+ term: Low Constant 10.000
+ term: Medium Constant 15.000
+ term: High Constant 20.000
+RuleBlock:
+ enabled: true
+ conjunction: EinsteinProduct
+ disjunction: none
+ implication: none
+ activation: General
+ rule: if FoodQuality is extremely Bad and Service is extremely Bad then CheapTip is extremely Low and AverageTip is very Low and GenerousTip is Low
+ rule: if FoodQuality is Good and Service is extremely Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is very Good and Service is very Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Bad and Service is Bad then CheapTip is Low and AverageTip is Low and GenerousTip is Medium
+ rule: if FoodQuality is Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is extremely Good and Service is Bad then CheapTip is Low and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is Bad and Service is Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is Good and Service is Good then CheapTip is Medium and AverageTip is Medium and GenerousTip is very High
+ rule: if FoodQuality is very Bad and Service is very Good then CheapTip is Low and AverageTip is Medium and GenerousTip is High
+ rule: if FoodQuality is very very Good and Service is very very Good then CheapTip is High and AverageTip is very High and GenerousTip is extremely High
+)"";
+#endif
+ }
+
+ static Hedge* myVeryConstructor() {
+ return new HedgeFunction("x*x");
+ }
+
+ static Hedge* myExtraVeryConstructor() {
+ return new HedgeFunction("x*x*x");
+ }
+
+ TEST_CASE("HedgeFunction x*x is equivalent to hedge Very", "[hedge][function]") {
+#ifdef FL_CPP98
+ FL_IUNUSED(&(hedgeEngine));
+ FL_IUNUSED(&(myVeryConstructor));
+ FL_IUNUSED(&(myExtraVeryConstructor));
+ WARN("Test only runs with -DFL_CPP98=OFF");
+ return;
+#else
+ std::string fllEngine = hedgeEngine();
+ //Import using regular hedge very
+ FL_unique_ptr<Engine> engine(FllImporter().fromString(fllEngine));
+ std::string fldVery = FldExporter().toString(engine.get(), 1024);
+
+ //Replace hedge very with a HedgeFunction(x*x)
+ HedgeFactory* factory = FactoryManager::instance()->hedge();
+ factory->registerConstructor("very", &(myVeryConstructor));
+ //Import again with new HedgeFunction
+ engine.reset(FllImporter().fromString(fllEngine));
+ std::string anotherFld = FldExporter().toString(engine.get(), 1024);
+ //Both must be equal
+ CHECK(fldVery == anotherFld);
+
+ //Replace very with a HedgeFunction(x*x*x)
+ factory->registerConstructor("very", &(myExtraVeryConstructor));
+
+ engine.reset(FllImporter().fromString(fllEngine));
+ anotherFld = FldExporter().toString(engine.get(), 1024);
+
+ //Must be different
+ CHECK(fldVery != anotherFld);
+#endif
+ }
+
+}
diff --git a/fuzzylite/test/imex/FldExporterTest.cpp b/fuzzylite/test/imex/FldExporterTest.cpp
new file mode 100644
index 0000000..e312f1d
--- /dev/null
+++ b/fuzzylite/test/imex/FldExporterTest.cpp
@@ -0,0 +1,45 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ TEST_CASE("Exports same number of values in scopes", "[imex]") {
+ FL_unique_ptr<Engine> engine(Console::mamdani());
+ engine->addInputVariable(new InputVariable("Dummy2", 0, 1));
+ engine->addInputVariable(new InputVariable("Dummy3", 0, 1));
+ engine->addInputVariable(new InputVariable("Dummy4", 0, 1));
+
+ FldExporter exporter("\t");
+ exporter.setExportHeader(false);
+
+ int valuesEachVariable = 3;
+ int expectedValues = (int) std::pow(valuesEachVariable, 1.0 * engine->numberOfInputVariables());
+
+ std::string eachVariable = exporter.toString(engine.get(), valuesEachVariable, FldExporter::EachVariable);
+ // FL_LOG("eachVariable:\n" << eachVariable);
+ std::vector<std::string> linesByVariable = Op::split(eachVariable, "\n");
+ CHECK(int(linesByVariable.size()) == expectedValues);
+
+ std::string allVariables = exporter.toString(engine.get(), expectedValues, FldExporter::AllVariables);
+ std::vector<std::string> linesAllVariables = Op::split(allVariables, "\n");
+ // FL_LOG("allVariables:\n" << allVariables);
+ CHECK(int(linesAllVariables.size()) == expectedValues);
+ }
+
+}
diff --git a/fuzzylite/test/imex/FllImporterTest.cpp b/fuzzylite/test/imex/FllImporterTest.cpp
new file mode 100644
index 0000000..d31701a
--- /dev/null
+++ b/fuzzylite/test/imex/FllImporterTest.cpp
@@ -0,0 +1,56 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ TEST_CASE("Template of FuzzyLite Language works", "[imex]") {
+ std::string fllTemplate;
+#ifdef FL_CPP98
+ //ignore
+#else
+ fllTemplate = R""(
+#Template: FuzzyLite Language (FLL)
+#Engine: string
+#InputVariable: identifier
+# enabled: boolean
+# range: scalar scalar
+# term: identifier Term [parameters]
+#OutputVariable: identifier
+# enabled: boolean
+# range: scalar scalar
+# aggregation: SNorm|none
+# defuzzifier: [Defuzzifier [parameter]]|none
+# default: scalar
+# lock-previous: boolean
+# lock-range: boolean
+# term: identifier Term [parameters]
+#RuleBlock: string
+# enabled: boolean
+# conjunction: TNorm|none
+# disjunction: SNorm|none
+# implication: TNorm|none
+# rule: if antecedent then consequent with weight
+)"";
+#endif
+ FL_unique_ptr<Engine> engine(FllImporter().fromString(fllTemplate));
+ Engine empty;
+ CHECK(FllExporter().toString(engine.get()) == FllExporter().toString(&empty));
+ }
+
+}
diff --git a/fuzzylite/test/imex/RScriptExporterTest.cpp b/fuzzylite/test/imex/RScriptExporterTest.cpp
new file mode 100644
index 0000000..b6d87d8
--- /dev/null
+++ b/fuzzylite/test/imex/RScriptExporterTest.cpp
@@ -0,0 +1,103 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+#include <fstream>
+
+namespace fl {
+
+ TEST_CASE("RExporter creates plots with a single variable", "[imex]") {
+ FL_unique_ptr<Engine> engine(Console::mamdani());
+ engine->addInputVariable(new InputVariable("Dummy", 0, 1));
+
+ std::string filename("/tmp/simple-dimmer.fld");
+ {
+ std::ofstream os(filename.c_str());
+ FldExporter().write(engine.get(), os, 1024);
+ os.close();
+ }
+
+ std::ifstream is(filename.c_str());
+ std::string dummy;
+ std::getline(is, dummy); //remove header
+
+ std::ostringstream os;
+
+ RScriptExporter().writeScriptImportingDataFrame(engine.get(), os,
+ engine->getInputVariable(0), engine->getInputVariable(1),
+ "/dummy/path/to/x.fld",
+ engine->outputVariables());
+ FL_LOG(os.str());
+ }
+
+ TEST_CASE("RExporter ") {
+ std::string fll =
+ "Engine: mam21\n"
+ "InputVariable: angle\n"
+ " enabled: true\n"
+ " range: -5.000 5.000\n"
+ " lock-range: false\n"
+ " term: small Bell -5.000 5.000 8.000\n"
+ " term: big Bell 5.000 5.000 8.000\n"
+ "InputVariable: velocity\n"
+ " enabled: true\n"
+ " range: -5.000 5.000\n"
+ " lock-range: false\n"
+ " term: small Bell -5.000 5.000 2.000\n"
+ " term: big Bell 5.000 5.000 2.000\n"
+ "OutputVariable: force\n"
+ " enabled: true\n"
+ " range: -5.000 5.000\n"
+ " lock-range: false\n"
+ " aggregation: Maximum\n"
+ " defuzzifier: Centroid 200\n"
+ " default: nan\n"
+ " lock-previous: false\n"
+ " term: negBig Bell -5.000 1.670 8.000\n"
+ " term: negSmall Bell -1.670 1.670 8.000\n"
+ " term: posSmall Bell 1.670 1.670 8.000\n"
+ " term: posBig Bell 5.000 1.670 8.000\n"
+ "OutputVariable: force2\n"
+ " enabled: true\n"
+ " range: -5.000 5.000\n"
+ " lock-range: false\n"
+ " aggregation: Maximum\n"
+ " defuzzifier: Centroid 200\n"
+ " default: nan\n"
+ " lock-previous: false\n"
+ " term: negBig2 Bell -3.000 1.670 8.000\n"
+ " term: negSmall2 Bell -1.000 1.670 8.000\n"
+ " term: posSmall2 Bell 1.000 1.670 8.000\n"
+ " term: posBig2 Bell 3.000 1.670 8.000\n"
+ "RuleBlock: \n"
+ " enabled: true\n"
+ " conjunction: Minimum\n"
+ " disjunction: Maximum\n"
+ " implication: Minimum\n"
+ " activation: General\n"
+ " rule: if angle is small and velocity is small then force is negBig and force2 is posBig2\n"
+ " rule: if angle is small and velocity is big then force is negSmall and force2 is posSmall2\n"
+ " rule: if angle is big and velocity is small then force is posSmall and force2 is negSmall2\n"
+ " rule: if angle is big and velocity is big then force is posBig and force2 is negBig2\n";
+
+ Engine* engine = FllImporter().fromString(fll);
+ RScriptExporter().toFile("/tmp/mam22.R", engine,
+ engine->getInputVariable(0), engine->getInputVariable(1),
+ 1024, FldExporter::AllVariables, engine->outputVariables());
+ }
+
+}
diff --git a/fuzzylite/test/norm/NormFunctionTest.cpp b/fuzzylite/test/norm/NormFunctionTest.cpp
new file mode 100644
index 0000000..afce4c8
--- /dev/null
+++ b/fuzzylite/test/norm/NormFunctionTest.cpp
@@ -0,0 +1,202 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: norm/NormFunctions
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ static std::string snormEngine() {
+#ifdef FL_CPP98
+ return "";
+#else
+ return R""(
+Engine: tipper
+InputVariable: service
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ term: poor Gaussian 0.000 1.500
+ term: good Gaussian 5.000 1.500
+ term: excellent Gaussian 10.000 1.500
+InputVariable: food
+ enabled: true
+ range: 0.000 10.000
+ lock-range: false
+ term: rancid Trapezoid 0.000 0.000 1.000 3.000
+ term: delicious Trapezoid 7.000 9.000 10.000 10.000
+OutputVariable: tip
+ enabled: true
+ range: 0.000 30.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: cheap Triangle 0.000 5.000 10.000
+ term: average Triangle 10.000 15.000 20.000
+ term: generous Triangle 20.000 25.000 30.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if service is poor or food is rancid then tip is cheap
+ rule: if service is good then tip is average
+ rule: if service is excellent or food is delicious then tip is generous
+)"";
+#endif
+ }
+
+ static SNorm* myMaximumNorm() {
+ return new SNormFunction("max(a,b)");
+ }
+
+ static SNorm* myNotSoMaximumNorm() {
+ return new SNormFunction("max(a,b) * 0.5");
+ }
+
+ TEST_CASE("SNormFunction (max(a,b)) is equivalent to Maximum", "[snorm][maximum]") {
+#ifdef FL_CPP98
+ FL_IUNUSED(&(myMaximumNorm));
+ FL_IUNUSED(&(myNotSoMaximumNorm));
+ FL_IUNUSED(&(snormEngine));
+ WARN("Test only runs with -DFL_CPP98=OFF");
+ return;
+#else
+ std::string fllEngine = snormEngine();
+ FL_unique_ptr<Engine> engine(FllImporter().fromString(fllEngine));
+ std::string fld = FldExporter().toString(engine.get(), 1024);
+
+ SNormFactory* factory = FactoryManager::instance()->snorm();
+ factory->registerConstructor("Maximum", &(myMaximumNorm));
+
+ //Check our custom SNorm is registered
+ FL_unique_ptr<SNorm> x(factory->constructObject("Maximum"));
+ CHECK(Op::isEq(x->compute(0, 0.5), 0.5));
+
+ //Test creating an engine with the new SNorm
+ engine.reset(FllImporter().fromString(fllEngine));
+ std::string anotherFld = FldExporter().toString(engine.get(), 1024);
+
+ CHECK(fld == anotherFld);
+
+ //Make sure a different SNorm fails in results
+
+ factory->registerConstructor("Maximum", &(myNotSoMaximumNorm));
+ engine.reset(FllImporter().fromString(fllEngine));
+ anotherFld = FldExporter().toString(engine.get(), 1024);
+
+ CHECK(fld != anotherFld);
+#endif
+ }
+
+ static std::string tnormEngine() {
+#ifdef FL_CPP98
+ return "";
+#else
+ return R""(
+Engine: mam21
+InputVariable: angle
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ term: small Bell -5.000 5.000 8.000
+ term: big Bell 5.000 5.000 8.000
+InputVariable: velocity
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ term: small Bell -5.000 5.000 2.000
+ term: big Bell 5.000 5.000 2.000
+OutputVariable: force
+ enabled: true
+ range: -5.000 5.000
+ lock-range: false
+ aggregation: Maximum
+ defuzzifier: Centroid 200
+ default: nan
+ lock-previous: false
+ term: negBig Bell -5.000 1.670 8.000
+ term: negSmall Bell -1.670 1.670 8.000
+ term: posSmall Bell 1.670 1.670 8.000
+ term: posBig Bell 5.000 1.670 8.000
+RuleBlock:
+ enabled: true
+ conjunction: Minimum
+ disjunction: Maximum
+ implication: Minimum
+ activation: General
+ rule: if angle is small and velocity is small then force is negBig
+ rule: if angle is small and velocity is big then force is negSmall
+ rule: if angle is big and velocity is small then force is posSmall
+ rule: if angle is big and velocity is big then force is posBig
+)"";
+#endif
+ }
+
+ static TNorm* myMinimumNorm() {
+ return new TNormFunction("min(a,b)");
+ }
+
+ static TNorm* myNotSoMinimumNorm() {
+ return new TNormFunction("min(a,b) * 0.5");
+ }
+
+ TEST_CASE("TNormFunction (min(a,b)) is equivalent to Minimum", "[tnorm][minimum]") {
+#ifdef FL_CPP98
+ FL_IUNUSED(&(myMinimumNorm));
+ FL_IUNUSED(&(myNotSoMinimumNorm));
+ FL_IUNUSED(&(tnormEngine));
+ WARN("Test only runs with -DFL_CPP98=OFF");
+ return;
+#else
+ std::string fllEngine = tnormEngine();
+ FL_unique_ptr<Engine> engine(FllImporter().fromString(fllEngine));
+ std::string fld = FldExporter().toString(engine.get(), 1024);
+
+ TNormFactory* factory = FactoryManager::instance()->tnorm();
+ factory->registerConstructor("Minimum", &(myMinimumNorm));
+
+ //Check our custom SNorm is registered
+ FL_unique_ptr<TNorm> x(factory->constructObject("Minimum"));
+ CHECK(Op::isEq(x->compute(0.5, 1), 0.5));
+
+ //Test creating an engine with the new SNorm
+ engine.reset(FllImporter().fromString(fllEngine));
+ std::string anotherFld = FldExporter().toString(engine.get(), 1024);
+
+ CHECK(fld == anotherFld);
+
+ //Make sure a different SNorm fails in results
+
+ factory->registerConstructor("Minimum", &(myNotSoMinimumNorm));
+ engine.reset(FllImporter().fromString(fllEngine));
+ anotherFld = FldExporter().toString(engine.get(), 1024);
+
+ CHECK(fld != anotherFld);
+#endif
+ }
+
+}
diff --git a/fuzzylite/test/term/AggregatedTest.cpp b/fuzzylite/test/term/AggregatedTest.cpp
new file mode 100644
index 0000000..bb3f0e4
--- /dev/null
+++ b/fuzzylite/test/term/AggregatedTest.cpp
@@ -0,0 +1,52 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: term/Aggregated
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("highest term in aggregated", "[term][aggregated]") {
+
+ FL_unique_ptr<Term> dark(new Triangle("DARK", 0.000, 0.250, 0.500));
+ FL_unique_ptr<Term> medium(new Triangle("MEDIUM", 0.250, 0.500, 0.750));
+ FL_unique_ptr<Term> bright(new Triangle("BRIGHT", 0.500, 0.750, 1.000));
+
+ Aggregated aggregated;
+ aggregated.addTerm(dark.get(), 0.5, fl::null);
+ aggregated.addTerm(medium.get(), 0.1, fl::null);
+ aggregated.addTerm(bright.get(), 0.6, fl::null);
+
+ REQUIRE(aggregated.highestActivatedTerm()->getTerm() == bright.get());
+
+ aggregated.terms().at(1).setDegree(0.7);
+ REQUIRE(aggregated.highestActivatedTerm()->getTerm() == medium.get());
+
+ aggregated.terms().front().setDegree(0.9);
+ REQUIRE(aggregated.highestActivatedTerm()->getTerm() == dark.get());
+
+ aggregated.clear();
+ REQUIRE(aggregated.highestActivatedTerm() == fl::null);
+ }
+
+}
diff --git a/fuzzylite/test/term/DiscreteTest.cpp b/fuzzylite/test/term/DiscreteTest.cpp
new file mode 100644
index 0000000..2fb32aa
--- /dev/null
+++ b/fuzzylite/test/term/DiscreteTest.cpp
@@ -0,0 +1,125 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: term/Discrete
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("discrete finds elements using binary search", "[term][discrete]") {
+ fuzzylite::setLogging(true);
+ fuzzylite::setDebugging(false);
+ Rectangle rectangle("rectangle", 0, 1);
+ FL_unique_ptr<Discrete> discrete(Discrete::discretize(&rectangle, rectangle.getStart(), rectangle.getEnd(), 10));
+ FL_LOG(discrete->toString());
+
+ CHECK(discrete->membership(.25) == 1.0);
+ CHECK(discrete->membership(0.0) == 1.0);
+ CHECK(discrete->membership(-1.0) == 1.0);
+ CHECK(discrete->membership(1.0) == 1.0);
+ CHECK(discrete->membership(2.0) == 1.0);
+ CHECK(Op::isNaN(discrete->membership(fl::nan)));
+ CHECK(discrete->membership(fl::inf) == 1.0);
+ CHECK(discrete->membership(-fl::inf) == 1.0);
+ }
+
+ TEST_CASE("discrete still finds elements using binary search", "[term][discrete]") {
+ fuzzylite::setLogging(true);
+ fuzzylite::setDebugging(false);
+ Triangle triangle("triangle", 0, 1);
+ FL_unique_ptr<Discrete> discrete(Discrete::discretize(&triangle, triangle.getVertexA(), triangle.getVertexC(), 100));
+ FL_LOG(discrete->toString());
+ for (int i = 0; i < 200; ++i) {
+ scalar x = Op::scale(i, 0, 200, -1, 1);
+ if (not Op::isEq(triangle.membership(x), discrete->membership(x))) {
+ fuzzylite::setDebugging(true);
+ CHECK(Op::isEq(triangle.membership(x), discrete->membership(x)));
+ fuzzylite::setDebugging(false);
+ }
+ }
+ }
+
+ TEST_CASE("discrete finds all elements using binary search", "[term][discrete]") {
+ fuzzylite::setLogging(true);
+ fuzzylite::setDebugging(false);
+ scalar min = -1.0;
+ scalar max = 1.0;
+ scalar range = max - min;
+ scalar mean = 0.5 * (max + min);
+
+
+ std::vector<Term*> terms;
+ terms.push_back(new Triangle("triangle", min, mean, max));
+ terms.push_back(new Trapezoid("trapezoid", min, min + .25 * range, min + .75 * range, max));
+ terms.push_back(new Rectangle("rectangle", min, max));
+ terms.push_back(new Bell("bell", mean, range / 4, 3.0));
+ terms.push_back(new Cosine("cosine", mean, range));
+ terms.push_back(new Gaussian("gaussian", mean, range / 4));
+ terms.push_back(new GaussianProduct("gaussianProduct", mean, range / 4, mean, range / 4));
+ terms.push_back(new PiShape("piShape", min, mean, mean, max));
+ terms.push_back(new SigmoidDifference("sigmoidDifference", min + .25 * range, 20 / range, 20 / range, max - .25 * range));
+ terms.push_back(new SigmoidProduct("sigmoidProduct", min + .25 * range, 20 / range, 20 / range, max - .25 * range));
+ terms.push_back(new Spike("spike", mean, range));
+
+ terms.push_back(new Binary("binary", min, max));
+ terms.push_back(new Concave("concave", mean, max));
+ terms.push_back(new Ramp("ramp", min, max));
+ terms.push_back(new Sigmoid("sigmoid", mean, 20 / range));
+ terms.push_back(new SShape("sshape", min, max));
+ terms.push_back(new ZShape("zshape", min, max));
+
+ for (std::size_t t = 0; t < terms.size(); ++t) {
+ Term* term = terms.at(t);
+ std::vector<Discrete::Pair> pairs;
+ srand(0);
+ for (int i = 0; i < 1000; ++i) {
+ int randomX = std::rand();
+ scalar x = Op::scale(randomX % 100, 0, 100, -1, 1);
+ pairs.push_back(Discrete::Pair(x, term->membership(x)));
+ }
+ Discrete::sort(pairs);
+
+ Discrete discrete("discrete", pairs);
+ for (std::size_t i = 0; i < pairs.size(); ++i) {
+ Discrete::Pair pair = pairs.at(i);
+ scalar x = pair.first;
+ if (not Op::isEq(discrete.membership(x), term->membership(x))) {
+ fuzzylite::setDebugging(true);
+ CHECK(discrete.membership(x) == term->membership(x));
+ fuzzylite::setDebugging(false);
+ }
+ }
+ for (int i = 0 ; i < 100 ; i++) {
+ scalar x = Op::scale(i, 0, 100, -1, 1);
+ if (not Op::isEq(discrete.membership(x), term->membership(x))) {
+ fuzzylite::setDebugging(true);
+ CHECK(discrete.membership(x) == term->membership(x));
+ fuzzylite::setDebugging(false);
+ }
+ }
+ }
+ for (std::size_t i = 0 ; i < terms.size(); ++i){
+ delete terms.at(i);
+ }
+ }
+}
diff --git a/fuzzylite/test/term/FunctionTest.cpp b/fuzzylite/test/term/FunctionTest.cpp
new file mode 100644
index 0000000..a42e37b
--- /dev/null
+++ b/fuzzylite/test/term/FunctionTest.cpp
@@ -0,0 +1,115 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: term/Function
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("function parses basic arithmetic", "[term][function]") {
+ Function f;
+ std::string text = "3+4*2/(1-5)^2^3";
+ CHECK(f.toPostfix(text) == "3 4 2 * 1 5 - 2 3 ^ ^ / +");
+ CHECK(f.parse(text)->toInfix() == "3.000 ^ 2.000 ^ 5.000 - 1.000 / 2.000 * 4.000 + 3.000");
+ CHECK(f.parse(text)->toPrefix() == "+ / ^ ^ 3.000 2.000 - 5.000 1.000 * 2.000 4.000 3.000");
+ }
+
+ TEST_CASE("function parses basic trigonometry", "[term][function]") {
+ Function f;
+ std::string text = "sin(y*x)^2/x";
+
+ CHECK_THROWS(f.load(text));
+
+ f.variables["y"] = 1.0;
+ f.load(text);
+
+ CHECK(f.toPostfix(text) == "y x * sin 2 ^ x /");
+ CHECK(f.parse(text)->toInfix() == "x / 2.000 ^ x * y sin");
+ CHECK(f.parse(text)->toPrefix() == "/ x ^ 2.000 sin * x y");
+ }
+
+ TEST_CASE("function parses propositions", "[term][function]") {
+ Function f;
+
+ std::string text = "(Temperature is High and Oxygen is Low) or "
+ "(Temperature is Low and (Oxygen is Low or Oxygen is High))";
+
+ CHECK(f.toPostfix(text) == "Temperature is High Oxygen is Low "
+ "and Temperature is Low Oxygen is Low Oxygen is High or and or");
+ }
+
+ TEST_CASE("function cannot deal with negative numbers", "[term][function]") {
+ Function f;
+ std::string text = "-5 *4/sin(-pi/2)";
+
+ SECTION("function throws exception") {
+ CHECK_THROWS(f.parse(text)->evaluate());
+ }
+
+ f.variables["pi"] = 3.14;
+ CHECK_THROWS(f.parse(text)->evaluate(&f.variables));
+
+ text = "~5 *4/sin(~pi/2)";
+ CHECK(f.parse(text)->evaluate(&f.variables) == Approx(20));
+
+ f.load(text);
+
+ f.variables["pi"] = 3.14;
+
+ CHECK(f.toPostfix(text) == "5 ~ 4 * pi ~ 2 / sin /");
+ CHECK(f.parse(text)->toInfix() == "2.000 / pi ~ sin / 4.000 * 5.000 ~");
+ CHECK(f.parse(text)->toPrefix() == "/ sin / 2.000 ~ pi * 4.000 ~ 5.000");
+ }
+
+ TEST_CASE("Function is clonable", "[term][function]") {
+ Function* f = new Function;
+ std::string text = "2+2";
+ f->load(text);
+ CHECK(Op::isEq(f->membership(fl::nan), 4));
+ Function* clone = f->clone();
+ delete f;
+ CHECK(Op::isEq(clone->membership(fl::nan), 4));
+ delete clone;
+ }
+
+ TEST_CASE("Function is constructor copyable", "[term][function]") {
+ Function* f = new Function;
+ std::string text = "2+2";
+ f->load(text);
+ CHECK(Op::isEq(f->membership(fl::nan), 4));
+ Function* clone = new Function(*f);
+ delete f;
+ CHECK(Op::isEq(clone->membership(fl::nan), 4));
+ delete clone;
+ }
+
+ TEST_CASE("Function computes tree size correctly", "[term][function]"){
+ Function f("f", "x*x+(x-x)/x+log(x)");
+ f.load();
+ CHECK(f.root()->treeSize() == 6);
+ CHECK(f.root()->treeSize(Function::Element::Function) == 1);
+ CHECK(f.root()->treeSize(Function::Element::Operator) == 5);
+ FL_LOG(f.complexity().toString());
+ }
+
+}
diff --git a/fuzzylite/test/term/TrapezoidTest.cpp b/fuzzylite/test/term/TrapezoidTest.cpp
new file mode 100644
index 0000000..8581ac1
--- /dev/null
+++ b/fuzzylite/test/term/TrapezoidTest.cpp
@@ -0,0 +1,53 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: term/Trapezoid
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("trapezoid can be open ended with -infinity", "[term][trapezoid]") {
+ Trapezoid trapezoid("A", -fl::inf, 0, 1, 2);
+ Ramp ramp("a", 2, 1);
+ //(-inf, inf)
+ for (scalar i = -10.0; Op::isLE(i, 10.0); i += .2) {
+ FL_DBG("A(" << i << ")=" << trapezoid.membership(i));
+ FL_DBG("a(" << i << ")=" << ramp.membership(i));
+ REQUIRE(Op::isEq(trapezoid.membership(i), ramp.membership(i)));
+ }
+ REQUIRE(Op::isEq(trapezoid.membership(-fl::inf), 1.0));
+ REQUIRE(Op::isEq(trapezoid.membership(fl::inf), 0.0));
+ }
+
+ TEST_CASE("trapezoid can be open ended with +infinity", "[term][trapezoid]") {
+ Trapezoid trapezoid("A", 0, 1, 2, fl::inf);
+ Ramp ramp("a", 0, 1);
+ //(-inf, inf)
+ for (scalar i = -10.0; Op::isLE(i, 10.0); i += .2) {
+ REQUIRE(Op::isEq(trapezoid.membership(i), ramp.membership(i)));
+ }
+ REQUIRE(Op::isEq(trapezoid.membership(fl::inf), 1.0));
+ REQUIRE(Op::isEq(trapezoid.membership(-fl::inf), 0.0));
+ }
+
+}
diff --git a/fuzzylite/test/term/TriangleTest.cpp b/fuzzylite/test/term/TriangleTest.cpp
new file mode 100644
index 0000000..bd1459d
--- /dev/null
+++ b/fuzzylite/test/term/TriangleTest.cpp
@@ -0,0 +1,66 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+namespace fl {
+
+ /**
+ * Tests: term/Triangle
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("triangle can be open ended with -infinity", "[term][triangle]") {
+ Triangle triangle("A", -fl::inf, 0, 1);
+ Ramp ramp("a", 1, 0);
+ for (int i = -10; i < 2; ++i) {
+ FL_DBG("A(" << i << ")=" << triangle.membership(i));
+ FL_DBG("a(" << i << ")=" << ramp.membership(i));
+ REQUIRE(Op::isEq(triangle.membership(i), ramp.membership(i)));
+ }
+ REQUIRE(Op::isEq(triangle.membership(-fl::inf), 1.0));
+ REQUIRE(Op::isEq(triangle.membership(fl::inf), 0.0));
+ }
+
+ TEST_CASE("triangle can be open ended with +infinity", "[term][triangle]") {
+ Triangle triangle("A", 0, 1, fl::inf);
+ Ramp ramp("a", 0, 1);
+ for (int i = 10; i >= -2; --i) {
+ FL_DBG("A(" << i << ")=" << triangle.membership(i));
+ FL_DBG("a(" << i << ")=" << ramp.membership(i));
+ REQUIRE(Op::isEq(triangle.membership(i), ramp.membership(i)));
+ }
+ REQUIRE(Op::isEq(triangle.membership(fl::inf), 1.0));
+ REQUIRE(Op::isEq(triangle.membership(-fl::inf), 0.0));
+ }
+
+ TEST_CASE("triangle defuzzification is correct", "[term][triangle]") {
+ Triangle a("A", 0, 1, 2);
+ Triangle b("B", 1, 2, 3);
+ AlgebraicProduct times;
+ Aggregated x("X", 0, 3, new AlgebraicSum);
+ x.addTerm(&a, 1, &times);
+ x.addTerm(&b, 1, &times);
+ Centroid c(101);
+ FL_LOG(c.defuzzify(&x, 0, 3));
+
+ Triangle t("T", 0, 0, 1);
+ FL_LOG(c.defuzzify(&t, 0, 1));
+ }
+}
diff --git a/fuzzylite/test/variable/VariableTest.cpp b/fuzzylite/test/variable/VariableTest.cpp
new file mode 100644
index 0000000..6f77e94
--- /dev/null
+++ b/fuzzylite/test/variable/VariableTest.cpp
@@ -0,0 +1,74 @@
+/*
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the FuzzyLite License included with the software.
+
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+
+ fuzzylite is a registered trademark of FuzzyLite Limited.
+ */
+
+#include "test/catch.hpp"
+#include "fl/Headers.h"
+
+#include <algorithm> // std::random_shuffle
+
+namespace fl {
+
+ /**
+ * Tests: variable/Variable
+ *
+ * @author Juan Rada-Vilela, Ph.D.
+ *
+ */
+
+ TEST_CASE("variable of Constant terms is sorted", "[variable][variable]") {
+ Variable variable("Variable", -10, 10);
+ for (int i = 0; i <= 20; ++i) {
+ variable.addTerm(new Constant(Op::str(i), i - 10));
+ }
+ std::random_shuffle(variable.terms().begin(), variable.terms().end());
+ FL_DBG(variable.toString());
+ REQUIRE(variable.numberOfTerms() == 21);
+ variable.sort();
+ REQUIRE(variable.numberOfTerms() == 21);
+ int value = -10;
+ for (std::size_t i = 0; i < variable.terms().size(); ++i) {
+ Constant* term = dynamic_cast<Constant*> (variable.terms().at(i));
+ REQUIRE(term);
+ REQUIRE(term->getValue() == float(value));
+ ++value;
+ }
+ FL_DBG(variable.toString());
+ }
+
+ TEST_CASE("variable of Triangle terms is sorted", "[variable][variable]") {
+ Variable variable("Variable", -30, 30);
+ for (int i = 0; i <= 20; ++i) {
+ variable.addTerm(new Triangle(Op::str(i), i - 1, i, i + 1));
+ }
+ std::random_shuffle(variable.terms().begin(), variable.terms().end());
+ FL_DBG(variable.toString());
+ REQUIRE(variable.numberOfTerms() == 21);
+ variable.sort();
+ FL_DBG("Shuffled:");
+ FL_DBG(variable.toString());
+ REQUIRE(variable.numberOfTerms() == 21);
+ int value = 0;
+ for (std::size_t i = 0; i < variable.terms().size(); ++i) {
+ Triangle* term = dynamic_cast<Triangle*> (variable.terms().at(i));
+ REQUIRE(term);
+ REQUIRE(term->getName() == Op::str(value < 0 ? -1 * value : value));
+ ++value;
+ }
+ FL_DBG(variable.toString());
+ }
+
+}
+